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: */ 5: 6: #include "kernel.h" 7: #include "proc.h" 8: #include "protect.h" 9: 10: #if _WORD_SIZE == 4 11: #define INT_GATE_TYPE (INT_286_GATE | DESC_386_BIT) 12: #define TSS_TYPE (AVL_286_TSS | DESC_386_BIT) 13: #else 14: #define INT_GATE_TYPE INT_286_GATE 15: #define TSS_TYPE AVL_286_TSS 16: #endif 17: 18: struct desctableptr_s { 19: char limit[sizeof(u16_t)]; 20: char base[sizeof(u32_t)]; /* really u24_t + pad for 286 */ 21: }; 22: 23: struct gatedesc_s { 24: u16_t offset_low; 25: u16_t selector; 26: u8_t pad; /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */ 27: u8_t p_dpl_type; /* |P|DL|0|TYPE| */ 28: u16_t offset_high; 29: }; 30: 31: struct tss_s { 32: reg_t backlink; 33: reg_t sp0; /* stack pointer to use during interrupt */ 34: reg_t ss0; /* " segment " " " " */ 35: reg_t sp1; 36: reg_t ss1; 37: reg_t sp2; 38: reg_t ss2; 39: #if _WORD_SIZE == 4 40: reg_t cr3; 41: #endif 42: reg_t ip; 43: reg_t flags; 44: reg_t ax; 45: reg_t cx; 46: reg_t dx; 47: reg_t bx; 48: reg_t sp; 49: reg_t bp; 50: reg_t si; 51: reg_t di; 52: reg_t es; 53: reg_t cs; 54: reg_t ss; 55: reg_t ds; 56: #if _WORD_SIZE == 4 57: reg_t fs; 58: reg_t gs; 59: #endif 60: reg_t ldt; 61: #if _WORD_SIZE == 4 62: u16_t trap; 63: u16_t iobase; 64: /* u8_t iomap[0]; */ 65: #endif 66: }; 67: 68: PUBLIC struct segdesc_s gdt[GDT_SIZE]; 69: PRIVATE struct gatedesc_s idt[IDT_SIZE]; /* zero-init so none present */ 70: PUBLIC struct tss_s tss; /* zero init */ 71: 72: FORWARD _PROTOTYPE( void int_gate, (unsigned vec_nr, vir_bytes offset, 73: unsigned dpl_type) ); 74: FORWARD _PROTOTYPE( void sdesc, (struct segdesc_s *segdp, phys_bytes base, 75: vir_bytes size) ); 76: 77: /*=========================================================================* 78: * prot_init * 79: *=========================================================================*/ 80: PUBLIC void prot_init() 81: { 82: /* Set up tables for protected mode. 83: * All GDT slots are allocated at compile time. 84: */ 85: 86: extern int etext, end; 87: #define code_bytes ((vir_bytes) &etext) /* Size of code segment. */ 88: #define data_bytes ((vir_bytes) &end) /* Size of data segment. */ 89: struct gate_table_s *gtp; 90: struct desctableptr_s *dtp; 91: unsigned ldt_index; 92: register struct proc *rp; 93: 94: static struct gate_table_s { 95: _PROTOTYPE( void (*gate), (void) ); 96: unsigned char vec_nr; 97: unsigned char privilege; 98: } 99: gate_table[] = { 100: divide_error, DIVIDE_VECTOR, INTR_PRIVILEGE, 101: single_step_exception, DEBUG_VECTOR, INTR_PRIVILEGE, 102: nmi, NMI_VECTOR, INTR_PRIVILEGE, 103: breakpoint_exception, BREAKPOINT_VECTOR, USER_PRIVILEGE, 104: overflow, OVERFLOW_VECTOR, USER_PRIVILEGE, 105: bounds_check, BOUNDS_VECTOR, INTR_PRIVILEGE, 106: inval_opcode, INVAL_OP_VECTOR, INTR_PRIVILEGE, 107: copr_not_available, COPROC_NOT_VECTOR, INTR_PRIVILEGE, 108: double_fault, DOUBLE_FAULT_VECTOR, INTR_PRIVILEGE, 109: copr_seg_overrun, COPROC_SEG_VECTOR, INTR_PRIVILEGE, 110: inval_tss, INVAL_TSS_VECTOR, INTR_PRIVILEGE, 111: segment_not_present, SEG_NOT_VECTOR, INTR_PRIVILEGE, 112: stack_exception, STACK_FAULT_VECTOR, INTR_PRIVILEGE, 113: general_protection, PROTECTION_VECTOR, INTR_PRIVILEGE, 114: #if _WORD_SIZE == 4 115: page_fault, PAGE_FAULT_VECTOR, INTR_PRIVILEGE, 116: copr_error, COPROC_ERR_VECTOR, INTR_PRIVILEGE, 117: #endif 118: { hwint00, VECTOR( 0), INTR_PRIVILEGE }, 119: { hwint01, VECTOR( 1), INTR_PRIVILEGE }, 120: { hwint02, VECTOR( 2), INTR_PRIVILEGE }, 121: { hwint03, VECTOR( 3), INTR_PRIVILEGE }, 122: { hwint04, VECTOR( 4), INTR_PRIVILEGE }, 123: { hwint05, VECTOR( 5), INTR_PRIVILEGE }, 124: { hwint06, VECTOR( 6), INTR_PRIVILEGE }, 125: { hwint07, VECTOR( 7), INTR_PRIVILEGE }, 126: { hwint08, VECTOR( 8), INTR_PRIVILEGE }, 127: { hwint09, VECTOR( 9), INTR_PRIVILEGE }, 128: { hwint10, VECTOR(10), INTR_PRIVILEGE }, 129: { hwint11, VECTOR(11), INTR_PRIVILEGE }, 130: { hwint12, VECTOR(12), INTR_PRIVILEGE }, 131: { hwint13, VECTOR(13), INTR_PRIVILEGE }, 132: { hwint14, VECTOR(14), INTR_PRIVILEGE }, 133: { hwint15, VECTOR(15), INTR_PRIVILEGE }, 134: #if _WORD_SIZE == 2 135: { p_s_call, SYS_VECTOR, USER_PRIVILEGE }, /* 286 system call */ 136: #else 137: { s_call, SYS386_VECTOR, USER_PRIVILEGE }, /* 386 system call */ 138: #endif 139: { level0_call, LEVEL0_VECTOR, TASK_PRIVILEGE }, 140: }; 141: 142: /* Build gdt and idt pointers in GDT where the BIOS expects them. */ 143: dtp= (struct desctableptr_s *) &gdt[GDT_INDEX]; 144: * (u16_t *) dtp->limit = (sizeof gdt) - 1; 145: * (u32_t *) dtp->base = vir2phys(gdt); 146: 147: dtp= (struct desctableptr_s *) &gdt[IDT_INDEX]; 148: * (u16_t *) dtp->limit = (sizeof idt) - 1; 149: * (u32_t *) dtp->base = vir2phys(idt); 150: 151: /* Build segment descriptors for tasks and interrupt handlers. */ 152: init_codeseg(&gdt[CS_INDEX], code_base, code_bytes, INTR_PRIVILEGE); 153: init_dataseg(&gdt[DS_INDEX], data_base, data_bytes, INTR_PRIVILEGE); 154: init_dataseg(&gdt[ES_INDEX], 0L, 0, TASK_PRIVILEGE); 155: 156: /* Build scratch descriptors for functions in klib88. */ 157: init_dataseg(&gdt[DS_286_INDEX], 0L, 0, TASK_PRIVILEGE); 158: init_dataseg(&gdt[ES_286_INDEX], 0L, 0, TASK_PRIVILEGE); 159: 160: /* Build local descriptors in GDT for LDT's in process table. 161: * The LDT's are allocated at compile time in the process table, and 162: * initialized whenever a process' map is initialized or changed. 163: */ 164: for (rp = BEG_PROC_ADDR, ldt_index = FIRST_LDT_INDEX; 165: rp < END_PROC_ADDR; ++rp, ldt_index++) { 166: init_dataseg(&gdt[ldt_index], vir2phys(rp->p_ldt), 167: sizeof(rp->p_ldt), INTR_PRIVILEGE); 168: gdt[ldt_index].access = PRESENT | LDT; 169: rp->p_ldt_sel = ldt_index * DESC_SIZE; 170: } 171: 172: /* Build main TSS. 173: * This is used only to record the stack pointer to be used after an 174: * interrupt. 175: * The pointer is set up so that an interrupt automatically saves the 176: * current process's registers ip:cs:f:sp:ss in the correct slots in the 177: * process table. 178: */ 179: tss.ss0 = DS_SELECTOR; 180: init_dataseg(&gdt[TSS_INDEX], vir2phys(&tss), sizeof(tss), INTR_PRIVILEGE); 181: gdt[TSS_INDEX].access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE; 182: 183: /* Build descriptors for interrupt gates in IDT. */ 184: for (gtp = &gate_table[0]; 185: gtp < &gate_table[sizeof gate_table / sizeof gate_table[0]]; ++gtp) { 186: int_gate(gtp->vec_nr, (vir_bytes) gtp->gate, 187: PRESENT | INT_GATE_TYPE | (gtp->privilege << DPL_SHIFT)); 188: } 189: 190: #if _WORD_SIZE == 4 191: /* Complete building of main TSS. */ 192: tss.iobase = sizeof tss; /* empty i/o permissions map */ 193: #endif 194: } 195: 196: /*=========================================================================* 197: * init_codeseg * 198: *=========================================================================*/ 199: PUBLIC void init_codeseg(segdp, base, size, privilege) 200: register struct segdesc_s *segdp; 201: phys_bytes base; 202: vir_bytes size; 203: int privilege; 204: { 205: /* Build descriptor for a code segment. */ 206: 207: sdesc(segdp, base, size); 208: segdp->access = (privilege << DPL_SHIFT) 209: | (PRESENT | SEGMENT | EXECUTABLE | READABLE); 210: /* CONFORMING = 0, ACCESSED = 0 */ 211: } 212: 213: /*=========================================================================* 214: * init_dataseg * 215: *=========================================================================*/ 216: PUBLIC void init_dataseg(segdp, base, size, privilege) 217: register struct segdesc_s *segdp; 218: phys_bytes base; 219: vir_bytes size; 220: int privilege; 221: { 222: /* Build descriptor for a data segment. */ 223: 224: sdesc(segdp, base, size); 225: segdp->access = (privilege << DPL_SHIFT) | (PRESENT | SEGMENT | WRITEABLE); 226: /* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */ 227: } 228: 229: /*=========================================================================* 230: * sdesc * 231: *=========================================================================*/ 232: PRIVATE void sdesc(segdp, base, size) 233: register struct segdesc_s *segdp; 234: phys_bytes base; 235: vir_bytes size; 236: { 237: /* Fill in the size fields (base, limit and granularity) of a descriptor. */ 238: 239: segdp->base_low = base; 240: segdp->base_middle = base >> BASE_MIDDLE_SHIFT; 241: segdp->base_high = base >> BASE_HIGH_SHIFT; 242: 243: #if _WORD_SIZE == 4 244: --size; /* convert to a limit, 0 size means 4G */ 245: if (size > BYTE_GRAN_MAX) { 246: segdp->limit_low = size >> PAGE_GRAN_SHIFT; 247: segdp->granularity = GRANULAR | (size >> 248: (PAGE_GRAN_SHIFT + GRANULARITY_SHIFT)); 249: } else { 250: segdp->limit_low = size; 251: segdp->granularity = size >> GRANULARITY_SHIFT; 252: } 253: segdp->granularity |= DEFAULT; /* means BIG for data seg */ 254: #else 255: segdp->limit_low = size - 1; 256: #endif 257: } 258: 259: /*=========================================================================* 260: * seg2phys * 261: *=========================================================================*/ 262: PUBLIC phys_bytes seg2phys(seg) 263: U16_t seg; 264: { 265: /* Return the base address of a segment, with seg being either a 8086 segment 266: * register, or a 286/386 segment selector. 267: */ 268: phys_bytes base; 269: struct segdesc_s *segdp; 270: 271: if (!protected_mode) { 272: base = hclick_to_physb(seg); 273: } else { 274: segdp = &gdt[seg >> 3]; 275: base = ((u32_t) segdp->base_low << 0) 276: | ((u32_t) segdp->base_middle << 16) 277: | ((u32_t) segdp->base_high << 24); 278: } 279: return base; 280: } 281: 282: 283: /*=========================================================================* 284: * phys2seg * 285: *=========================================================================*/ 286: PUBLIC void phys2seg(seg, off, phys) 287: u16_t *seg; 288: vir_bytes *off; 289: phys_bytes phys; 290: { 291: /* Return a segment selector and offset that can be used to reach a physical 292: * address, for use by a driver doing memory I/O in the A0000 - DFFFF range. 293: */ 294: #if _WORD_SIZE == 2 295: if (!protected_mode) { 296: *seg = phys / HCLICK_SIZE; 297: *off = phys % HCLICK_SIZE; 298: } else { 299: unsigned bank = phys >> 16; 300: unsigned index = bank - 0xA + A_INDEX; 301: init_dataseg(&gdt[index], (phys_bytes) bank << 16, 0, TASK_PRIVILEGE); 302: *seg = (index * 0x08) | TASK_PRIVILEGE; 303: *off = phys & 0xFFFF; 304: } 305: #else 306: *seg = FLAT_DS_SELECTOR; 307: *off = phys; 308: #endif 309: } 310: 311: /*=========================================================================* 312: * int_gate * 313: *=========================================================================*/ 314: PRIVATE void int_gate(vec_nr, offset, dpl_type) 315: unsigned vec_nr; 316: vir_bytes offset; 317: unsigned dpl_type; 318: { 319: /* Build descriptor for an interrupt gate. */ 320: 321: register struct gatedesc_s *idp; 322: 323: idp = &idt[vec_nr]; 324: idp->offset_low = offset; 325: idp->selector = CS_SELECTOR; 326: idp->p_dpl_type = dpl_type; 327: #if _WORD_SIZE == 4 328: idp->offset_high = offset >> OFFSET_HIGH_SHIFT; 329: #endif 330: } 331: 332: /*=========================================================================* 333: * enable_iop * 334: *=========================================================================*/ 335: PUBLIC void enable_iop(pp) 336: struct proc *pp; 337: { 338: /* Allow a user process to use I/O instructions. Change the I/O Permission 339: * Level bits in the psw. These specify least-privileged Current Permission 340: * Level allowed to execute I/O instructions. Users and servers have CPL 3. 341: * You can't have less privilege than that. Kernel has CPL 0, tasks CPL 1. 342: */ 343: pp->p_reg.psw |= 0x3000; 344: }