interrupts, timer, keyboard, segments, lots of kernel code
[bootcensus] / src / segm.c
1 #include <string.h>
2 #include "segm.h"
3 #include "desc.h"
4 #include "tss.h"
5
6 /* bits for the 3rd 16bt part of the descriptor */
7 #define BIT_ACCESSED    (1 << 8)
8 #define BIT_WR                  (1 << 9)
9 #define BIT_RD                  (1 << 9)
10 #define BIT_EXP_DOWN    (1 << 10)
11 #define BIT_CONFORMING  (1 << 10)
12 #define BIT_CODE                (1 << 11)
13 #define BIT_NOSYS               (1 << 12)
14 #define BIT_PRESENT             (1 << 15)
15 /* TSS busy bit */
16 #define BIT_BUSY                (1 << 9)
17
18 /* bits for the last 16bit part of the descriptor */
19 #define BIT_BIG                 (1 << 6)
20 #define BIT_DEFAULT             (1 << 6)
21 #define BIT_GRAN                (1 << 7)
22
23 enum {TYPE_DATA, TYPE_CODE};
24
25 /* we need the following bit pattern at the 8th bit excluding the busy bit: 1001 */
26 #define TSS_TYPE_BITS   (9 << 8)
27
28 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type);
29 static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl);
30
31 /* these functions are implemented in segm-asm.S */
32 void setup_selectors(uint16_t code, uint16_t data);
33 void set_gdt(uint32_t addr, uint16_t limit);
34 void set_task_reg(uint16_t tss_selector);
35
36
37 /* our global descriptor table */
38 static desc_t gdt[6] __attribute__((aligned(8)));
39
40
41 void init_segm(void)
42 {
43         memset(gdt, 0, sizeof gdt);
44         segm_desc(gdt + SEGM_KCODE, 0, 0xffffffff, 0, TYPE_CODE);
45         segm_desc(gdt + SEGM_KDATA, 0, 0xffffffff, 0, TYPE_DATA);
46         segm_desc(gdt + SEGM_UCODE, 0, 0xffffffff, 3, TYPE_CODE);
47         segm_desc(gdt + SEGM_UDATA, 0, 0xffffffff, 3, TYPE_DATA);
48
49         set_gdt((uint32_t)gdt, sizeof gdt - 1);
50
51         setup_selectors(selector(SEGM_KCODE, 0), selector(SEGM_KDATA, 0));
52 }
53
54 /* constructs a GDT selector based on index and priviledge level */
55 uint16_t selector(int idx, int rpl)
56 {
57         return (idx << 3) | (rpl & 3);
58 }
59
60 void set_tss(uint32_t addr)
61 {
62         task_desc(gdt + SEGM_TASK, addr, sizeof(struct task_state) - 1, 3);
63         set_task_reg(selector(SEGM_TASK, 0));
64 }
65
66 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
67 {
68         desc->d[0] = limit & 0xffff; /* low order 16bits of limit */
69         desc->d[1] = base & 0xffff;  /* low order 16bits of base */
70
71         /* third 16bit part contains the last 8 bits of base, the 2 priviledge
72          * level bits starting on bit 13, present flag on bit 15, and type bits
73          * starting from bit 8
74          */
75         desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
76                 BIT_NOSYS | (type == TYPE_DATA ? BIT_WR : (BIT_RD | BIT_CODE));
77
78         /* last 16bit part contains the last nibble of limit, the last byte of
79          * base, and the granularity and deafult/big flags in bits 23 and 22 resp.
80          */
81         desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN | BIT_BIG;
82 }
83
84 static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl)
85 {
86         desc->d[0] = limit & 0xffff;
87         desc->d[1] = base & 0xffff;
88
89         desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
90                 TSS_TYPE_BITS; /* XXX busy ? */
91         desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN;
92 }
93 /*
94 static void dbg_print_gdt(void)
95 {
96         int i;
97
98         printf("Global Descriptor Table\n");
99         printf("-----------------------\n");
100
101         for(i=0; i<6; i++) {
102                 print_desc(gdt + i);
103         }
104 }
105
106 static void print_desc(desc_t *desc)
107 {
108         uint32_t base, limit;
109         int dpl, g, db, l, avl, p, s, type;
110         char *type_str;
111
112         base = (uint32_t)desc->d[1] | ((uint32_t)(desc->d[2] & 0xff) << 16) | ((uint32_t)(desc->d[3] >> 8) << 24);
113         limit = (uint32_t)desc->d[0] | ((uint32_t)(desc->d[3] & 0xf) << 16);
114         dpl = (desc->d[2] >> 13) & 3;
115         type = (desc->d[2] >> 8) & 0xf;
116         g = (desc->d[3] >> 23) & 1;
117         db = (desc->d[3] >> 22) & 1;
118         l = (desc->d[3] >> 21) & 1;
119         avl = (desc->d[3] >> 20) & 1;
120
121         p = (desc->d[2] >> 15) & 1;
122         s = (desc->d[2] >> 12) & 1;
123 }
124 */