The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kernel/protect.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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];          /* used in klib.s and mpx.s */
   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   struct gate_table_s *gtp;
   86   struct desctableptr_s *dtp;
   87   unsigned ldt_index;
   88   register struct proc *rp;
   89 
   90   static struct gate_table_s {
   91         _PROTOTYPE( void (*gate), (void) );
   92         unsigned char vec_nr;
   93         unsigned char privilege;
   94   }
   95   gate_table[] = {
   96         { divide_error, DIVIDE_VECTOR, INTR_PRIVILEGE },
   97         { single_step_exception, DEBUG_VECTOR, INTR_PRIVILEGE },
   98         { nmi, NMI_VECTOR, INTR_PRIVILEGE },
   99         { breakpoint_exception, BREAKPOINT_VECTOR, USER_PRIVILEGE },
  100         { overflow, OVERFLOW_VECTOR, USER_PRIVILEGE },
  101         { bounds_check, BOUNDS_VECTOR, INTR_PRIVILEGE },
  102         { inval_opcode, INVAL_OP_VECTOR, INTR_PRIVILEGE },
  103         { copr_not_available, COPROC_NOT_VECTOR, INTR_PRIVILEGE },
  104         { double_fault, DOUBLE_FAULT_VECTOR, INTR_PRIVILEGE },
  105         { copr_seg_overrun, COPROC_SEG_VECTOR, INTR_PRIVILEGE },
  106         { inval_tss, INVAL_TSS_VECTOR, INTR_PRIVILEGE },
  107         { segment_not_present, SEG_NOT_VECTOR, INTR_PRIVILEGE },
  108         { stack_exception, STACK_FAULT_VECTOR, INTR_PRIVILEGE },
  109         { general_protection, PROTECTION_VECTOR, INTR_PRIVILEGE },
  110 #if _WORD_SIZE == 4
  111         { page_fault, PAGE_FAULT_VECTOR, INTR_PRIVILEGE },
  112         { copr_error, COPROC_ERR_VECTOR, INTR_PRIVILEGE },
  113 #endif
  114         { hwint00, VECTOR( 0), INTR_PRIVILEGE },
  115         { hwint01, VECTOR( 1), INTR_PRIVILEGE },
  116         { hwint02, VECTOR( 2), INTR_PRIVILEGE },
  117         { hwint03, VECTOR( 3), INTR_PRIVILEGE },
  118         { hwint04, VECTOR( 4), INTR_PRIVILEGE },
  119         { hwint05, VECTOR( 5), INTR_PRIVILEGE },
  120         { hwint06, VECTOR( 6), INTR_PRIVILEGE },
  121         { hwint07, VECTOR( 7), INTR_PRIVILEGE },
  122         { hwint08, VECTOR( 8), INTR_PRIVILEGE },
  123         { hwint09, VECTOR( 9), INTR_PRIVILEGE },
  124         { hwint10, VECTOR(10), INTR_PRIVILEGE },
  125         { hwint11, VECTOR(11), INTR_PRIVILEGE },
  126         { hwint12, VECTOR(12), INTR_PRIVILEGE },
  127         { hwint13, VECTOR(13), INTR_PRIVILEGE },
  128         { hwint14, VECTOR(14), INTR_PRIVILEGE },
  129         { hwint15, VECTOR(15), INTR_PRIVILEGE },
  130 #if _WORD_SIZE == 2
  131         { p_s_call, SYS_VECTOR, USER_PRIVILEGE },       /* 286 system call */
  132 #else
  133         { s_call, SYS386_VECTOR, USER_PRIVILEGE },      /* 386 system call */
  134 #endif
  135         { level0_call, LEVEL0_VECTOR, TASK_PRIVILEGE },
  136   };
  137 
  138   /* Build gdt and idt pointers in GDT where the BIOS expects them. */
  139   dtp= (struct desctableptr_s *) &gdt[GDT_INDEX];
  140   * (u16_t *) dtp->limit = (sizeof gdt) - 1;
  141   * (u32_t *) dtp->base = vir2phys(gdt);
  142 
  143   dtp= (struct desctableptr_s *) &gdt[IDT_INDEX];
  144   * (u16_t *) dtp->limit = (sizeof idt) - 1;
  145   * (u32_t *) dtp->base = vir2phys(idt);
  146 
  147   /* Build segment descriptors for tasks and interrupt handlers. */
  148   init_codeseg(&gdt[CS_INDEX],
  149          kinfo.code_base, kinfo.code_size, INTR_PRIVILEGE);
  150   init_dataseg(&gdt[DS_INDEX],
  151          kinfo.data_base, kinfo.data_size, INTR_PRIVILEGE);
  152   init_dataseg(&gdt[ES_INDEX], 0L, 0, TASK_PRIVILEGE);
  153 
  154   /* Build scratch descriptors for functions in klib88. */
  155   init_dataseg(&gdt[DS_286_INDEX], 0L, 0, TASK_PRIVILEGE);
  156   init_dataseg(&gdt[ES_286_INDEX], 0L, 0, TASK_PRIVILEGE);
  157 
  158   /* Build local descriptors in GDT for LDT's in process table.
  159    * The LDT's are allocated at compile time in the process table, and
  160    * initialized whenever a process' map is initialized or changed.
  161    */
  162   for (rp = BEG_PROC_ADDR, ldt_index = FIRST_LDT_INDEX;
  163        rp < END_PROC_ADDR; ++rp, ldt_index++) {
  164         init_dataseg(&gdt[ldt_index], vir2phys(rp->p_ldt),
  165                                      sizeof(rp->p_ldt), INTR_PRIVILEGE);
  166         gdt[ldt_index].access = PRESENT | LDT;
  167         rp->p_ldt_sel = ldt_index * DESC_SIZE;
  168   }
  169 
  170   /* Build main TSS.
  171    * This is used only to record the stack pointer to be used after an
  172    * interrupt.
  173    * The pointer is set up so that an interrupt automatically saves the
  174    * current process's registers ip:cs:f:sp:ss in the correct slots in the
  175    * process table.
  176    */
  177   tss.ss0 = DS_SELECTOR;
  178   init_dataseg(&gdt[TSS_INDEX], vir2phys(&tss), sizeof(tss), INTR_PRIVILEGE);
  179   gdt[TSS_INDEX].access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE;
  180 
  181   /* Build descriptors for interrupt gates in IDT. */
  182   for (gtp = &gate_table[0];
  183        gtp < &gate_table[sizeof gate_table / sizeof gate_table[0]]; ++gtp) {
  184         int_gate(gtp->vec_nr, (vir_bytes) gtp->gate,
  185                  PRESENT | INT_GATE_TYPE | (gtp->privilege << DPL_SHIFT));
  186   }
  187 
  188 #if _WORD_SIZE == 4
  189   /* Complete building of main TSS. */
  190   tss.iobase = sizeof tss;      /* empty i/o permissions map */
  191 #endif
  192 }
  193 
  194 /*===========================================================================*
  195  *                              init_codeseg                                 *
  196  *===========================================================================*/
  197 PUBLIC void init_codeseg(segdp, base, size, privilege)
  198 register struct segdesc_s *segdp;
  199 phys_bytes base;
  200 vir_bytes size;
  201 int privilege;
  202 {
  203 /* Build descriptor for a code segment. */
  204   sdesc(segdp, base, size);
  205   segdp->access = (privilege << DPL_SHIFT)
  206                 | (PRESENT | SEGMENT | EXECUTABLE | READABLE);
  207                 /* CONFORMING = 0, ACCESSED = 0 */
  208 }
  209 
  210 /*===========================================================================*
  211  *                              init_dataseg                                 *
  212  *===========================================================================*/
  213 PUBLIC void init_dataseg(segdp, base, size, privilege)
  214 register struct segdesc_s *segdp;
  215 phys_bytes base;
  216 vir_bytes size;
  217 int privilege;
  218 {
  219 /* Build descriptor for a data segment. */
  220   sdesc(segdp, base, size);
  221   segdp->access = (privilege << DPL_SHIFT) | (PRESENT | SEGMENT | WRITEABLE);
  222                 /* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */
  223 }
  224 
  225 /*===========================================================================*
  226  *                              sdesc                                        *
  227  *===========================================================================*/
  228 PRIVATE void sdesc(segdp, base, size)
  229 register struct segdesc_s *segdp;
  230 phys_bytes base;
  231 vir_bytes size;
  232 {
  233 /* Fill in the size fields (base, limit and granularity) of a descriptor. */
  234   segdp->base_low = base;
  235   segdp->base_middle = base >> BASE_MIDDLE_SHIFT;
  236   segdp->base_high = base >> BASE_HIGH_SHIFT;
  237 
  238 #if _WORD_SIZE == 4
  239   --size;                       /* convert to a limit, 0 size means 4G */
  240   if (size > BYTE_GRAN_MAX) {
  241         segdp->limit_low = size >> PAGE_GRAN_SHIFT;
  242         segdp->granularity = GRANULAR | (size >>
  243                                      (PAGE_GRAN_SHIFT + GRANULARITY_SHIFT));
  244   } else {
  245         segdp->limit_low = size;
  246         segdp->granularity = size >> GRANULARITY_SHIFT;
  247   }
  248   segdp->granularity |= DEFAULT;        /* means BIG for data seg */
  249 #else
  250   segdp->limit_low = size - 1;
  251 #endif
  252 }
  253 
  254 /*===========================================================================*
  255  *                              seg2phys                                     *
  256  *===========================================================================*/
  257 PUBLIC phys_bytes seg2phys(seg)
  258 U16_t seg;
  259 {
  260 /* Return the base address of a segment, with seg being either a 8086 segment
  261  * register, or a 286/386 segment selector.
  262  */
  263   phys_bytes base;
  264   struct segdesc_s *segdp;
  265 
  266   if (! machine.protected) {
  267         base = hclick_to_physb(seg);
  268   } else {
  269         segdp = &gdt[seg >> 3];
  270         base =    ((u32_t) segdp->base_low << 0)
  271                 | ((u32_t) segdp->base_middle << 16)
  272                 | ((u32_t) segdp->base_high << 24);
  273   }
  274   return base;
  275 }
  276 
  277 /*===========================================================================*
  278  *                              phys2seg                                     *
  279  *===========================================================================*/
  280 PUBLIC void phys2seg(seg, off, phys)
  281 u16_t *seg;
  282 vir_bytes *off;
  283 phys_bytes phys;
  284 {
  285 /* Return a segment selector and offset that can be used to reach a physical
  286  * address, for use by a driver doing memory I/O in the A0000 - DFFFF range.
  287  */
  288 #if _WORD_SIZE == 2
  289   if (! machine.protected) {
  290         *seg = phys / HCLICK_SIZE;
  291         *off = phys % HCLICK_SIZE;
  292   } else {
  293         unsigned bank = phys >> 16;
  294         unsigned index = bank - 0xA + A_INDEX;
  295         init_dataseg(&gdt[index], (phys_bytes) bank << 16, 0, TASK_PRIVILEGE);
  296         *seg = (index * 0x08) | TASK_PRIVILEGE;
  297         *off = phys & 0xFFFF;
  298   }
  299 #else
  300   *seg = FLAT_DS_SELECTOR;
  301   *off = phys;
  302 #endif
  303 }
  304 
  305 /*===========================================================================*
  306  *                              int_gate                                     *
  307  *===========================================================================*/
  308 PRIVATE void int_gate(vec_nr, offset, dpl_type)
  309 unsigned vec_nr;
  310 vir_bytes offset;
  311 unsigned dpl_type;
  312 {
  313 /* Build descriptor for an interrupt gate. */
  314   register struct gatedesc_s *idp;
  315 
  316   idp = &idt[vec_nr];
  317   idp->offset_low = offset;
  318   idp->selector = CS_SELECTOR;
  319   idp->p_dpl_type = dpl_type;
  320 #if _WORD_SIZE == 4
  321   idp->offset_high = offset >> OFFSET_HIGH_SHIFT;
  322 #endif
  323 }
  324 
  325 /*===========================================================================*
  326  *                              enable_iop                                   * 
  327  *===========================================================================*/
  328 PUBLIC void enable_iop(pp)
  329 struct proc *pp;
  330 {
  331 /* Allow a user process to use I/O instructions.  Change the I/O Permission
  332  * Level bits in the psw. These specify least-privileged Current Permission
  333  * Level allowed to execute I/O instructions. Users and servers have CPL 3. 
  334  * You can't have less privilege than that. Kernel has CPL 0, tasks CPL 1.
  335  */
  336   pp->p_reg.psw |= 0x3000;
  337 }
  338 
  339 /*===========================================================================*
  340  *                              alloc_segments                               *
  341  *===========================================================================*/
  342 PUBLIC void alloc_segments(rp)
  343 register struct proc *rp;
  344 {
  345 /* This is called at system initialization from main() and by do_newmap(). 
  346  * The code has a separate function because of all hardware-dependencies.
  347  * Note that IDLE is part of the kernel and gets TASK_PRIVILEGE here.
  348  */
  349   phys_bytes code_bytes;
  350   phys_bytes data_bytes;
  351   int privilege;
  352 
  353   if (machine.protected) {
  354       data_bytes = (phys_bytes) (rp->p_memmap[S].mem_vir + 
  355           rp->p_memmap[S].mem_len) << CLICK_SHIFT;
  356       if (rp->p_memmap[T].mem_len == 0)
  357           code_bytes = data_bytes;      /* common I&D, poor protect */
  358       else
  359           code_bytes = (phys_bytes) rp->p_memmap[T].mem_len << CLICK_SHIFT;
  360       privilege = (iskernelp(rp)) ? TASK_PRIVILEGE : USER_PRIVILEGE;
  361       init_codeseg(&rp->p_ldt[CS_LDT_INDEX],
  362           (phys_bytes) rp->p_memmap[T].mem_phys << CLICK_SHIFT,
  363           code_bytes, privilege);
  364       init_dataseg(&rp->p_ldt[DS_LDT_INDEX],
  365           (phys_bytes) rp->p_memmap[D].mem_phys << CLICK_SHIFT,
  366           data_bytes, privilege);
  367       rp->p_reg.cs = (CS_LDT_INDEX * DESC_SIZE) | TI | privilege;
  368 #if _WORD_SIZE == 4
  369       rp->p_reg.gs =
  370       rp->p_reg.fs =
  371 #endif
  372       rp->p_reg.ss =
  373       rp->p_reg.es =
  374       rp->p_reg.ds = (DS_LDT_INDEX*DESC_SIZE) | TI | privilege;
  375   } else {
  376       rp->p_reg.cs = click_to_hclick(rp->p_memmap[T].mem_phys);
  377       rp->p_reg.ss =
  378       rp->p_reg.es =
  379       rp->p_reg.ds = click_to_hclick(rp->p_memmap[D].mem_phys);
  380   }
  381 }
  382 

Cache object: 8b07b6bef88df05e09f1962775687541


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.