added copyright headers to new files
[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 task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl);
47
48 /* these functions are implemented in segm-asm.S */
49 void setup_selectors(uint16_t code, uint16_t data);
50 void set_gdt(uint32_t addr, uint16_t limit);
51 void set_task_reg(uint16_t tss_selector);
52
53
54 /* our global descriptor table */
55 static desc_t gdt[6] __attribute__((aligned(8)));
56
57
58 void init_segm(void)
59 {
60         memset(gdt, 0, sizeof gdt);
61         segm_desc(gdt + SEGM_KCODE, 0, 0xffffffff, 0, TYPE_CODE);
62         segm_desc(gdt + SEGM_KDATA, 0, 0xffffffff, 0, TYPE_DATA);
63         segm_desc(gdt + SEGM_UCODE, 0, 0xffffffff, 3, TYPE_CODE);
64         segm_desc(gdt + SEGM_UDATA, 0, 0xffffffff, 3, TYPE_DATA);
65
66         set_gdt((uint32_t)gdt, sizeof gdt - 1);
67
68         setup_selectors(selector(SEGM_KCODE, 0), selector(SEGM_KDATA, 0));
69 }
70
71 /* constructs a GDT selector based on index and priviledge level */
72 uint16_t selector(int idx, int rpl)
73 {
74         return (idx << 3) | (rpl & 3);
75 }
76
77 void set_tss(uint32_t addr)
78 {
79         task_desc(gdt + SEGM_TASK, addr, sizeof(struct task_state) - 1, 3);
80         set_task_reg(selector(SEGM_TASK, 0));
81 }
82
83 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
84 {
85         desc->d[0] = limit & 0xffff; /* low order 16bits of limit */
86         desc->d[1] = base & 0xffff;  /* low order 16bits of base */
87
88         /* third 16bit part contains the last 8 bits of base, the 2 priviledge
89          * level bits starting on bit 13, present flag on bit 15, and type bits
90          * starting from bit 8
91          */
92         desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
93                 BIT_NOSYS | (type == TYPE_DATA ? BIT_WR : (BIT_RD | BIT_CODE));
94
95         /* last 16bit part contains the last nibble of limit, the last byte of
96          * base, and the granularity and deafult/big flags in bits 23 and 22 resp.
97          */
98         desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN | BIT_BIG;
99 }
100
101 static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl)
102 {
103         desc->d[0] = limit & 0xffff;
104         desc->d[1] = base & 0xffff;
105
106         desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
107                 TSS_TYPE_BITS; /* XXX busy ? */
108         desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN;
109 }
110 /*
111 static void dbg_print_gdt(void)
112 {
113         int i;
114
115         printf("Global Descriptor Table\n");
116         printf("-----------------------\n");
117
118         for(i=0; i<6; i++) {
119                 print_desc(gdt + i);
120         }
121 }
122
123 static void print_desc(desc_t *desc)
124 {
125         uint32_t base, limit;
126         int dpl, g, db, l, avl, p, s, type;
127         char *type_str;
128
129         base = (uint32_t)desc->d[1] | ((uint32_t)(desc->d[2] & 0xff) << 16) | ((uint32_t)(desc->d[3] >> 8) << 24);
130         limit = (uint32_t)desc->d[0] | ((uint32_t)(desc->d[3] & 0xf) << 16);
131         dpl = (desc->d[2] >> 13) & 3;
132         type = (desc->d[2] >> 8) & 0xf;
133         g = (desc->d[3] >> 23) & 1;
134         db = (desc->d[3] >> 22) & 1;
135         l = (desc->d[3] >> 21) & 1;
136         avl = (desc->d[3] >> 20) & 1;
137
138         p = (desc->d[2] >> 15) & 1;
139         s = (desc->d[2] >> 12) & 1;
140 }
141 */