census logo
[bootcensus] / src / segm.c
1 /*
2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY, without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 #include <string.h>
19 #include "segm.h"
20 #include "desc.h"
21 #include "tss.h"
22
23 /* bits for the 3rd 16bt part of the descriptor */
24 #define BIT_ACCESSED    (1 << 8)
25 #define BIT_WR                  (1 << 9)
26 #define BIT_RD                  (1 << 9)
27 #define BIT_EXP_DOWN    (1 << 10)
28 #define BIT_CONFORMING  (1 << 10)
29 #define BIT_CODE                (1 << 11)
30 #define BIT_NOSYS               (1 << 12)
31 #define BIT_PRESENT             (1 << 15)
32 /* TSS busy bit */
33 #define BIT_BUSY                (1 << 9)
34
35 /* bits for the last 16bit part of the descriptor */
36 #define BIT_BIG                 (1 << 6)
37 #define BIT_DEFAULT             (1 << 6)
38 #define BIT_GRAN                (1 << 7)
39
40 enum {TYPE_DATA, TYPE_CODE};
41
42 /* we need the following bit pattern at the 8th bit excluding the busy bit: 1001 */
43 #define TSS_TYPE_BITS   (9 << 8)
44
45 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type);
46 static void segm_desc16(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type);
47 static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl);
48
49 /* these functions are implemented in segm-asm.S */
50 void setup_selectors(uint16_t code, uint16_t data);
51 void set_gdt(uint32_t addr, uint16_t limit);
52 void set_task_reg(uint16_t tss_selector);
53
54
55 /* our global descriptor table */
56 static desc_t gdt[NUM_SEGMENTS] __attribute__((aligned(8)));
57
58
59 void init_segm(void)
60 {
61         memset(gdt, 0, sizeof gdt);
62         segm_desc(gdt + SEGM_KCODE, 0, 0xffffffff, 0, TYPE_CODE);
63         segm_desc(gdt + SEGM_KDATA, 0, 0xffffffff, 0, TYPE_DATA);
64         segm_desc(gdt + SEGM_UCODE, 0, 0xffffffff, 3, TYPE_CODE);
65         segm_desc(gdt + SEGM_UDATA, 0, 0xffffffff, 3, TYPE_DATA);
66         segm_desc16(gdt + SEGM_CODE16, 0, 0xffff, 0, TYPE_CODE);
67
68         set_gdt((uint32_t)gdt, sizeof gdt - 1);
69
70         setup_selectors(selector(SEGM_KCODE, 0), selector(SEGM_KDATA, 0));
71 }
72
73 /* constructs a GDT selector based on index and priviledge level */
74 uint16_t selector(int idx, int rpl)
75 {
76         return (idx << 3) | (rpl & 3);
77 }
78
79 void set_tss(uint32_t addr)
80 {
81         task_desc(gdt + SEGM_TASK, addr, sizeof(struct task_state) - 1, 3);
82         set_task_reg(selector(SEGM_TASK, 0));
83 }
84
85 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
86 {
87         desc->d[0] = limit & 0xffff; /* low order 16bits of limit */
88         desc->d[1] = base & 0xffff;  /* low order 16bits of base */
89
90         /* third 16bit part contains the last 8 bits of base, the 2 priviledge
91          * level bits starting on bit 13, present flag on bit 15, and type bits
92          * starting from bit 8
93          */
94         desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
95                 BIT_NOSYS | (type == TYPE_DATA ? BIT_WR : (BIT_RD | BIT_CODE));
96
97         /* last 16bit part contains the last nibble of limit, the last byte of
98          * base, and the granularity and deafult/big flags in bits 23 and 22 resp.
99          */
100         desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN | BIT_BIG;
101 }
102
103 static void segm_desc16(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
104 {
105         desc->d[0] = limit & 0xffff; /* low order 16bits of limit */
106         desc->d[1] = base & 0xffff;  /* low order 16bits of base */
107
108         /* third 16bit part contains the last 8 bits of base, the 2 priviledge
109          * level bits starting on bit 13, present flag on bit 15, and type bits
110          * starting from bit 8
111          */
112         desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
113                 BIT_NOSYS | (type == TYPE_DATA ? BIT_WR : (BIT_RD | BIT_CODE));
114
115         /* 16bit descriptors have the upper word 0 */
116         desc->d[3] = 0;
117 }
118
119 static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl)
120 {
121         desc->d[0] = limit & 0xffff;
122         desc->d[1] = base & 0xffff;
123
124         desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
125                 TSS_TYPE_BITS; /* XXX busy ? */
126         desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN;
127 }
128 /*
129 static void dbg_print_gdt(void)
130 {
131         int i;
132
133         printf("Global Descriptor Table\n");
134         printf("-----------------------\n");
135
136         for(i=0; i<6; i++) {
137                 print_desc(gdt + i);
138         }
139 }
140
141 static void print_desc(desc_t *desc)
142 {
143         uint32_t base, limit;
144         int dpl, g, db, l, avl, p, s, type;
145         char *type_str;
146
147         base = (uint32_t)desc->d[1] | ((uint32_t)(desc->d[2] & 0xff) << 16) | ((uint32_t)(desc->d[3] >> 8) << 24);
148         limit = (uint32_t)desc->d[0] | ((uint32_t)(desc->d[3] & 0xf) << 16);
149         dpl = (desc->d[2] >> 13) & 3;
150         type = (desc->d[2] >> 8) & 0xf;
151         g = (desc->d[3] >> 23) & 1;
152         db = (desc->d[3] >> 22) & 1;
153         l = (desc->d[3] >> 21) & 1;
154         avl = (desc->d[3] >> 20) & 1;
155
156         p = (desc->d[2] >> 15) & 1;
157         s = (desc->d[2] >> 12) & 1;
158 }
159 */