coverity appeasement
[minix.git] / kernel / arch / i386 / protect.c
blob23f566107f5a776305037c1904376f81539764f7
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.
4 */
6 #include <string.h>
7 #include <assert.h>
8 #include <machine/multiboot.h>
10 #include "kernel/kernel.h"
11 #include "archconst.h"
13 #include "arch_proto.h"
15 #include <libexec.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 /*===========================================================================*
39 * enable_iop *
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 /*===========================================================================*
53 * sdesc *
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));
67 } else {
68 segdp->limit_low = size;
69 segdp->granularity = size >> GRANULARITY_SHIFT;
71 segdp->granularity |= DEFAULT; /* means BIG for data seg */
74 /*===========================================================================*
75 * init_dataseg *
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 /*===========================================================================*
93 * init_codeseg *
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 },
121 { NULL, 0, 0}
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 },
146 { NULL, 0, 0}
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;
161 /* Build TSS. */
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
169 * usable word
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;
196 idp = &tab[vec_nr];
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);
223 void idt_init(void)
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)
233 x86_lidt(&idt_desc);
236 multiboot_module_t *bootmod(int pnr)
238 int i;
240 assert(pnr >= 0);
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++) {
247 int p;
248 p = i - NR_TASKS;
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);
259 int booting_cpu = 0;
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 */
268 idt_init();
269 idt_reload();
270 x86_lldt(LDT_SELECTOR); /* Load bogus ldt */
271 x86_ltr(TSS_SELECTOR(booting_cpu));
273 x86_load_kerncs();
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 /*===========================================================================*
282 * prot_init *
283 *===========================================================================*/
284 void prot_init()
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);
298 /* Build GDT */
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
315 * data.
318 pg_clear();
319 pg_identity(&kinfo); /* Still need 1:1 for lapic and video mem and such. */
320 pg_mapkernel();
321 pg_load();
323 prot_init_done = 1;
326 static int alloc_for_vm = 0;
328 void arch_post_init(void)
330 /* Let memory mapping code know what's going on at bootstrap time */
331 struct proc *vm;
332 vm = proc_addr(VM_PROC_NR);
333 get_cpulocal_var(ptproc) = vm;
334 pg_info(&vm->p_seg.p_cr3, &vm->p_seg.p_cr3_v);
337 int libexec_pg_alloc(struct exec_info *execi, off_t vaddr, size_t len)
339 pg_map(PG_ALLOCATEME, vaddr, vaddr+len, &kinfo);
340 pg_load();
341 memset((char *) vaddr, 0, len);
342 alloc_for_vm += len;
343 return OK;
346 void arch_boot_proc(struct boot_image *ip, struct proc *rp)
348 multiboot_module_t *mod;
350 if(rp->p_nr < 0) return;
352 mod = bootmod(rp->p_nr);
354 /* Important special case: we put VM in the bootstrap pagetable
355 * so it can run.
358 if(rp->p_nr == VM_PROC_NR) {
359 struct exec_info execi;
361 memset(&execi, 0, sizeof(execi));
363 /* exec parameters */
364 execi.stack_high = kinfo.user_sp;
365 execi.stack_size = 16 * 1024; /* not too crazy as it must be preallocated */
366 execi.proc_e = ip->endpoint;
367 execi.hdr = (char *) mod->mod_start; /* phys mem direct */
368 execi.hdr_len = mod->mod_end - mod->mod_start;
369 strlcpy(execi.progname, ip->proc_name, sizeof(execi.progname));
370 execi.frame_len = 0;
372 /* callbacks for use in the kernel */
373 execi.copymem = libexec_copy_memcpy;
374 execi.clearmem = libexec_clear_memset;
375 execi.allocmem_prealloc = libexec_pg_alloc;
376 execi.allocmem_ondemand = libexec_pg_alloc;
377 execi.clearproc = NULL;
379 /* parse VM ELF binary and alloc/map it into bootstrap pagetable */
380 libexec_load_elf(&execi);
382 /* Initialize the server stack pointer. Take it down three words
383 * to give startup code something to use as "argc", "argv" and "envp".
385 arch_proc_init(rp, execi.pc, kinfo.user_sp - 3*4, ip->proc_name);
387 /* Free VM blob that was just copied into existence. */
388 cut_memmap(&kinfo, mod->mod_start, mod->mod_end);
390 /* Remember them */
391 kinfo.vm_allocated_bytes = alloc_for_vm;