|
[ source navigation ] [ diff markup ] [ identifier search ] [ general search ] |
|||
|
001 /* Copyright (C) 2004 David Decotigny 002 Copyright (C) 2003 Thomas Petazzoni 003 004 This program is free software; you can redistribute it and/or 005 modify it under the terms of the GNU General Public License 006 as published by the Free Software Foundation; either version 2 007 of the License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU General Public License for more details. 013 014 You should have received a copy of the GNU General Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 017 USA. 018 */ 019 #include "segment.h" 020 021 #include "gdt.h" 022 023 024 /** 025 * The sructure of a segment descriptor. 026 * 027 * @see Intel x86 doc, Vol 3, section 3.4.3, figure 3-8. For segment 028 * types, see section 3.5 029 */ 030 struct x86_segment_descriptor 031 { 032 /* Lowest dword */ 033 sos_ui16_t limit_15_0; /* Segment limit, bits 15..0 */ 034 sos_ui16_t base_paged_addr_15_0; /* Base address, bits 15..0 */ 035 036 /* Highest dword */ 037 sos_ui8_t base_paged_addr_23_16; /* Base address bits 23..16 */ 038 sos_ui8_t segment_type:4; /* Section 3.4.3.1 (code/data) 039 and 3.5 (system) of Intel x86 vol 3 */ 040 sos_ui8_t descriptor_type:1; /* 0=system, 1=Code/Data */ 041 sos_ui8_t dpl:2; /* Descriptor privilege level */ 042 sos_ui8_t present:1; 043 044 sos_ui8_t limit_19_16:4; /* Segment limit, bits 19..16 */ 045 sos_ui8_t custom:1; 046 sos_ui8_t zero:1; 047 sos_ui8_t op_size:1; /* 0=16bits instructions, 1=32bits */ 048 sos_ui8_t granularity:1; /* 0=limit in bytes, 1=limit in pages */ 049 050 sos_ui8_t base_paged_addr_31_24; /* Base address bits 31..24 */ 051 } __attribute__ ((packed, aligned(8))); 052 053 054 /** 055 * The GDT register, which stores the address and size of the 056 * GDT. 057 * 058 * @see Intel x86 doc vol 3, section 2.4, figure 2-4; and section 059 * 3.5.1 060 */ 061 struct x86_gdt_register { 062 /** Intel doc says that the real GDT register (ie the "limit" field) 063 should be odd-word aligned. That's why we add a padding here. 064 Credits to Romain for having signalled this to us. */ 065 sos_ui16_t padding; 066 067 /** The maximum GDT offset allowed to access an entry in the GDT */ 068 sos_ui16_t limit; 069 070 /** 071 * This is not exactly a "virtual" address, ie an adddress such as 072 * those of instructions and data; this is a "linear" address, ie an 073 * address in the paged memory. However, in SOS we configure the 074 * segmented memory as a "flat" space: the 0-4GB segment-based (ie 075 * "virtual") addresses directly map to the 0-4GB paged memory (ie 076 * "linear"), so that the "linear" addresses are numerically equal 077 * to the "virtual" addresses: this base_addr will thus be the same 078 * as the address of the gdt array 079 */ 080 sos_ui32_t base_addr; 081 } __attribute__((packed, aligned(4))); 082 083 084 /** 085 * Helper macro that builds a Segment descriptor for the virtual 086 * 0..4GB addresses to be mapped to the linear 0..4GB linear 087 * addresses. 088 */ 089 #define BUILD_GDTE(descr_privilege_level,is_code) \ 090 ((struct x86_segment_descriptor) { \ 091 .limit_15_0= 0xffff, \ 092 .base_paged_addr_15_0= 0, \ 093 .base_paged_addr_23_16= 0, \ 094 .segment_type= ((is_code)?0xb:0x3), \ 095 /* With descriptor_type (below) = 1 (code/data), \ 096 * see Figure 3-1 of section 3.4.3.1 in Intel \ 097 * x86 vol 3: \ 098 * - Code (bit 3 = 1): \ 099 * bit 0: 1=Accessed \ 100 * bit 1: 1=Readable \ 101 * bit 2: 0=Non-Conforming \ 102 * - Data (bit 3 = 0): \ 103 * bit 0: 1=Accessed \ 104 * bit 1: 1=Writable \ 105 * bit 2: 0=Expand up (stack-related) \ 106 * For Conforming/non conforming segments, see \ 107 * Intel x86 Vol 3 section 4.8.1.1 \ 108 */ \ 109 .descriptor_type= 1, /* 1=Code/Data */ \ 110 .dpl= ((descr_privilege_level) & 0x3), \ 111 .present= 1, \ 112 .limit_19_16= 0xf, \ 113 .custom= 0, \ 114 .zero= 0, \ 115 .op_size= 1, /* 32 bits instr/data */ \ 116 .granularity= 1, /* limit is in 4kB Pages */ \ 117 .base_paged_addr_31_24= 0 \ 118 }) 119 120 121 /** The actual GDT */ 122 static struct x86_segment_descriptor gdt[] = { 123 [SOS_SEG_NULL] = (struct x86_segment_descriptor){ 0, }, 124 [SOS_SEG_KCODE] = BUILD_GDTE(0, 1), 125 [SOS_SEG_KDATA] = BUILD_GDTE(0, 0), 126 [SOS_SEG_UCODE] = BUILD_GDTE(3, 1), 127 [SOS_SEG_UDATA] = BUILD_GDTE(3, 0), 128 [SOS_SEG_KERNEL_TSS] = { 0, } /* Initialized by 129 register_kernel_tss */ 130 }; 131 132 133 sos_ret_t sos_gdt_subsystem_setup(void) 134 { 135 struct x86_gdt_register gdtr; 136 137 /* Put some garbage in the padding field of the GDTR */ 138 gdtr.padding = ~0; 139 140 /* Address of the GDT */ 141 gdtr.base_addr = (sos_ui32_t) gdt; 142 143 /* The limit is the maximum offset in bytes from the base address of 144 the GDT */ 145 gdtr.limit = sizeof(gdt) - 1; 146 147 /* Commit the GDT into the CPU, and update the segment 148 registers. The CS register may only be updated with a long jump 149 to an absolute address in the given segment (see Intel x86 doc 150 vol 3, section 4.8.1). */ 151 asm volatile ("lgdt %0 \n\ 152 ljmp %1,$1f \n\ 153 1: \n\ 154 movw %2, %%ax \n\ 155 movw %%ax, %%ss \n\ 156 movw %%ax, %%ds \n\ 157 movw %%ax, %%es \n\ 158 movw %%ax, %%fs \n\ 159 movw %%ax, %%gs" 160 : 161 :"m"(gdtr.limit) /* The real beginning of the GDT 162 register is /after/ the "padding" 163 field, ie at the "limit" 164 field. */, 165 "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE)), 166 "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA)) 167 :"memory","eax"); 168 169 return SOS_OK; 170 } 171 172 173 sos_ret_t sos_gdt_register_kernel_tss(sos_vaddr_t tss_vaddr) 174 { 175 sos_ui16_t regval_tss; 176 177 /* Initialize the GDT entry */ 178 gdt[SOS_SEG_KERNEL_TSS] 179 = (struct x86_segment_descriptor) { 180 .limit_15_0= 0x67, /* See Intel x86 vol 3 section 6.2.2 */ 181 .base_paged_addr_15_0= (tss_vaddr) & 0xffff, 182 .base_paged_addr_23_16= (tss_vaddr >> 16) & 0xff, 183 .segment_type= 0x9, /* See Intel x86 vol 3 figure 6-3 */ 184 .descriptor_type= 0, /* (idem) */ 185 .dpl= 3, /* Allowed for CPL3 tasks */ 186 .present= 1, 187 .limit_19_16= 0, /* Size of a TSS is < 2^16 ! */ 188 .custom= 0, /* Unused */ 189 .zero= 0, 190 .op_size= 0, /* See Intel x86 vol 3 figure 6-3 */ 191 .granularity= 1, /* limit is in Bytes */ 192 .base_paged_addr_31_24= (tss_vaddr >> 24) & 0xff 193 }; 194 195 /* Load the TSS register into the processor */ 196 regval_tss = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, 197 SOS_SEG_KERNEL_TSS); 198 asm ("ltr %0" : :"r"(regval_tss)); 199 200 return SOS_OK; 201 } 202 203
[ source navigation ] | [ diff markup ] | [ identifier search ] | [ general search ] |