reorganize source
[com32] / src / kern / 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 <stdio.h>
19 #include <string.h>
20 #include "segm.h"
21 #include "desc.h"
22 #include "tss.h"
23
24 /* bits for the 3rd 16bt part of the descriptor */
25 #define BIT_ACCESSED    (1 << 8)
26 #define BIT_WR                  (1 << 9)
27 #define BIT_RD                  (1 << 9)
28 #define BIT_EXP_DOWN    (1 << 10)
29 #define BIT_CONFORMING  (1 << 10)
30 #define BIT_CODE                (1 << 11)
31 #define BIT_NOSYS               (1 << 12)
32 #define BIT_PRESENT             (1 << 15)
33 /* TSS busy bit */
34 #define BIT_BUSY                (1 << 9)
35
36 /* bits for the last 16bit part of the descriptor */
37 #define BIT_BIG                 (1 << 6)
38 #define BIT_DEFAULT             (1 << 6)
39 #define BIT_GRAN                (1 << 7)
40
41 enum {TYPE_DATA, TYPE_CODE};
42
43 /* we need the following bit pattern at the 8th bit excluding the busy bit: 1001 */
44 #define TSS_TYPE_BITS   (9 << 8)
45
46 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type);
47 static void segm_desc16(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type);
48 /*static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl);*/
49
50 /* these functions are implemented in segm-asm.S */
51 void setup_selectors(uint16_t code, uint16_t data);
52 void set_gdt(uint32_t addr, uint16_t limit);
53 void set_task_reg(uint16_t tss_selector);
54
55 /*
56 static void dbg_print_gdt(void);
57 static void print_desc(desc_t *desc);
58 */
59
60 /* our global descriptor table */
61 static desc_t gdt[NUM_SEGMENTS] __attribute__((aligned(8)));
62 uint16_t orig_seg;
63
64 void init_segm(void)
65 {
66         asm volatile (
67                 "mov %%fs, %0\n\t"
68                 : "=a"(orig_seg));
69
70         memset(gdt, 0, sizeof gdt);
71         segm_desc(gdt + SEGM_CODE, 0, 0xffffffff, 0, TYPE_CODE);
72         segm_desc(gdt + SEGM_DATA, 0, 0xffffffff, 0, TYPE_DATA);
73         segm_desc(gdt + SEGM_XCODE, orig_seg << 4, 0xffffffff, 0, TYPE_CODE);
74         segm_desc(gdt + SEGM_XDATA, orig_seg << 4, 0xffffffff, 0, TYPE_DATA);
75         segm_desc16(gdt + SEGM_CODE16, orig_seg << 4, 0xffff, 0, TYPE_CODE);
76
77         set_gdt((uint32_t)gdt, sizeof gdt - 1);
78
79         setup_selectors(selector(SEGM_CODE, 0), selector(SEGM_DATA, 0));
80 }
81
82 /* constructs a GDT selector based on index and priviledge level */
83 uint16_t selector(int idx, int rpl)
84 {
85         return (idx << 3) | (rpl & 3);
86 }
87
88 /*
89 void set_tss(uint32_t addr)
90 {
91         task_desc(gdt + SEGM_TASK, addr, sizeof(struct task_state) - 1, 3);
92         set_task_reg(selector(SEGM_TASK, 0));
93 }
94 */
95
96 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
97 {
98         desc->d[0] = limit & 0xffff; /* low order 16bits of limit */
99         desc->d[1] = base & 0xffff;  /* low order 16bits of base */
100
101         /* third 16bit part contains the last 8 bits of base, the 2 priviledge
102          * level bits starting on bit 13, present flag on bit 15, and type bits
103          * starting from bit 8
104          */
105         desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
106                 BIT_NOSYS | (type == TYPE_DATA ? BIT_WR : (BIT_RD | BIT_CODE));
107
108         /* last 16bit part contains the last nibble of limit, the last byte of
109          * base, and the granularity and deafult/big flags in bits 23 and 22 resp.
110          */
111         desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN | BIT_BIG;
112 }
113
114 static void segm_desc16(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
115 {
116         desc->d[0] = limit & 0xffff; /* low order 16bits of limit */
117         desc->d[1] = base & 0xffff;  /* low order 16bits of base */
118
119         /* third 16bit part contains the last 8 bits of base, the 2 priviledge
120          * level bits starting on bit 13, present flag on bit 15, and type bits
121          * starting from bit 8
122          */
123         desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
124                 BIT_NOSYS | (type == TYPE_DATA ? BIT_WR : (BIT_RD | BIT_CODE));
125
126         /* 16bit descriptors have the upper word 0 */
127         desc->d[3] = 0;
128 }
129
130 #if 0
131 static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl)
132 {
133         desc->d[0] = limit & 0xffff;
134         desc->d[1] = base & 0xffff;
135
136         desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
137                 TSS_TYPE_BITS; /* XXX busy ? */
138         desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN;
139 }
140
141 static void dbg_print_gdt(void)
142 {
143         int i;
144
145         printf("Global Descriptor Table\n");
146         printf("-----------------------\n");
147
148         for(i=0; i<NUM_SEGMENTS; i++) {
149                 printf("%d: ", i);
150                 print_desc(gdt + i);
151         }
152 }
153
154 static void print_desc(desc_t *desc)
155 {
156         uint32_t base, limit;
157         int dpl, g;
158
159         if((desc->d[0] | desc->d[1] | desc->d[2] | desc->d[3]) == 0) {
160                 printf("null\n");
161         }
162
163         base = (uint32_t)desc->d[1] | ((uint32_t)(desc->d[2] & 0xff) << 16) | ((uint32_t)(desc->d[3] >> 8) << 24);
164         limit = (uint32_t)desc->d[0] | ((uint32_t)(desc->d[3] & 0xf) << 16);
165         dpl = (desc->d[2] >> 13) & 3;
166         g = (desc->d[3] >> 7) & 1;
167
168         if(g) limit = ((limit + 1) << 12) - 1;
169
170         printf("base:%x lim:%x dpl:%d type:%s %dbit\n", base, limit, dpl,
171                         desc->d[2] & BIT_CODE ? "code" : "data", desc->d[3] & BIT_BIG ? 32 : 16);
172 }
173 #endif