1 /* 2 * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. 3 * Distributed under the terms of the MIT License. 4 */ 5 #ifndef _KERNEL_ARCH_X86_64_DESCRIPTORS_H 6 #define _KERNEL_ARCH_X86_64_DESCRIPTORS_H 7 8 9 // Segment definitions. 10 // Note that the ordering of these is important to SYSCALL/SYSRET. 11 #define KERNEL_CODE_SEG 0x08 12 #define KERNEL_DATA_SEG 0x10 13 #define USER_DATA_SEG 0x1b 14 #define USER_CODE_SEG 0x23 15 16 17 #ifndef _ASSEMBLER 18 19 20 #define TSS_BASE_SEGMENT 5 21 #define TSS_SEGMENT(cpu) (TSS_BASE_SEGMENT + cpu * 2) 22 23 24 // Structure of a segment descriptor. 25 struct segment_descriptor { 26 uint32 limit0 : 16; 27 uint32 base0 : 24; 28 uint32 type : 4; 29 uint32 desc_type : 1; 30 uint32 dpl : 2; 31 uint32 present : 1; 32 uint32 limit1 : 4; 33 uint32 available : 1; 34 uint32 long_mode : 1; 35 uint32 d_b : 1; 36 uint32 granularity : 1; 37 uint32 base1 : 8; 38 } _PACKED; 39 40 // Structure of a TSS segment descriptor. 41 struct tss_descriptor { 42 uint32 limit0 : 16; 43 uint32 base0 : 24; 44 uint32 type : 4; 45 uint32 desc_type : 1; 46 uint32 dpl : 2; 47 uint32 present : 1; 48 uint32 limit1 : 4; 49 uint32 available : 1; 50 uint32 unused1 : 2; 51 uint32 granularity : 1; 52 uint32 base1 : 8; 53 uint32 base2 : 32; 54 uint32 unused2 : 32; 55 } _PACKED; 56 57 // Structure of an interrupt descriptor. 58 struct interrupt_descriptor { 59 uint32 base0 : 16; 60 uint32 sel : 16; 61 uint32 ist : 3; 62 uint32 unused1 : 5; 63 uint32 type : 4; 64 uint32 unused2 : 1; 65 uint32 dpl : 2; 66 uint32 present : 1; 67 uint32 base1 : 16; 68 uint32 base2 : 32; 69 uint32 reserved : 32; 70 } _PACKED; 71 72 struct gdt_idt_descr { 73 uint16 limit; 74 addr_t base; 75 } _PACKED; 76 77 struct tss { 78 uint32 _reserved1; 79 uint64 sp0; 80 uint64 sp1; 81 uint64 sp2; 82 uint64 _reserved2; 83 uint64 ist1; 84 uint64 ist2; 85 uint64 ist3; 86 uint64 ist4; 87 uint64 ist5; 88 uint64 ist6; 89 uint64 ist7; 90 uint64 _reserved3; 91 uint16 _reserved4; 92 uint16 io_map_base; 93 } _PACKED; 94 95 96 static inline void 97 clear_segment_descriptor(segment_descriptor* desc) 98 { 99 *(uint64*)desc = 0; 100 } 101 102 103 static inline void 104 set_segment_descriptor(segment_descriptor* desc, uint8 type, uint8 dpl) 105 { 106 clear_segment_descriptor(desc); 107 108 // In 64-bit mode the CPU ignores the base/limit of code/data segments, 109 // it always treats base as 0 and does no limit checks. 110 desc->base0 = 0; 111 desc->base1 = 0; 112 desc->limit0 = 0xffff; 113 desc->limit1 = 0xf; 114 desc->granularity = 1; 115 116 desc->type = type; 117 desc->desc_type = DT_CODE_DATA_SEGMENT; 118 desc->dpl = dpl; 119 desc->present = 1; 120 121 desc->long_mode = (type & DT_CODE_EXECUTE_ONLY) ? 1 : 0; 122 // Must be set to 1 for code segments only. 123 } 124 125 126 static inline void 127 set_tss_descriptor(segment_descriptor* _desc, uint64 base, uint32 limit) 128 { 129 clear_segment_descriptor(_desc); 130 clear_segment_descriptor(&_desc[1]); 131 132 // The TSS descriptor is a special format in 64-bit mode, it is 16 bytes 133 // instead of 8. 134 tss_descriptor* desc = (tss_descriptor*)_desc; 135 136 desc->base0 = base & 0xffffff; 137 desc->base1 = (base >> 24) & 0xff; 138 desc->base2 = (base >> 32); 139 desc->limit0 = limit & 0xffff; 140 desc->limit1 = (limit >> 16) & 0xf; 141 142 desc->present = 1; 143 desc->type = DT_TSS; 144 desc->desc_type = DT_SYSTEM_SEGMENT; 145 desc->dpl = DPL_KERNEL; 146 } 147 148 149 static inline void 150 set_interrupt_descriptor(interrupt_descriptor* desc, uint64 addr, uint32 type, 151 uint16 seg, uint32 dpl, uint32 ist) 152 { 153 desc->base0 = addr & 0xffff; 154 desc->base1 = (addr >> 16) & 0xffff; 155 desc->base2 = (addr >> 32) & 0xffffffff; 156 desc->sel = seg; 157 desc->ist = ist; 158 desc->type = type; 159 desc->dpl = dpl; 160 desc->present = 1; 161 desc->unused1 = 0; 162 desc->unused2 = 0; 163 desc->reserved = 0; 164 } 165 166 167 #endif /* _ASSEMBLER */ 168 169 #endif /* _KERNEL_ARCH_X86_64_DESCRIPTORS_H */ 170