1 /* This file contains code for initialization of protected mode, to initialize
2 * code and data segment descriptors, and to initialize global descriptors
3 * for local descriptors in the process table.
6 #include "../../kernel.h"
7 #include "../../proc.h"
12 #define INT_GATE_TYPE (INT_286_GATE | DESC_386_BIT)
13 #define TSS_TYPE (AVL_286_TSS | DESC_386_BIT)
15 struct desctableptr_s
{
16 char limit
[sizeof(u16_t
)];
17 char base
[sizeof(u32_t
)]; /* really u24_t + pad for 286 */
23 u8_t pad
; /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */
24 u8_t p_dpl_type
; /* |P|DL|0|TYPE| */
28 PUBLIC
struct segdesc_s gdt
[GDT_SIZE
]; /* used in klib.s and mpx.s */
29 PRIVATE
struct gatedesc_s idt
[IDT_SIZE
]; /* zero-init so none present */
30 PUBLIC
struct tss_s tss
; /* zero init */
32 FORWARD
_PROTOTYPE( void sdesc
, (struct segdesc_s
*segdp
, phys_bytes base
,
35 /*===========================================================================*
37 *===========================================================================*/
38 PUBLIC
void enable_iop(struct proc
*pp
)
40 /* Allow a user process to use I/O instructions. Change the I/O Permission
41 * Level bits in the psw. These specify least-privileged Current Permission
42 * Level allowed to execute I/O instructions. Users and servers have CPL 3.
43 * You can't have less privilege than that. Kernel has CPL 0, tasks CPL 1.
45 pp
->p_reg
.psw
|= 0x3000;
48 /*===========================================================================*
50 *===========================================================================*/
51 PUBLIC phys_bytes
seg2phys(U16_t seg
)
53 /* Return the base address of a segment, with seg being a
54 * register, or a 286/386 segment selector.
57 struct segdesc_s
*segdp
;
59 segdp
= &gdt
[seg
>> 3];
60 base
= ((u32_t
) segdp
->base_low
<< 0)
61 | ((u32_t
) segdp
->base_middle
<< 16)
62 | ((u32_t
) segdp
->base_high
<< 24);
66 /*===========================================================================*
68 *===========================================================================*/
69 PRIVATE
void phys2seg(u16_t
*seg
, vir_bytes
*off
, phys_bytes phys
)
71 /* Return a segment selector and offset that can be used to reach a physical
72 * address, for use by a driver doing memory I/O in the A0000 - DFFFF range.
74 *seg
= FLAT_DS_SELECTOR
;
75 *off
= (vir_bytes
) phys
;
78 /*===========================================================================*
80 *===========================================================================*/
81 PUBLIC
void init_dataseg(register struct segdesc_s
*segdp
,
82 phys_bytes base
, vir_bytes size
, int privilege
)
84 /* Build descriptor for a data segment. */
85 sdesc(segdp
, base
, size
);
86 segdp
->access
= (privilege
<< DPL_SHIFT
) | (PRESENT
| SEGMENT
|
88 /* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */
91 /*===========================================================================*
93 *===========================================================================*/
94 PRIVATE
void init_codeseg(register struct segdesc_s
*segdp
, phys_bytes base
,
95 vir_bytes size
, int privilege
)
97 /* Build descriptor for a code segment. */
98 sdesc(segdp
, base
, size
);
99 segdp
->access
= (privilege
<< DPL_SHIFT
)
100 | (PRESENT
| SEGMENT
| EXECUTABLE
| READABLE
);
101 /* CONFORMING = 0, ACCESSED = 0 */
104 PUBLIC
struct gate_table_s gate_table_pic
[] = {
105 { hwint00
, VECTOR( 0), INTR_PRIVILEGE
},
106 { hwint01
, VECTOR( 1), INTR_PRIVILEGE
},
107 { hwint02
, VECTOR( 2), INTR_PRIVILEGE
},
108 { hwint03
, VECTOR( 3), INTR_PRIVILEGE
},
109 { hwint04
, VECTOR( 4), INTR_PRIVILEGE
},
110 { hwint05
, VECTOR( 5), INTR_PRIVILEGE
},
111 { hwint06
, VECTOR( 6), INTR_PRIVILEGE
},
112 { hwint07
, VECTOR( 7), INTR_PRIVILEGE
},
113 { hwint08
, VECTOR( 8), INTR_PRIVILEGE
},
114 { hwint09
, VECTOR( 9), INTR_PRIVILEGE
},
115 { hwint10
, VECTOR(10), INTR_PRIVILEGE
},
116 { hwint11
, VECTOR(11), INTR_PRIVILEGE
},
117 { hwint12
, VECTOR(12), INTR_PRIVILEGE
},
118 { hwint13
, VECTOR(13), INTR_PRIVILEGE
},
119 { hwint14
, VECTOR(14), INTR_PRIVILEGE
},
120 { hwint15
, VECTOR(15), INTR_PRIVILEGE
},
124 /*===========================================================================*
126 *===========================================================================*/
127 PUBLIC
void prot_init(void)
129 /* Set up tables for protected mode.
130 * All GDT slots are allocated at compile time.
132 struct desctableptr_s
*dtp
;
134 register struct proc
*rp
;
136 /* Click-round kernel. */
137 if(kinfo
.data_base
% CLICK_SIZE
)
138 panic("kinfo.data_base not aligned");
139 kinfo
.data_size
= (phys_bytes
) (CLICK_CEIL(kinfo
.data_size
));
141 /* Build gdt and idt pointers in GDT where the BIOS expects them. */
142 dtp
= (struct desctableptr_s
*) &gdt
[GDT_INDEX
];
143 * (u16_t
*) dtp
->limit
= (sizeof gdt
) - 1;
144 * (u32_t
*) dtp
->base
= vir2phys(gdt
);
146 dtp
= (struct desctableptr_s
*) &gdt
[IDT_INDEX
];
147 * (u16_t
*) dtp
->limit
= (sizeof idt
) - 1;
148 * (u32_t
*) dtp
->base
= vir2phys(idt
);
150 /* Build segment descriptors for tasks and interrupt handlers. */
151 init_codeseg(&gdt
[CS_INDEX
],
152 kinfo
.code_base
, kinfo
.code_size
, INTR_PRIVILEGE
);
153 init_dataseg(&gdt
[DS_INDEX
],
154 kinfo
.data_base
, kinfo
.data_size
, INTR_PRIVILEGE
);
155 init_dataseg(&gdt
[ES_INDEX
], 0L, 0, INTR_PRIVILEGE
);
157 /* Build local descriptors in GDT for LDT's in process table.
158 * The LDT's are allocated at compile time in the process table, and
159 * initialized whenever a process' map is initialized or changed.
161 for (rp
= BEG_PROC_ADDR
, ldt_index
= FIRST_LDT_INDEX
;
162 rp
< END_PROC_ADDR
; ++rp
, ldt_index
++) {
163 init_dataseg(&gdt
[ldt_index
], vir2phys(rp
->p_seg
.p_ldt
),
164 sizeof(rp
->p_seg
.p_ldt
), INTR_PRIVILEGE
);
165 gdt
[ldt_index
].access
= PRESENT
| LDT
;
166 rp
->p_seg
.p_ldt_sel
= ldt_index
* DESC_SIZE
;
170 tss
.ss0
= DS_SELECTOR
;
171 init_dataseg(&gdt
[TSS_INDEX
], vir2phys(&tss
), sizeof(tss
), INTR_PRIVILEGE
);
172 gdt
[TSS_INDEX
].access
= PRESENT
| (INTR_PRIVILEGE
<< DPL_SHIFT
) | TSS_TYPE
;
174 /* Complete building of main TSS. */
175 tss
.iobase
= sizeof tss
; /* empty i/o permissions map */
178 PUBLIC
void idt_copy_vectors(struct gate_table_s
* first
)
180 struct gate_table_s
*gtp
;
181 for (gtp
= first
; gtp
->gate
; gtp
++) {
182 int_gate(gtp
->vec_nr
, (vir_bytes
) gtp
->gate
,
183 PRESENT
| INT_GATE_TYPE
|
184 (gtp
->privilege
<< DPL_SHIFT
));
188 /* Build descriptors for interrupt gates in IDT. */
189 PUBLIC
void idt_init(void)
191 struct gate_table_s gate_table
[] = {
192 { divide_error
, DIVIDE_VECTOR
, INTR_PRIVILEGE
},
193 { single_step_exception
, DEBUG_VECTOR
, INTR_PRIVILEGE
},
194 { nmi
, NMI_VECTOR
, INTR_PRIVILEGE
},
195 { breakpoint_exception
, BREAKPOINT_VECTOR
, USER_PRIVILEGE
},
196 { overflow
, OVERFLOW_VECTOR
, USER_PRIVILEGE
},
197 { bounds_check
, BOUNDS_VECTOR
, INTR_PRIVILEGE
},
198 { inval_opcode
, INVAL_OP_VECTOR
, INTR_PRIVILEGE
},
199 { copr_not_available
, COPROC_NOT_VECTOR
, INTR_PRIVILEGE
},
200 { double_fault
, DOUBLE_FAULT_VECTOR
, INTR_PRIVILEGE
},
201 { copr_seg_overrun
, COPROC_SEG_VECTOR
, INTR_PRIVILEGE
},
202 { inval_tss
, INVAL_TSS_VECTOR
, INTR_PRIVILEGE
},
203 { segment_not_present
, SEG_NOT_VECTOR
, INTR_PRIVILEGE
},
204 { stack_exception
, STACK_FAULT_VECTOR
, INTR_PRIVILEGE
},
205 { general_protection
, PROTECTION_VECTOR
, INTR_PRIVILEGE
},
206 { page_fault
, PAGE_FAULT_VECTOR
, INTR_PRIVILEGE
},
207 { copr_error
, COPROC_ERR_VECTOR
, INTR_PRIVILEGE
},
208 { alignment_check
, ALIGNMENT_CHECK_VECTOR
, INTR_PRIVILEGE
},
209 { machine_check
, MACHINE_CHECK_VECTOR
, INTR_PRIVILEGE
},
210 { simd_exception
, SIMD_EXCEPTION_VECTOR
, INTR_PRIVILEGE
},
211 { ipc_entry
, IPC_VECTOR
, USER_PRIVILEGE
},
212 { kernel_call_entry
, KERN_CALL_VECTOR
, USER_PRIVILEGE
},
216 idt_copy_vectors(gate_table
);
217 idt_copy_vectors(gate_table_pic
);
221 /*===========================================================================*
223 *===========================================================================*/
224 PRIVATE
void sdesc(segdp
, base
, size
)
225 register struct segdesc_s
*segdp
;
229 /* Fill in the size fields (base, limit and granularity) of a descriptor. */
230 segdp
->base_low
= base
;
231 segdp
->base_middle
= base
>> BASE_MIDDLE_SHIFT
;
232 segdp
->base_high
= base
>> BASE_HIGH_SHIFT
;
234 --size
; /* convert to a limit, 0 size means 4G */
235 if (size
> BYTE_GRAN_MAX
) {
236 segdp
->limit_low
= size
>> PAGE_GRAN_SHIFT
;
237 segdp
->granularity
= GRANULAR
| (size
>>
238 (PAGE_GRAN_SHIFT
+ GRANULARITY_SHIFT
));
240 segdp
->limit_low
= size
;
241 segdp
->granularity
= size
>> GRANULARITY_SHIFT
;
243 segdp
->granularity
|= DEFAULT
; /* means BIG for data seg */
246 /*===========================================================================*
248 *===========================================================================*/
249 PUBLIC
void int_gate(vec_nr
, offset
, dpl_type
)
254 /* Build descriptor for an interrupt gate. */
255 register struct gatedesc_s
*idp
;
258 idp
->offset_low
= offset
;
259 idp
->selector
= CS_SELECTOR
;
260 idp
->p_dpl_type
= dpl_type
;
261 idp
->offset_high
= offset
>> OFFSET_HIGH_SHIFT
;
264 /*===========================================================================*
266 *===========================================================================*/
267 PUBLIC
void alloc_segments(register struct proc
*rp
)
269 /* This is called at system initialization from main() and by do_newmap().
270 * The code has a separate function because of all hardware-dependencies.
272 phys_bytes code_bytes
;
273 phys_bytes data_bytes
;
276 data_bytes
= (phys_bytes
) (rp
->p_memmap
[S
].mem_vir
+
277 rp
->p_memmap
[S
].mem_len
) << CLICK_SHIFT
;
278 if (rp
->p_memmap
[T
].mem_len
== 0)
279 code_bytes
= data_bytes
; /* common I&D, poor protect */
281 code_bytes
= (phys_bytes
) rp
->p_memmap
[T
].mem_len
<< CLICK_SHIFT
;
282 privilege
= USER_PRIVILEGE
;
283 init_codeseg(&rp
->p_seg
.p_ldt
[CS_LDT_INDEX
],
284 (phys_bytes
) rp
->p_memmap
[T
].mem_phys
<< CLICK_SHIFT
,
285 code_bytes
, privilege
);
286 init_dataseg(&rp
->p_seg
.p_ldt
[DS_LDT_INDEX
],
287 (phys_bytes
) rp
->p_memmap
[D
].mem_phys
<< CLICK_SHIFT
,
288 data_bytes
, privilege
);
289 rp
->p_reg
.cs
= (CS_LDT_INDEX
* DESC_SIZE
) | TI
| privilege
;
294 rp
->p_reg
.ds
= (DS_LDT_INDEX
*DESC_SIZE
) | TI
| privilege
;
297 /*===========================================================================*
299 *===========================================================================*/
300 PRIVATE
void check_segments(char *File
, int line
)
305 for (rp
= BEG_PROC_ADDR
; rp
< END_PROC_ADDR
; ++rp
) {
313 privilege
= USER_PRIVILEGE
;
315 cs
= (CS_LDT_INDEX
*DESC_SIZE
) | TI
| privilege
;
316 ds
= (DS_LDT_INDEX
*DESC_SIZE
) | TI
| privilege
;
318 #define CHECK(s1, s2) if(s1 != s2) { \
319 printf("%s:%d: " #s1 " != " #s2 " for ep %d\n", \
320 File, line, rp->p_endpoint); fail++; } checked++;
322 CHECK(rp
->p_reg
.cs
, cs
);
323 CHECK(rp
->p_reg
.gs
, ds
);
324 CHECK(rp
->p_reg
.fs
, ds
);
325 CHECK(rp
->p_reg
.ss
, ds
);
326 if(rp
->p_endpoint
!= -2) {
327 CHECK(rp
->p_reg
.es
, ds
);
329 CHECK(rp
->p_reg
.ds
, ds
);
332 printf("%d/%d checks failed\n", fail
, checked
);
333 panic("wrong: %d", fail
);
337 /*===========================================================================*
339 *===========================================================================*/
340 PUBLIC
void printseg(char *banner
, int iscs
, struct proc
*pr
, u32_t selector
)
342 u32_t base
, limit
, index
, dpl
;
343 struct segdesc_s
*desc
;
345 if(banner
) { printf("%s", banner
); }
347 index
= selector
>> 3;
349 printf("RPL %d, ind %d of ",
350 (selector
& RPL_MASK
), index
);
354 if(index
>= LDT_SIZE
) {
355 printf("invalid index in ldt\n");
359 printf("local selector but unknown process\n");
362 desc
= &pr
->p_seg
.p_ldt
[index
];
365 if(index
>= GDT_SIZE
) {
366 printf("invalid index in gdt\n");
372 limit
= desc
->limit_low
|
373 (((u32_t
) desc
->granularity
& LIMIT_HIGH
) << GRANULARITY_SHIFT
);
375 if(desc
->granularity
& GRANULAR
) {
376 limit
= (limit
<< PAGE_GRAN_SHIFT
) + 0xfff;
379 base
= desc
->base_low
|
380 ((u32_t
) desc
->base_middle
<< BASE_MIDDLE_SHIFT
) |
381 ((u32_t
) desc
->base_high
<< BASE_HIGH_SHIFT
);
383 printf(" -> base 0x%08lx size 0x%08lx ", base
, limit
+1);
386 if(!(desc
->granularity
& BIG
))
389 if(!(desc
->granularity
& BIG
))
393 if(desc
->granularity
& 0x20) { /* reserved */
394 panic("granularity reserved field set");
397 if(!(desc
->access
& PRESENT
))
398 printf("notpresent ");
400 if(!(desc
->access
& SEGMENT
))
403 if(desc
->access
& EXECUTABLE
) {
405 if(desc
->access
& CONFORMING
) printf("conforming ");
406 if(!(desc
->access
& READABLE
)) printf("non-readable ");
409 if(desc
->access
& EXPAND_DOWN
) printf("non-expand-down ");
410 if(!(desc
->access
& WRITEABLE
)) printf("non-writable ");
413 if(!(desc
->access
& ACCESSED
)) {
417 dpl
= ((u32_t
) desc
->access
& DPL
) >> DPL_SHIFT
;
419 printf("DPL %d\n", dpl
);
424 /*===========================================================================*
425 * prot_set_kern_seg_limit *
426 *===========================================================================*/
427 PUBLIC
int prot_set_kern_seg_limit(vir_bytes limit
)
433 if(limit
<= kinfo
.data_base
) {
434 printf("prot_set_kern_seg_limit: limit bogus\n");
438 /* Do actual increase. */
439 orig_click
= kinfo
.data_size
/ CLICK_SIZE
;
440 kinfo
.data_size
= limit
- kinfo
.data_base
;
441 incr_clicks
= kinfo
.data_size
/ CLICK_SIZE
- orig_click
;
445 /* Increase kernel processes too. */
446 for (rp
= BEG_PROC_ADDR
; rp
< END_PROC_ADDR
; ++rp
) {
447 if (isemptyp(rp
) || !iskernelp(rp
))
449 rp
->p_memmap
[S
].mem_len
+= incr_clicks
;
451 rp
->p_memmap
[S
].mem_len
-= incr_clicks
;