1433d6423SLionel Sambuc /* This file contains code for initialization of protected mode, to initialize
2433d6423SLionel Sambuc * code and data segment descriptors, and to initialize global descriptors
3433d6423SLionel Sambuc * for local descriptors in the process table.
4433d6423SLionel Sambuc */
5433d6423SLionel Sambuc
6433d6423SLionel Sambuc #include <assert.h>
7433d6423SLionel Sambuc #include <string.h>
8433d6423SLionel Sambuc
9433d6423SLionel Sambuc #include <minix/cpufeature.h>
10433d6423SLionel Sambuc #include <sys/types.h>
11433d6423SLionel Sambuc #include "kernel/kernel.h"
12433d6423SLionel Sambuc
13433d6423SLionel Sambuc #include "arch_proto.h"
14433d6423SLionel Sambuc
15433d6423SLionel Sambuc #include <sys/exec.h>
16433d6423SLionel Sambuc #include <libexec.h>
17433d6423SLionel Sambuc
18433d6423SLionel Sambuc #define INT_GATE_TYPE (INT_286_GATE | DESC_386_BIT)
19433d6423SLionel Sambuc #define TSS_TYPE (AVL_286_TSS | DESC_386_BIT)
20433d6423SLionel Sambuc
21433d6423SLionel Sambuc /* This is OK initially, when the 1:1 mapping is still there. */
22433d6423SLionel Sambuc char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER;
23433d6423SLionel Sambuc
24433d6423SLionel Sambuc /* Storage for gdt, idt and tss. */
25433d6423SLionel Sambuc struct segdesc_s gdt[GDT_SIZE] __aligned(DESC_SIZE);
26433d6423SLionel Sambuc struct gatedesc_s idt[IDT_SIZE] __aligned(DESC_SIZE);
27433d6423SLionel Sambuc struct tss_s tss[CONFIG_MAX_CPUS];
28433d6423SLionel Sambuc
29433d6423SLionel Sambuc u32_t k_percpu_stacks[CONFIG_MAX_CPUS];
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc int prot_init_done = 0;
32433d6423SLionel Sambuc
vir2phys(void * vir)33433d6423SLionel Sambuc phys_bytes vir2phys(void *vir)
34433d6423SLionel Sambuc {
35433d6423SLionel Sambuc extern char _kern_vir_base, _kern_phys_base; /* in kernel.lds */
36433d6423SLionel Sambuc u32_t offset = (vir_bytes) &_kern_vir_base -
37433d6423SLionel Sambuc (vir_bytes) &_kern_phys_base;
38433d6423SLionel Sambuc return (phys_bytes)vir - offset;
39433d6423SLionel Sambuc }
40433d6423SLionel Sambuc
41433d6423SLionel Sambuc /*===========================================================================*
42433d6423SLionel Sambuc * enable_iop *
43433d6423SLionel Sambuc *===========================================================================*/
enable_iop(struct proc * pp)44433d6423SLionel Sambuc void enable_iop(struct proc *pp)
45433d6423SLionel Sambuc {
46433d6423SLionel Sambuc /* Allow a user process to use I/O instructions. Change the I/O Permission
47433d6423SLionel Sambuc * Level bits in the psw. These specify least-privileged Current Permission
48433d6423SLionel Sambuc * Level allowed to execute I/O instructions. Users and servers have CPL 3.
49433d6423SLionel Sambuc * You can't have less privilege than that. Kernel has CPL 0, tasks CPL 1.
50433d6423SLionel Sambuc */
51433d6423SLionel Sambuc pp->p_reg.psw |= 0x3000;
52433d6423SLionel Sambuc }
53433d6423SLionel Sambuc
54433d6423SLionel Sambuc
55433d6423SLionel Sambuc /*===========================================================================*
56433d6423SLionel Sambuc * sdesc *
57433d6423SLionel Sambuc *===========================================================================*/
sdesc(struct segdesc_s * segdp,phys_bytes base,vir_bytes size)58433d6423SLionel Sambuc void sdesc(struct segdesc_s *segdp, phys_bytes base, vir_bytes size)
59433d6423SLionel Sambuc {
60433d6423SLionel Sambuc /* Fill in the size fields (base, limit and granularity) of a descriptor. */
61433d6423SLionel Sambuc segdp->base_low = base;
62433d6423SLionel Sambuc segdp->base_middle = base >> BASE_MIDDLE_SHIFT;
63433d6423SLionel Sambuc segdp->base_high = base >> BASE_HIGH_SHIFT;
64433d6423SLionel Sambuc
65433d6423SLionel Sambuc --size; /* convert to a limit, 0 size means 4G */
66433d6423SLionel Sambuc if (size > BYTE_GRAN_MAX) {
67433d6423SLionel Sambuc segdp->limit_low = size >> PAGE_GRAN_SHIFT;
68433d6423SLionel Sambuc segdp->granularity = GRANULAR | (size >>
69433d6423SLionel Sambuc (PAGE_GRAN_SHIFT + GRANULARITY_SHIFT));
70433d6423SLionel Sambuc } else {
71433d6423SLionel Sambuc segdp->limit_low = size;
72433d6423SLionel Sambuc segdp->granularity = size >> GRANULARITY_SHIFT;
73433d6423SLionel Sambuc }
74433d6423SLionel Sambuc segdp->granularity |= DEFAULT; /* means BIG for data seg */
75433d6423SLionel Sambuc }
76433d6423SLionel Sambuc
77433d6423SLionel Sambuc /*===========================================================================*
78433d6423SLionel Sambuc * init_dataseg *
79433d6423SLionel Sambuc *===========================================================================*/
init_param_dataseg(register struct segdesc_s * segdp,phys_bytes base,vir_bytes size,const int privilege)80433d6423SLionel Sambuc void init_param_dataseg(register struct segdesc_s *segdp,
81433d6423SLionel Sambuc phys_bytes base, vir_bytes size, const int privilege)
82433d6423SLionel Sambuc {
83433d6423SLionel Sambuc /* Build descriptor for a data segment. */
84433d6423SLionel Sambuc sdesc(segdp, base, size);
85433d6423SLionel Sambuc segdp->access = (privilege << DPL_SHIFT) | (PRESENT | SEGMENT |
86433d6423SLionel Sambuc WRITEABLE | ACCESSED);
87433d6423SLionel Sambuc /* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */
88433d6423SLionel Sambuc }
89433d6423SLionel Sambuc
init_dataseg(int index,const int privilege)90433d6423SLionel Sambuc void init_dataseg(int index, const int privilege)
91433d6423SLionel Sambuc {
92433d6423SLionel Sambuc init_param_dataseg(&gdt[index], 0, 0xFFFFFFFF, privilege);
93433d6423SLionel Sambuc }
94433d6423SLionel Sambuc
95433d6423SLionel Sambuc /*===========================================================================*
96433d6423SLionel Sambuc * init_codeseg *
97433d6423SLionel Sambuc *===========================================================================*/
init_codeseg(int index,int privilege)98433d6423SLionel Sambuc static void init_codeseg(int index, int privilege)
99433d6423SLionel Sambuc {
100433d6423SLionel Sambuc /* Build descriptor for a code segment. */
101433d6423SLionel Sambuc sdesc(&gdt[index], 0, 0xFFFFFFFF);
102433d6423SLionel Sambuc gdt[index].access = (privilege << DPL_SHIFT)
103433d6423SLionel Sambuc | (PRESENT | SEGMENT | EXECUTABLE | READABLE);
104433d6423SLionel Sambuc /* CONFORMING = 0, ACCESSED = 0 */
105433d6423SLionel Sambuc }
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc static struct gate_table_s gate_table_pic[] = {
108433d6423SLionel Sambuc { hwint00, VECTOR( 0), INTR_PRIVILEGE },
109433d6423SLionel Sambuc { hwint01, VECTOR( 1), INTR_PRIVILEGE },
110433d6423SLionel Sambuc { hwint02, VECTOR( 2), INTR_PRIVILEGE },
111433d6423SLionel Sambuc { hwint03, VECTOR( 3), INTR_PRIVILEGE },
112433d6423SLionel Sambuc { hwint04, VECTOR( 4), INTR_PRIVILEGE },
113433d6423SLionel Sambuc { hwint05, VECTOR( 5), INTR_PRIVILEGE },
114433d6423SLionel Sambuc { hwint06, VECTOR( 6), INTR_PRIVILEGE },
115433d6423SLionel Sambuc { hwint07, VECTOR( 7), INTR_PRIVILEGE },
116433d6423SLionel Sambuc { hwint08, VECTOR( 8), INTR_PRIVILEGE },
117433d6423SLionel Sambuc { hwint09, VECTOR( 9), INTR_PRIVILEGE },
118433d6423SLionel Sambuc { hwint10, VECTOR(10), INTR_PRIVILEGE },
119433d6423SLionel Sambuc { hwint11, VECTOR(11), INTR_PRIVILEGE },
120433d6423SLionel Sambuc { hwint12, VECTOR(12), INTR_PRIVILEGE },
121433d6423SLionel Sambuc { hwint13, VECTOR(13), INTR_PRIVILEGE },
122433d6423SLionel Sambuc { hwint14, VECTOR(14), INTR_PRIVILEGE },
123433d6423SLionel Sambuc { hwint15, VECTOR(15), INTR_PRIVILEGE },
124433d6423SLionel Sambuc { NULL, 0, 0}
125433d6423SLionel Sambuc };
126433d6423SLionel Sambuc
127433d6423SLionel Sambuc static struct gate_table_s gate_table_exceptions[] = {
128433d6423SLionel Sambuc { divide_error, DIVIDE_VECTOR, INTR_PRIVILEGE },
129433d6423SLionel Sambuc { single_step_exception, DEBUG_VECTOR, INTR_PRIVILEGE },
130433d6423SLionel Sambuc { nmi, NMI_VECTOR, INTR_PRIVILEGE },
131433d6423SLionel Sambuc { breakpoint_exception, BREAKPOINT_VECTOR, USER_PRIVILEGE },
132433d6423SLionel Sambuc { overflow, OVERFLOW_VECTOR, USER_PRIVILEGE },
133433d6423SLionel Sambuc { bounds_check, BOUNDS_VECTOR, INTR_PRIVILEGE },
134433d6423SLionel Sambuc { inval_opcode, INVAL_OP_VECTOR, INTR_PRIVILEGE },
135433d6423SLionel Sambuc { copr_not_available, COPROC_NOT_VECTOR, INTR_PRIVILEGE },
136433d6423SLionel Sambuc { double_fault, DOUBLE_FAULT_VECTOR, INTR_PRIVILEGE },
137433d6423SLionel Sambuc { copr_seg_overrun, COPROC_SEG_VECTOR, INTR_PRIVILEGE },
138433d6423SLionel Sambuc { inval_tss, INVAL_TSS_VECTOR, INTR_PRIVILEGE },
139433d6423SLionel Sambuc { segment_not_present, SEG_NOT_VECTOR, INTR_PRIVILEGE },
140433d6423SLionel Sambuc { stack_exception, STACK_FAULT_VECTOR, INTR_PRIVILEGE },
141433d6423SLionel Sambuc { general_protection, PROTECTION_VECTOR, INTR_PRIVILEGE },
142433d6423SLionel Sambuc { page_fault, PAGE_FAULT_VECTOR, INTR_PRIVILEGE },
143433d6423SLionel Sambuc { copr_error, COPROC_ERR_VECTOR, INTR_PRIVILEGE },
144433d6423SLionel Sambuc { alignment_check, ALIGNMENT_CHECK_VECTOR, INTR_PRIVILEGE },
145433d6423SLionel Sambuc { machine_check, MACHINE_CHECK_VECTOR, INTR_PRIVILEGE },
146433d6423SLionel Sambuc { simd_exception, SIMD_EXCEPTION_VECTOR, INTR_PRIVILEGE },
147433d6423SLionel Sambuc { ipc_entry_softint_orig, IPC_VECTOR_ORIG, USER_PRIVILEGE },
148433d6423SLionel Sambuc { kernel_call_entry_orig, KERN_CALL_VECTOR_ORIG, USER_PRIVILEGE },
149433d6423SLionel Sambuc { ipc_entry_softint_um, IPC_VECTOR_UM, USER_PRIVILEGE },
150433d6423SLionel Sambuc { kernel_call_entry_um, KERN_CALL_VECTOR_UM, USER_PRIVILEGE },
151433d6423SLionel Sambuc { NULL, 0, 0}
152433d6423SLionel Sambuc };
153433d6423SLionel Sambuc
tss_init(unsigned cpu,void * kernel_stack)154433d6423SLionel Sambuc int tss_init(unsigned cpu, void * kernel_stack)
155433d6423SLionel Sambuc {
156433d6423SLionel Sambuc struct tss_s * t = &tss[cpu];
157433d6423SLionel Sambuc int index = TSS_INDEX(cpu);
158433d6423SLionel Sambuc struct segdesc_s *tssgdt;
159433d6423SLionel Sambuc
160433d6423SLionel Sambuc tssgdt = &gdt[index];
161433d6423SLionel Sambuc
162433d6423SLionel Sambuc init_param_dataseg(tssgdt, (phys_bytes) t,
163433d6423SLionel Sambuc sizeof(struct tss_s), INTR_PRIVILEGE);
164433d6423SLionel Sambuc tssgdt->access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE;
165433d6423SLionel Sambuc
166433d6423SLionel Sambuc /* Build TSS. */
167433d6423SLionel Sambuc memset(t, 0, sizeof(*t));
168433d6423SLionel Sambuc t->ds = t->es = t->fs = t->gs = t->ss0 = KERN_DS_SELECTOR;
169433d6423SLionel Sambuc t->cs = KERN_CS_SELECTOR;
170433d6423SLionel Sambuc t->iobase = sizeof(struct tss_s); /* empty i/o permissions map */
171433d6423SLionel Sambuc
172433d6423SLionel Sambuc /*
173433d6423SLionel Sambuc * make space for process pointer and cpu id and point to the first
174433d6423SLionel Sambuc * usable word
175433d6423SLionel Sambuc */
176433d6423SLionel Sambuc k_percpu_stacks[cpu] = t->sp0 = ((unsigned) kernel_stack) - X86_STACK_TOP_RESERVED;
177433d6423SLionel Sambuc /*
178433d6423SLionel Sambuc * set the cpu id at the top of the stack so we know on which cpu is
179*d578d57bSGerhard Poul * this stack in use when we trap to kernel
180433d6423SLionel Sambuc */
181433d6423SLionel Sambuc *((reg_t *)(t->sp0 + 1 * sizeof(reg_t))) = cpu;
182433d6423SLionel Sambuc
183433d6423SLionel Sambuc /* Set up Intel SYSENTER support if available. */
184433d6423SLionel Sambuc if(minix_feature_flags & MKF_I386_INTEL_SYSENTER) {
185433d6423SLionel Sambuc ia32_msr_write(INTEL_MSR_SYSENTER_CS, 0, KERN_CS_SELECTOR);
186433d6423SLionel Sambuc ia32_msr_write(INTEL_MSR_SYSENTER_ESP, 0, t->sp0);
187433d6423SLionel Sambuc ia32_msr_write(INTEL_MSR_SYSENTER_EIP, 0, (u32_t) ipc_entry_sysenter);
188433d6423SLionel Sambuc }
189433d6423SLionel Sambuc
190433d6423SLionel Sambuc /* Set up AMD SYSCALL support if available. */
191433d6423SLionel Sambuc if(minix_feature_flags & MKF_I386_AMD_SYSCALL) {
192433d6423SLionel Sambuc u32_t msr_lo, msr_hi;
193433d6423SLionel Sambuc
194433d6423SLionel Sambuc /* set SYSCALL ENABLE bit in EFER MSR */
195433d6423SLionel Sambuc ia32_msr_read(AMD_MSR_EFER, &msr_hi, &msr_lo);
196433d6423SLionel Sambuc msr_lo |= AMD_EFER_SCE;
197433d6423SLionel Sambuc ia32_msr_write(AMD_MSR_EFER, msr_hi, msr_lo);
198433d6423SLionel Sambuc
199433d6423SLionel Sambuc /* set STAR register value */
200433d6423SLionel Sambuc #define set_star_cpu(forcpu) if(cpu == forcpu) { \
201433d6423SLionel Sambuc ia32_msr_write(AMD_MSR_STAR, \
202433d6423SLionel Sambuc ((u32_t)USER_CS_SELECTOR << 16) | (u32_t)KERN_CS_SELECTOR, \
203433d6423SLionel Sambuc (u32_t) ipc_entry_syscall_cpu ## forcpu); }
204433d6423SLionel Sambuc set_star_cpu(0);
205433d6423SLionel Sambuc set_star_cpu(1);
206433d6423SLionel Sambuc set_star_cpu(2);
207433d6423SLionel Sambuc set_star_cpu(3);
208433d6423SLionel Sambuc set_star_cpu(4);
209433d6423SLionel Sambuc set_star_cpu(5);
210433d6423SLionel Sambuc set_star_cpu(6);
211433d6423SLionel Sambuc set_star_cpu(7);
212433d6423SLionel Sambuc assert(CONFIG_MAX_CPUS <= 8);
213433d6423SLionel Sambuc }
214433d6423SLionel Sambuc
215433d6423SLionel Sambuc return SEG_SELECTOR(index);
216433d6423SLionel Sambuc }
217433d6423SLionel Sambuc
init_segdesc(int gdt_index,void * base,int size)218433d6423SLionel Sambuc phys_bytes init_segdesc(int gdt_index, void *base, int size)
219433d6423SLionel Sambuc {
220433d6423SLionel Sambuc struct desctableptr_s *dtp = (struct desctableptr_s *) &gdt[gdt_index];
221433d6423SLionel Sambuc dtp->limit = size - 1;
222433d6423SLionel Sambuc dtp->base = (phys_bytes) base;
223433d6423SLionel Sambuc
224433d6423SLionel Sambuc return (phys_bytes) dtp;
225433d6423SLionel Sambuc }
226433d6423SLionel Sambuc
int_gate(struct gatedesc_s * tab,unsigned vec_nr,vir_bytes offset,unsigned dpl_type)227433d6423SLionel Sambuc void int_gate(struct gatedesc_s *tab,
228433d6423SLionel Sambuc unsigned vec_nr, vir_bytes offset, unsigned dpl_type)
229433d6423SLionel Sambuc {
230433d6423SLionel Sambuc /* Build descriptor for an interrupt gate. */
231433d6423SLionel Sambuc register struct gatedesc_s *idp;
232433d6423SLionel Sambuc
233433d6423SLionel Sambuc idp = &tab[vec_nr];
234433d6423SLionel Sambuc idp->offset_low = offset;
235433d6423SLionel Sambuc idp->selector = KERN_CS_SELECTOR;
236433d6423SLionel Sambuc idp->p_dpl_type = dpl_type;
237433d6423SLionel Sambuc idp->offset_high = offset >> OFFSET_HIGH_SHIFT;
238433d6423SLionel Sambuc }
239433d6423SLionel Sambuc
int_gate_idt(unsigned vec_nr,vir_bytes offset,unsigned dpl_type)240433d6423SLionel Sambuc void int_gate_idt(unsigned vec_nr, vir_bytes offset, unsigned dpl_type)
241433d6423SLionel Sambuc {
242433d6423SLionel Sambuc int_gate(idt, vec_nr, offset, dpl_type);
243433d6423SLionel Sambuc }
244433d6423SLionel Sambuc
idt_copy_vectors(struct gate_table_s * first)245433d6423SLionel Sambuc void idt_copy_vectors(struct gate_table_s * first)
246433d6423SLionel Sambuc {
247433d6423SLionel Sambuc struct gate_table_s *gtp;
248433d6423SLionel Sambuc for (gtp = first; gtp->gate; gtp++) {
249433d6423SLionel Sambuc int_gate(idt, gtp->vec_nr, (vir_bytes) gtp->gate,
250433d6423SLionel Sambuc PRESENT | INT_GATE_TYPE |
251433d6423SLionel Sambuc (gtp->privilege << DPL_SHIFT));
252433d6423SLionel Sambuc }
253433d6423SLionel Sambuc }
254433d6423SLionel Sambuc
idt_copy_vectors_pic(void)255433d6423SLionel Sambuc void idt_copy_vectors_pic(void)
256433d6423SLionel Sambuc {
257433d6423SLionel Sambuc idt_copy_vectors(gate_table_pic);
258433d6423SLionel Sambuc }
259433d6423SLionel Sambuc
idt_init(void)260433d6423SLionel Sambuc void idt_init(void)
261433d6423SLionel Sambuc {
262433d6423SLionel Sambuc idt_copy_vectors_pic();
263433d6423SLionel Sambuc idt_copy_vectors(gate_table_exceptions);
264433d6423SLionel Sambuc }
265433d6423SLionel Sambuc
266433d6423SLionel Sambuc struct desctableptr_s gdt_desc, idt_desc;
267433d6423SLionel Sambuc
idt_reload(void)268433d6423SLionel Sambuc void idt_reload(void)
269433d6423SLionel Sambuc {
270433d6423SLionel Sambuc x86_lidt(&idt_desc);
271433d6423SLionel Sambuc }
272433d6423SLionel Sambuc
bootmod(int pnr)273433d6423SLionel Sambuc multiboot_module_t *bootmod(int pnr)
274433d6423SLionel Sambuc {
275433d6423SLionel Sambuc int i;
276433d6423SLionel Sambuc
277433d6423SLionel Sambuc assert(pnr >= 0);
278433d6423SLionel Sambuc
279433d6423SLionel Sambuc /* Search for desired process in boot process
280433d6423SLionel Sambuc * list. The first NR_TASKS ones do not correspond
281433d6423SLionel Sambuc * to a module, however, so we don't search those.
282433d6423SLionel Sambuc */
283433d6423SLionel Sambuc for(i = NR_TASKS; i < NR_BOOT_PROCS; i++) {
284433d6423SLionel Sambuc int p;
285433d6423SLionel Sambuc p = i - NR_TASKS;
286433d6423SLionel Sambuc if(image[i].proc_nr == pnr) {
287433d6423SLionel Sambuc assert(p < MULTIBOOT_MAX_MODS);
288433d6423SLionel Sambuc assert(p < kinfo.mbi.mi_mods_count);
289433d6423SLionel Sambuc return &kinfo.module_list[p];
290433d6423SLionel Sambuc }
291433d6423SLionel Sambuc }
292433d6423SLionel Sambuc
293433d6423SLionel Sambuc panic("boot module %d not found", pnr);
294433d6423SLionel Sambuc }
295433d6423SLionel Sambuc
296433d6423SLionel Sambuc int booting_cpu = 0;
297433d6423SLionel Sambuc
prot_load_selectors(void)298433d6423SLionel Sambuc void prot_load_selectors(void)
299433d6423SLionel Sambuc {
300433d6423SLionel Sambuc /* this function is called by both prot_init by the BSP and
301433d6423SLionel Sambuc * the early AP booting code in mpx.S by secondary CPU's.
302433d6423SLionel Sambuc * everything is set up the same except for the TSS that is per-CPU.
303433d6423SLionel Sambuc */
304433d6423SLionel Sambuc x86_lgdt(&gdt_desc); /* Load gdt */
305433d6423SLionel Sambuc idt_init();
306433d6423SLionel Sambuc idt_reload();
307433d6423SLionel Sambuc x86_lldt(LDT_SELECTOR); /* Load bogus ldt */
308433d6423SLionel Sambuc x86_ltr(TSS_SELECTOR(booting_cpu));
309433d6423SLionel Sambuc
310433d6423SLionel Sambuc x86_load_kerncs();
311433d6423SLionel Sambuc x86_load_ds(KERN_DS_SELECTOR);
312433d6423SLionel Sambuc x86_load_es(KERN_DS_SELECTOR);
313433d6423SLionel Sambuc x86_load_fs(KERN_DS_SELECTOR);
314433d6423SLionel Sambuc x86_load_gs(KERN_DS_SELECTOR);
315433d6423SLionel Sambuc x86_load_ss(KERN_DS_SELECTOR);
316433d6423SLionel Sambuc }
317433d6423SLionel Sambuc
318433d6423SLionel Sambuc /*===========================================================================*
319433d6423SLionel Sambuc * prot_init *
320433d6423SLionel Sambuc *===========================================================================*/
prot_init(void)3216077d1adSDr. Florian Grätz void prot_init(void)
322433d6423SLionel Sambuc {
323433d6423SLionel Sambuc extern char k_boot_stktop;
324433d6423SLionel Sambuc
325433d6423SLionel Sambuc if(_cpufeature(_CPUF_I386_SYSENTER))
326433d6423SLionel Sambuc minix_feature_flags |= MKF_I386_INTEL_SYSENTER;
327433d6423SLionel Sambuc if(_cpufeature(_CPUF_I386_SYSCALL))
328433d6423SLionel Sambuc minix_feature_flags |= MKF_I386_AMD_SYSCALL;
329433d6423SLionel Sambuc
330433d6423SLionel Sambuc memset(gdt, 0, sizeof(gdt));
331433d6423SLionel Sambuc memset(idt, 0, sizeof(idt));
332433d6423SLionel Sambuc
333433d6423SLionel Sambuc /* Build GDT, IDT, IDT descriptors. */
334433d6423SLionel Sambuc gdt_desc.base = (u32_t) gdt;
335433d6423SLionel Sambuc gdt_desc.limit = sizeof(gdt)-1;
336433d6423SLionel Sambuc idt_desc.base = (u32_t) idt;
337433d6423SLionel Sambuc idt_desc.limit = sizeof(idt)-1;
338433d6423SLionel Sambuc tss_init(0, &k_boot_stktop);
339433d6423SLionel Sambuc
340433d6423SLionel Sambuc /* Build GDT */
341433d6423SLionel Sambuc init_param_dataseg(&gdt[LDT_INDEX],
342433d6423SLionel Sambuc (phys_bytes) 0, 0, INTR_PRIVILEGE); /* unusable LDT */
343433d6423SLionel Sambuc gdt[LDT_INDEX].access = PRESENT | LDT;
344433d6423SLionel Sambuc init_codeseg(KERN_CS_INDEX, INTR_PRIVILEGE);
345433d6423SLionel Sambuc init_dataseg(KERN_DS_INDEX, INTR_PRIVILEGE);
346433d6423SLionel Sambuc init_codeseg(USER_CS_INDEX, USER_PRIVILEGE);
347433d6423SLionel Sambuc init_dataseg(USER_DS_INDEX, USER_PRIVILEGE);
348433d6423SLionel Sambuc
349433d6423SLionel Sambuc /* Currently the multiboot segments are loaded; which is fine, but
350433d6423SLionel Sambuc * let's replace them with the ones from our own GDT so we test
351433d6423SLionel Sambuc * right away whether they work as expected.
352433d6423SLionel Sambuc */
353433d6423SLionel Sambuc prot_load_selectors();
354433d6423SLionel Sambuc
355433d6423SLionel Sambuc /* Set up a new post-relocate bootstrap pagetable so that
356433d6423SLionel Sambuc * we can map in VM, and we no longer rely on pre-relocated
357433d6423SLionel Sambuc * data.
358433d6423SLionel Sambuc */
359433d6423SLionel Sambuc
360433d6423SLionel Sambuc pg_clear();
361433d6423SLionel Sambuc pg_identity(&kinfo); /* Still need 1:1 for lapic and video mem and such. */
362433d6423SLionel Sambuc pg_mapkernel();
363433d6423SLionel Sambuc pg_load();
364433d6423SLionel Sambuc
365433d6423SLionel Sambuc prot_init_done = 1;
366433d6423SLionel Sambuc }
367433d6423SLionel Sambuc
368433d6423SLionel Sambuc static int alloc_for_vm = 0;
369433d6423SLionel Sambuc
arch_post_init(void)370433d6423SLionel Sambuc void arch_post_init(void)
371433d6423SLionel Sambuc {
372433d6423SLionel Sambuc /* Let memory mapping code know what's going on at bootstrap time */
373433d6423SLionel Sambuc struct proc *vm;
374433d6423SLionel Sambuc vm = proc_addr(VM_PROC_NR);
375433d6423SLionel Sambuc get_cpulocal_var(ptproc) = vm;
376433d6423SLionel Sambuc pg_info(&vm->p_seg.p_cr3, &vm->p_seg.p_cr3_v);
377433d6423SLionel Sambuc }
378433d6423SLionel Sambuc
libexec_pg_alloc(struct exec_info * execi,vir_bytes vaddr,size_t len)379433d6423SLionel Sambuc static int libexec_pg_alloc(struct exec_info *execi, vir_bytes vaddr, size_t len)
380433d6423SLionel Sambuc {
381433d6423SLionel Sambuc pg_map(PG_ALLOCATEME, vaddr, vaddr+len, &kinfo);
382433d6423SLionel Sambuc pg_load();
383433d6423SLionel Sambuc memset((char *) vaddr, 0, len);
384433d6423SLionel Sambuc alloc_for_vm += len;
385433d6423SLionel Sambuc return OK;
386433d6423SLionel Sambuc }
387433d6423SLionel Sambuc
arch_boot_proc(struct boot_image * ip,struct proc * rp)388433d6423SLionel Sambuc void arch_boot_proc(struct boot_image *ip, struct proc *rp)
389433d6423SLionel Sambuc {
390433d6423SLionel Sambuc multiboot_module_t *mod;
391433d6423SLionel Sambuc struct ps_strings *psp;
392433d6423SLionel Sambuc char *sp;
393433d6423SLionel Sambuc
394433d6423SLionel Sambuc if(rp->p_nr < 0) return;
395433d6423SLionel Sambuc
396433d6423SLionel Sambuc mod = bootmod(rp->p_nr);
397433d6423SLionel Sambuc
398433d6423SLionel Sambuc /* Important special case: we put VM in the bootstrap pagetable
399433d6423SLionel Sambuc * so it can run.
400433d6423SLionel Sambuc */
401433d6423SLionel Sambuc
402433d6423SLionel Sambuc if(rp->p_nr == VM_PROC_NR) {
403433d6423SLionel Sambuc struct exec_info execi;
404433d6423SLionel Sambuc
405433d6423SLionel Sambuc memset(&execi, 0, sizeof(execi));
406433d6423SLionel Sambuc
407433d6423SLionel Sambuc /* exec parameters */
408433d6423SLionel Sambuc execi.stack_high = kinfo.user_sp;
409433d6423SLionel Sambuc execi.stack_size = 64 * 1024; /* not too crazy as it must be preallocated */
410433d6423SLionel Sambuc execi.proc_e = ip->endpoint;
411433d6423SLionel Sambuc execi.hdr = (char *) mod->mod_start; /* phys mem direct */
412433d6423SLionel Sambuc execi.filesize = execi.hdr_len = mod->mod_end - mod->mod_start;
413433d6423SLionel Sambuc strlcpy(execi.progname, ip->proc_name, sizeof(execi.progname));
414433d6423SLionel Sambuc execi.frame_len = 0;
415433d6423SLionel Sambuc
416433d6423SLionel Sambuc /* callbacks for use in the kernel */
417433d6423SLionel Sambuc execi.copymem = libexec_copy_memcpy;
418433d6423SLionel Sambuc execi.clearmem = libexec_clear_memset;
419433d6423SLionel Sambuc execi.allocmem_prealloc_junk = libexec_pg_alloc;
420433d6423SLionel Sambuc execi.allocmem_prealloc_cleared = libexec_pg_alloc;
421433d6423SLionel Sambuc execi.allocmem_ondemand = libexec_pg_alloc;
422433d6423SLionel Sambuc execi.clearproc = NULL;
423433d6423SLionel Sambuc
424433d6423SLionel Sambuc /* parse VM ELF binary and alloc/map it into bootstrap pagetable */
425433d6423SLionel Sambuc if(libexec_load_elf(&execi) != OK)
426433d6423SLionel Sambuc panic("VM loading failed");
427433d6423SLionel Sambuc
428433d6423SLionel Sambuc /* Setup a ps_strings struct on the stack, pointing to the
429433d6423SLionel Sambuc * following argv, envp. */
430433d6423SLionel Sambuc sp = (char *)execi.stack_high;
431433d6423SLionel Sambuc sp -= sizeof(struct ps_strings);
432433d6423SLionel Sambuc psp = (struct ps_strings *) sp;
433433d6423SLionel Sambuc
434433d6423SLionel Sambuc /* Take the stack pointer down three words to give startup code
435433d6423SLionel Sambuc * something to use as "argc", "argv" and "envp".
436433d6423SLionel Sambuc */
437433d6423SLionel Sambuc sp -= (sizeof(void *) + sizeof(void *) + sizeof(int));
438433d6423SLionel Sambuc
439433d6423SLionel Sambuc // linear address space, so it is available.
440433d6423SLionel Sambuc psp->ps_argvstr = (char **)(sp + sizeof(int));
441433d6423SLionel Sambuc psp->ps_nargvstr = 0;
442433d6423SLionel Sambuc psp->ps_envstr = psp->ps_argvstr + sizeof(void *);
443433d6423SLionel Sambuc psp->ps_nenvstr = 0;
444433d6423SLionel Sambuc
445433d6423SLionel Sambuc arch_proc_init(rp, execi.pc, (vir_bytes)sp,
446433d6423SLionel Sambuc execi.stack_high - sizeof(struct ps_strings),
447433d6423SLionel Sambuc ip->proc_name);
448433d6423SLionel Sambuc
449433d6423SLionel Sambuc /* Free VM blob that was just copied into existence. */
450433d6423SLionel Sambuc add_memmap(&kinfo, mod->mod_start, mod->mod_end-mod->mod_start);
451433d6423SLionel Sambuc mod->mod_end = mod->mod_start = 0;
452433d6423SLionel Sambuc
453433d6423SLionel Sambuc /* Remember them */
454433d6423SLionel Sambuc kinfo.vm_allocated_bytes = alloc_for_vm;
455433d6423SLionel Sambuc }
456433d6423SLionel Sambuc }
457