1 /* 2 ** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 3 ** Distributed under the terms of the NewOS License. 4 */ 5 #ifndef _KERNEL_ARCH_x86_DESCRIPTORS_H 6 #define _KERNEL_ARCH_x86_DESCRIPTORS_H 7 8 9 #define KERNEL_CODE_SEG 0x8 10 #define KERNEL_DATA_SEG 0x10 11 12 #define USER_CODE_SEG 0x1b 13 #define USER_DATA_SEG 0x23 14 15 16 #ifndef _ASSEMBLER 17 // this file can also be included from assembler as well 18 // (and is in arch_interrupts.S) 19 20 #define DOUBLE_FAULT_TSS_BASE_SEGMENT 5 21 #define TSS_BASE_SEGMENT (DOUBLE_FAULT_TSS_BASE_SEGMENT + smp_get_num_cpus()) 22 #define TLS_BASE_SEGMENT (TSS_BASE_SEGMENT + smp_get_num_cpus()) 23 24 25 // defines entries in the GDT/LDT 26 27 typedef struct segment_descriptor { 28 uint16 limit_00_15; // bit 0 - 15 29 uint16 base_00_15; // 16 - 31 30 uint32 base_23_16 : 8; // 0 - 7 31 uint32 type : 4; // 8 - 11 32 uint32 desc_type : 1; // 12 (0 = system, 1 = code/data) 33 uint32 privilege_level : 2; // 13 - 14 34 uint32 present : 1; // 15 35 uint32 limit_19_16 : 4; // 16 - 19 36 uint32 available : 1; // 20 37 uint32 zero : 1; // 21 38 uint32 d_b : 1; // 22 39 uint32 granularity : 1; // 23 40 uint32 base_31_24 : 8; // 24 - 31 41 } segment_descriptor; 42 43 enum descriptor_privilege_levels { 44 DPL_KERNEL = 0, 45 DPL_USER = 3, 46 }; 47 48 enum descriptor_types { 49 // segment types 50 DT_CODE_EXECUTE_ONLY = 0x8, 51 DT_CODE_ACCESSED = 0x9, 52 DT_CODE_READABLE = 0xa, 53 DT_CODE_CONFORM = 0xc, 54 DT_DATA_READ_ONLY = 0x0, 55 DT_DATA_ACCESSED = 0x1, 56 DT_DATA_WRITEABLE = 0x2, 57 DT_DATA_EXPANSION_DOWN = 0x4, 58 59 DT_TSS = 9, 60 /* non busy, 32 bit */ 61 62 // descriptor types 63 DT_SYSTEM_SEGMENT = 0, 64 DT_CODE_DATA_SEGMENT = 1, 65 }; 66 67 static inline void 68 clear_segment_descriptor(struct segment_descriptor *desc) 69 { 70 *(long long *)desc = 0; 71 } 72 73 74 static inline void 75 set_segment_descriptor_base(struct segment_descriptor *desc, addr_t base) 76 { 77 desc->base_00_15 = (addr_t)base & 0xffff; // base is 32 bits long 78 desc->base_23_16 = ((addr_t)base >> 16) & 0xff; 79 desc->base_31_24 = ((addr_t)base >> 24) & 0xff; 80 } 81 82 83 static inline void 84 set_segment_descriptor(struct segment_descriptor *desc, addr_t base, uint32 limit, 85 uint8 type, uint8 privilegeLevel) 86 { 87 set_segment_descriptor_base(desc, base); 88 89 // limit is 20 bits long 90 if (limit & 0xfff00000) { 91 desc->limit_00_15 = ((addr_t)limit >> 12) & 0x0ffff; 92 desc->limit_19_16 = ((addr_t)limit >> 28) & 0xf; 93 desc->granularity = 1; // 4 KB granularity 94 } else { 95 desc->limit_00_15 = (addr_t)limit & 0x0ffff; 96 desc->limit_19_16 = ((addr_t)limit >> 16) & 0xf; 97 desc->granularity = 0; // 1 byte granularity 98 } 99 limit >>= 12; 100 101 102 desc->type = type; 103 desc->desc_type = DT_CODE_DATA_SEGMENT; 104 desc->privilege_level = privilegeLevel; 105 106 desc->present = 1; 107 desc->available = 0; // system available bit is currently not used 108 desc->d_b = 1; // 32-bit code 109 110 desc->zero = 0; 111 } 112 113 114 static inline void 115 set_tss_descriptor(struct segment_descriptor *desc, addr_t base, uint32 limit) 116 { 117 // the TSS descriptor has a special layout different from the standard descriptor 118 set_segment_descriptor_base(desc, base); 119 120 desc->limit_00_15 = (addr_t)limit & 0x0ffff; 121 desc->limit_19_16 = 0; 122 123 desc->type = DT_TSS; 124 desc->desc_type = DT_SYSTEM_SEGMENT; 125 desc->privilege_level = DPL_KERNEL; 126 127 desc->present = 1; 128 desc->granularity = 0; // 1 Byte granularity 129 desc->available = 0; // system available bit is currently not used 130 desc->d_b = 0; 131 132 desc->zero = 0; 133 } 134 135 #endif /* _ASSEMBLER */ 136 137 #endif /* _KERNEL_ARCH_x86_DESCRIPTORS_H */ 138