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: }