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.
8 #include <machine/multiboot.h>
10 #include "kernel/kernel.h"
11 #include "archconst.h"
13 #include "arch_proto.h"
17 #define INT_GATE_TYPE (INT_286_GATE | DESC_386_BIT)
18 #define TSS_TYPE (AVL_286_TSS | DESC_386_BIT)
20 /* This is OK initially, when the 1:1 mapping is still there. */
21 char *video_mem
= (char *) MULTIBOOT_VIDEO_BUFFER
;
23 /* Storage for gdt, idt and tss. */
24 struct segdesc_s gdt
[GDT_SIZE
] __aligned(DESC_SIZE
);
25 struct gatedesc_s idt
[IDT_SIZE
] __aligned(DESC_SIZE
);
26 struct tss_s tss
[CONFIG_MAX_CPUS
];
28 int prot_init_done
= 0;
30 phys_bytes
vir2phys(void *vir
)
32 extern char _kern_vir_base
, _kern_phys_base
; /* in kernel.lds */
33 u32_t offset
= (vir_bytes
) &_kern_vir_base
-
34 (vir_bytes
) &_kern_phys_base
;
35 return (phys_bytes
)vir
- offset
;
38 /*===========================================================================*
40 *===========================================================================*/
41 void enable_iop(struct proc
*pp
)
43 /* Allow a user process to use I/O instructions. Change the I/O Permission
44 * Level bits in the psw. These specify least-privileged Current Permission
45 * Level allowed to execute I/O instructions. Users and servers have CPL 3.
46 * You can't have less privilege than that. Kernel has CPL 0, tasks CPL 1.
48 pp
->p_reg
.psw
|= 0x3000;
52 /*===========================================================================*
54 *===========================================================================*/
55 void sdesc(struct segdesc_s
*segdp
, phys_bytes base
, vir_bytes size
)
57 /* Fill in the size fields (base, limit and granularity) of a descriptor. */
58 segdp
->base_low
= base
;
59 segdp
->base_middle
= base
>> BASE_MIDDLE_SHIFT
;
60 segdp
->base_high
= base
>> BASE_HIGH_SHIFT
;
62 --size
; /* convert to a limit, 0 size means 4G */
63 if (size
> BYTE_GRAN_MAX
) {
64 segdp
->limit_low
= size
>> PAGE_GRAN_SHIFT
;
65 segdp
->granularity
= GRANULAR
| (size
>>
66 (PAGE_GRAN_SHIFT
+ GRANULARITY_SHIFT
));
68 segdp
->limit_low
= size
;
69 segdp
->granularity
= size
>> GRANULARITY_SHIFT
;
71 segdp
->granularity
|= DEFAULT
; /* means BIG for data seg */
74 /*===========================================================================*
76 *===========================================================================*/
77 void init_param_dataseg(register struct segdesc_s
*segdp
,
78 phys_bytes base
, vir_bytes size
, const int privilege
)
80 /* Build descriptor for a data segment. */
81 sdesc(segdp
, base
, size
);
82 segdp
->access
= (privilege
<< DPL_SHIFT
) | (PRESENT
| SEGMENT
|
83 WRITEABLE
| ACCESSED
);
84 /* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */
87 void init_dataseg(int index
, const int privilege
)
89 init_param_dataseg(&gdt
[index
], 0, 0xFFFFFFFF, privilege
);
92 /*===========================================================================*
94 *===========================================================================*/
95 static void init_codeseg(int index
, int privilege
)
97 /* Build descriptor for a code segment. */
98 sdesc(&gdt
[index
], 0, 0xFFFFFFFF);
99 gdt
[index
].access
= (privilege
<< DPL_SHIFT
)
100 | (PRESENT
| SEGMENT
| EXECUTABLE
| READABLE
);
101 /* CONFORMING = 0, ACCESSED = 0 */
104 static 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 static struct gate_table_s gate_table_exceptions
[] = {
125 { divide_error
, DIVIDE_VECTOR
, INTR_PRIVILEGE
},
126 { single_step_exception
, DEBUG_VECTOR
, INTR_PRIVILEGE
},
127 { nmi
, NMI_VECTOR
, INTR_PRIVILEGE
},
128 { breakpoint_exception
, BREAKPOINT_VECTOR
, USER_PRIVILEGE
},
129 { overflow
, OVERFLOW_VECTOR
, USER_PRIVILEGE
},
130 { bounds_check
, BOUNDS_VECTOR
, INTR_PRIVILEGE
},
131 { inval_opcode
, INVAL_OP_VECTOR
, INTR_PRIVILEGE
},
132 { copr_not_available
, COPROC_NOT_VECTOR
, INTR_PRIVILEGE
},
133 { double_fault
, DOUBLE_FAULT_VECTOR
, INTR_PRIVILEGE
},
134 { copr_seg_overrun
, COPROC_SEG_VECTOR
, INTR_PRIVILEGE
},
135 { inval_tss
, INVAL_TSS_VECTOR
, INTR_PRIVILEGE
},
136 { segment_not_present
, SEG_NOT_VECTOR
, INTR_PRIVILEGE
},
137 { stack_exception
, STACK_FAULT_VECTOR
, INTR_PRIVILEGE
},
138 { general_protection
, PROTECTION_VECTOR
, INTR_PRIVILEGE
},
139 { page_fault
, PAGE_FAULT_VECTOR
, INTR_PRIVILEGE
},
140 { copr_error
, COPROC_ERR_VECTOR
, INTR_PRIVILEGE
},
141 { alignment_check
, ALIGNMENT_CHECK_VECTOR
, INTR_PRIVILEGE
},
142 { machine_check
, MACHINE_CHECK_VECTOR
, INTR_PRIVILEGE
},
143 { simd_exception
, SIMD_EXCEPTION_VECTOR
, INTR_PRIVILEGE
},
144 { ipc_entry
, IPC_VECTOR
, USER_PRIVILEGE
},
145 { kernel_call_entry
, KERN_CALL_VECTOR
, USER_PRIVILEGE
},
149 int tss_init(unsigned cpu
, void * kernel_stack
)
151 struct tss_s
* t
= &tss
[cpu
];
152 int index
= TSS_INDEX(cpu
);
153 struct segdesc_s
*tssgdt
;
155 tssgdt
= &gdt
[index
];
157 init_param_dataseg(tssgdt
, (phys_bytes
) t
,
158 sizeof(struct tss_s
), INTR_PRIVILEGE
);
159 tssgdt
->access
= PRESENT
| (INTR_PRIVILEGE
<< DPL_SHIFT
) | TSS_TYPE
;
162 memset(t
, 0, sizeof(*t
));
163 t
->ds
= t
->es
= t
->fs
= t
->gs
= t
->ss0
= KERN_DS_SELECTOR
;
164 t
->cs
= KERN_CS_SELECTOR
;
165 t
->iobase
= sizeof(struct tss_s
); /* empty i/o permissions map */
168 * make space for process pointer and cpu id and point to the first
171 t
->sp0
= ((unsigned) kernel_stack
) - X86_STACK_TOP_RESERVED
;
173 * set the cpu id at the top of the stack so we know on which cpu is
174 * this stak in use when we trap to kernel
176 *((reg_t
*)(t
->sp0
+ 1 * sizeof(reg_t
))) = cpu
;
178 return SEG_SELECTOR(index
);
181 phys_bytes
init_segdesc(int gdt_index
, void *base
, int size
)
183 struct desctableptr_s
*dtp
= (struct desctableptr_s
*) &gdt
[gdt_index
];
184 dtp
->limit
= size
- 1;
185 dtp
->base
= (phys_bytes
) base
;
187 return (phys_bytes
) dtp
;
190 void int_gate(struct gatedesc_s
*tab
,
191 unsigned vec_nr
, vir_bytes offset
, unsigned dpl_type
)
193 /* Build descriptor for an interrupt gate. */
194 register struct gatedesc_s
*idp
;
197 idp
->offset_low
= offset
;
198 idp
->selector
= KERN_CS_SELECTOR
;
199 idp
->p_dpl_type
= dpl_type
;
200 idp
->offset_high
= offset
>> OFFSET_HIGH_SHIFT
;
203 void int_gate_idt(unsigned vec_nr
, vir_bytes offset
, unsigned dpl_type
)
205 int_gate(idt
, vec_nr
, offset
, dpl_type
);
208 void idt_copy_vectors(struct gate_table_s
* first
)
210 struct gate_table_s
*gtp
;
211 for (gtp
= first
; gtp
->gate
; gtp
++) {
212 int_gate(idt
, gtp
->vec_nr
, (vir_bytes
) gtp
->gate
,
213 PRESENT
| INT_GATE_TYPE
|
214 (gtp
->privilege
<< DPL_SHIFT
));
218 void idt_copy_vectors_pic(void)
220 idt_copy_vectors(gate_table_pic
);
225 idt_copy_vectors_pic();
226 idt_copy_vectors(gate_table_exceptions
);
229 struct desctableptr_s gdt_desc
, idt_desc
;
231 void idt_reload(void)
236 multiboot_module_t
*bootmod(int pnr
)
242 /* Search for desired process in boot process
243 * list. The first NR_TASKS ones do not correspond
244 * to a module, however, so we don't search those.
246 for(i
= NR_TASKS
; i
< NR_BOOT_PROCS
; i
++) {
249 if(image
[i
].proc_nr
== pnr
) {
250 assert(p
< MULTIBOOT_MAX_MODS
);
251 assert(p
< kinfo
.mbi
.mods_count
);
252 return &kinfo
.module_list
[p
];
256 panic("boot module %d not found", pnr
);
261 void prot_load_selectors(void)
263 /* this function is called by both prot_init by the BSP and
264 * the early AP booting code in mpx.S by secondary CPU's.
265 * everything is set up the same except for the TSS that is per-CPU.
267 x86_lgdt(&gdt_desc
); /* Load gdt */
270 x86_lldt(LDT_SELECTOR
); /* Load bogus ldt */
271 x86_ltr(TSS_SELECTOR(booting_cpu
));
274 x86_load_ds(KERN_DS_SELECTOR
);
275 x86_load_es(KERN_DS_SELECTOR
);
276 x86_load_fs(KERN_DS_SELECTOR
);
277 x86_load_gs(KERN_DS_SELECTOR
);
278 x86_load_ss(KERN_DS_SELECTOR
);
281 /*===========================================================================*
283 *===========================================================================*/
286 extern char k_boot_stktop
;
288 memset(gdt
, 0, sizeof(gdt
));
289 memset(idt
, 0, sizeof(idt
));
291 /* Build GDT, IDT, IDT descriptors. */
292 gdt_desc
.base
= (u32_t
) gdt
;
293 gdt_desc
.limit
= sizeof(gdt
)-1;
294 idt_desc
.base
= (u32_t
) idt
;
295 idt_desc
.limit
= sizeof(idt
)-1;
296 tss_init(0, &k_boot_stktop
);
299 init_param_dataseg(&gdt
[LDT_INDEX
],
300 (phys_bytes
) 0, 0, INTR_PRIVILEGE
); /* unusable LDT */
301 gdt
[LDT_INDEX
].access
= PRESENT
| LDT
;
302 init_codeseg(KERN_CS_INDEX
, INTR_PRIVILEGE
);
303 init_dataseg(KERN_DS_INDEX
, INTR_PRIVILEGE
);
304 init_codeseg(USER_CS_INDEX
, USER_PRIVILEGE
);
305 init_dataseg(USER_DS_INDEX
, USER_PRIVILEGE
);
307 /* Currently the multiboot segments are loaded; which is fine, but
308 * let's replace them with the ones from our own GDT so we test
309 * right away whether they work as expected.
311 prot_load_selectors();
313 /* Set up a new post-relocate bootstrap pagetable so that
314 * we can map in VM, and we no longer rely on pre-relocated
319 pg_identity(&kinfo
); /* Still need 1:1 for lapic and video mem and such. */
326 void arch_post_init(void)
328 /* Let memory mapping code know what's going on at bootstrap time */
330 vm
= proc_addr(VM_PROC_NR
);
331 get_cpulocal_var(ptproc
) = vm
;
332 pg_info(&vm
->p_seg
.p_cr3
, &vm
->p_seg
.p_cr3_v
);
335 int libexec_pg_alloc(struct exec_info
*execi
, off_t vaddr
, size_t len
)
337 pg_map(PG_ALLOCATEME
, vaddr
, vaddr
+len
, &kinfo
);
339 memset((char *) vaddr
, 0, len
);
343 void arch_boot_proc(struct boot_image
*ip
, struct proc
*rp
)
345 multiboot_module_t
*mod
;
347 if(rp
->p_nr
< 0) return;
349 mod
= bootmod(rp
->p_nr
);
351 /* Important special case: we put VM in the bootstrap pagetable
355 if(rp
->p_nr
== VM_PROC_NR
) {
356 struct exec_info execi
;
358 memset(&execi
, 0, sizeof(execi
));
360 /* exec parameters */
361 execi
.stack_high
= kinfo
.user_sp
;
362 execi
.stack_size
= 16 * 1024; /* not too crazy as it must be preallocated */
363 execi
.proc_e
= ip
->endpoint
;
364 execi
.hdr
= (char *) mod
->mod_start
; /* phys mem direct */
365 execi
.hdr_len
= mod
->mod_end
- mod
->mod_start
;
366 strlcpy(execi
.progname
, ip
->proc_name
, sizeof(execi
.progname
));
369 /* callbacks for use in the kernel */
370 execi
.copymem
= libexec_copy_memcpy
;
371 execi
.clearmem
= libexec_clear_memset
;
372 execi
.allocmem_prealloc
= libexec_pg_alloc
;
373 execi
.allocmem_ondemand
= libexec_pg_alloc
;
374 execi
.clearproc
= NULL
;
376 /* parse VM ELF binary and alloc/map it into bootstrap pagetable */
377 libexec_load_elf(&execi
);
379 /* Initialize the server stack pointer. Take it down three words
380 * to give startup code something to use as "argc", "argv" and "envp".
382 arch_proc_init(rp
, execi
.pc
, kinfo
.user_sp
- 3*4, ip
->proc_name
);
384 /* Free VM blob that was just copied into existence. */
385 cut_memmap(&kinfo
, mod
->mod_start
, mod
->mod_end
);