/* This file contains code for initialization of protected mode. * * The code must run in 16-bit mode (and be compiled with a 16-bit * compiler!) even for a 32-bit kernel. */ #include "kernel.h" #include "protect.h" #if INTEL_32BITS #include "protect1.c" /* local 16-bit versions of some functions */ #define INT_GATE_TYPE (INT_286_GATE | DESC_386_BIT) #define TSS_TYPE (AVL_286_TSS | DESC_386_BIT) #else #define INT_GATE_TYPE INT_286_GATE #define TSS_TYPE AVL_286_TSS #endif struct desctableptr_s { u16_t limit; u32_t base; /* really u24_t + pad for 286 */ }; struct gatedesc_s { u16_t offset_low; u16_t selector; u8_t pad; /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */ u8_t p_dpl_type; /* |P|DL|0|TYPE| */ #if INTEL_32BITS u16_t offset_high; #else u16_t reserved; #endif }; struct tss_s { reg_t backlink; reg_t sp0; reg_t ss0; reg_t sp1; reg_t ss1; reg_t sp2; reg_t ss2; #if INTEL_32BITS reg_t cr3; #endif reg_t ip; reg_t flags; reg_t ax; reg_t cx; reg_t dx; reg_t bx; reg_t sp; reg_t bp; reg_t si; reg_t di; reg_t es; reg_t cs; reg_t ss; reg_t ds; #if INTEL_32BITS reg_t fs; reg_t gs; #endif reg_t ldt; #if INTEL_32BITS u16_t trap; u16_t iobase; /* u8_t iomap[0]; */ #endif }; PUBLIC struct segdesc_s gdt[GDT_SIZE]; PRIVATE struct gatedesc_s idt[IDT_SIZE]; /* zero-init so none present */ PUBLIC struct tss_s tss; /* zero init */ FORWARD void int_gate(); /*=========================================================================* * int_gate * *=========================================================================*/ PRIVATE void int_gate(vec_nr, base, dpl_type) unsigned vec_nr; phys_bytes base; unsigned dpl_type; { /* Build descriptor for an interrupt gate. */ register struct gatedesc_s *idp; idp = &idt[vec_nr]; idp->offset_low = base; idp->selector = CS_SELECTOR; idp->p_dpl_type = dpl_type; #if INTEL_32BITS idp->offset_high = base >> OFFSET_HIGH_SHIFT; #endif } /*=========================================================================* * prot_init * *=========================================================================*/ PUBLIC void prot_init() { /* Set up tables for protected mode. * All GDT slots are allocated at compile time. */ phys_bytes code_bytes; phys_bytes data_bytes; struct gate_table_s *gtp; static struct gate_table_s { void (*gate)(); unsigned char vec_nr; unsigned char privilege; } gate_table[] = { divide_error, DIVIDE_VECTOR, INTR_PRIVILEGE, single_step_exception, DEBUG_VECTOR, INTR_PRIVILEGE, nmi, NMI_VECTOR, INTR_PRIVILEGE, breakpoint_exception, BREAKPOINT_VECTOR, USER_PRIVILEGE, overflow, OVERFLOW_VECTOR, USER_PRIVILEGE, bounds_check, BOUNDS_VECTOR, INTR_PRIVILEGE, inval_opcode, INVAL_OP_VECTOR, INTR_PRIVILEGE, copr_not_available, COPROC_NOT_VECTOR, INTR_PRIVILEGE, double_fault, DOUBLE_FAULT_VECTOR, INTR_PRIVILEGE, copr_seg_overrun, COPROC_SEG_VECTOR, INTR_PRIVILEGE, inval_tss, INVAL_TSS_VECTOR, INTR_PRIVILEGE, segment_not_present, SEG_NOT_VECTOR, INTR_PRIVILEGE, stack_exception, STACK_FAULT_VECTOR, INTR_PRIVILEGE, general_protection, PROTECTION_VECTOR, INTR_PRIVILEGE, #if INTEL_32BITS page_fault, PAGE_FAULT_VECTOR, INTR_PRIVILEGE, copr_error, COPROC_ERR_VECTOR, INTR_PRIVILEGE, #endif clock_int, CLOCK_VECTOR, INTR_PRIVILEGE, tty_int, KEYBOARD_VECTOR, INTR_PRIVILEGE, psecondary_int, SECONDARY_VECTOR, INTR_PRIVILEGE, #if AM_KERNEL #if !NONET eth_int, ETHER_VECTOR, INTR_PRIVILEGE, #endif #endif prs232_int, RS232_VECTOR, INTR_PRIVILEGE, disk_int, FLOPPY_VECTOR, INTR_PRIVILEGE, lpr_int, PRINTER_VECTOR, INTR_PRIVILEGE, wini_int, AT_WINI_VECTOR, INTR_PRIVILEGE, }; /* This is called early and can't use tables set up by main(). */ data_bytes = (phys_bytes) sizes[1] << CLICK_SHIFT; if (sizes[0] == 0) code_bytes = data_bytes; /* common I&D */ else code_bytes = (phys_bytes) sizes[0] << CLICK_SHIFT; /* Build temporary gdt and idt pointers in GDT where BIOS needs them. */ ((struct desctableptr_s *) &gdt[BIOS_GDT_INDEX])->limit = sizeof gdt - 1; ((struct desctableptr_s *) &gdt[BIOS_GDT_INDEX])->base = data_base + (phys_bytes) (vir_bytes) gdt; ((struct desctableptr_s *) &gdt[BIOS_IDT_INDEX])->limit = sizeof idt - 1; ((struct desctableptr_s *) &gdt[BIOS_IDT_INDEX])->base = data_base + (phys_bytes) (vir_bytes) idt; /* Build segment descriptors for tasks and interrupt handlers. */ init_dataseg(&gdt[DS_INDEX], data_base, data_bytes, INTR_PRIVILEGE); init_dataseg(&gdt[ES_INDEX], data_base, data_bytes, INTR_PRIVILEGE); init_dataseg(&gdt[SS_INDEX], data_base, data_bytes, INTR_PRIVILEGE); init_codeseg(&gdt[CS_INDEX], code_base, code_bytes, INTR_PRIVILEGE); /* Build segments for debugger. */ init_codeseg(&gdt[DB_CS_INDEX], hclick_to_physb(break_vector.selector), (phys_bytes) MAX_286_SEG_SIZE, INTR_PRIVILEGE); init_dataseg(&gdt[DB_DS_INDEX], hclick_to_physb(break_vector.selector), (phys_bytes) MAX_286_SEG_SIZE, INTR_PRIVILEGE); init_dataseg(&gdt[GDT_INDEX], data_base + (phys_bytes) (vir_bytes) gdt, (phys_bytes) sizeof gdt, INTR_PRIVILEGE); /* Build scratch descriptors for functions in klib286. */ init_dataseg(&gdt[DS_286_INDEX], (phys_bytes) 0, (phys_bytes) MAX_286_SEG_SIZE, TASK_PRIVILEGE); init_dataseg(&gdt[ES_286_INDEX], (phys_bytes) 0, (phys_bytes) MAX_286_SEG_SIZE, TASK_PRIVILEGE); /* Build descriptors for video segments. */ init_dataseg(&gdt[COLOR_INDEX], (phys_bytes) COLOR_BASE, (phys_bytes) COLOR_SIZE, TASK_PRIVILEGE); init_dataseg(&gdt[MONO_INDEX], (phys_bytes) MONO_BASE, (phys_bytes) MONO_SIZE, TASK_PRIVILEGE); #if AM_KERNEL #if !NONET /* Build descriptor for Western Digital Etherplus card buffer. */ init_dataseg(&gdt[EPLUS_INDEX], (phys_bytes) EPLUS_BASE, (phys_bytes) EPLUS_SIZE, TASK_PRIVILEGE); #endif /* !NONET */ #endif /* AM_KERNEL */ /* Build main TSS. * This is used only to record the stack pointer to be used after an * interrupt. * The pointer is set up so that an interrupt automatically saves the * current process's registers ip:cs:f:sp:ss in the correct slots in the * process table. */ tss.ss0 = DS_SELECTOR; init_dataseg(&gdt[TSS_INDEX], data_base + (phys_bytes) (vir_bytes) &tss, (phys_bytes) sizeof tss, INTR_PRIVILEGE); gdt[TSS_INDEX].access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE; /* Build descriptors for interrupt gates in IDT. */ for (gtp = &gate_table[0]; gtp < &gate_table[sizeof gate_table / sizeof gate_table[0]]; ++gtp) { int_gate(gtp->vec_nr, (phys_bytes) (vir_bytes) gtp->gate, PRESENT | INT_GATE_TYPE | (gtp->privilege << DPL_SHIFT)); } int_gate(SYS_VECTOR, (phys_bytes) (vir_bytes) p_s_call, PRESENT | (USER_PRIVILEGE << DPL_SHIFT) | INT_GATE_TYPE); #if INTEL_32BITS /* Build 16-bit code segment for debugger. Debugger runs mainly in 16-bit * mode but it is inconvenient to switch directly. */ init_codeseg(&gdt[DB_CS16_INDEX], hclick_to_physb(break_vector.selector), (phys_bytes) MAX_286_SEG_SIZE, INTR_PRIVILEGE); gdt[DB_CS16_INDEX].granularity &= ~DEFAULT; /* Complete building of main TSS. */ tss.iobase = sizeof tss; /* empty i/o permissions map */ /* Build flat data segment for functions in klib386. */ init_dataseg(&gdt[FLAT_DS_INDEX], (phys_bytes) 0, (phys_bytes) 0, TASK_PRIVILEGE); /* Complete building of interrupt gates. */ int_gate(SYS386_VECTOR, (phys_bytes) (vir_bytes) s_call, PRESENT | (USER_PRIVILEGE << DPL_SHIFT) | INT_GATE_TYPE); #endif /* Fix up debugger selectors, now the real-mode values are finished with. */ break_vector.selector = DB_CS_SELECTOR; sstep_vector.selector = DB_CS_SELECTOR; }