2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
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.
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.
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/>.
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)
33 #define BIT_BUSY (1 << 9)
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)
40 enum {TYPE_DATA, TYPE_CODE};
42 /* we need the following bit pattern at the 8th bit excluding the busy bit: 1001 */
43 #define TSS_TYPE_BITS (9 << 8)
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);
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);
55 /* our global descriptor table */
56 static desc_t gdt[NUM_SEGMENTS] __attribute__((aligned(8)));
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);
68 set_gdt((uint32_t)gdt, sizeof gdt - 1);
70 setup_selectors(selector(SEGM_KCODE, 0), selector(SEGM_KDATA, 0));
73 /* constructs a GDT selector based on index and priviledge level */
74 uint16_t selector(int idx, int rpl)
76 return (idx << 3) | (rpl & 3);
79 void set_tss(uint32_t addr)
81 task_desc(gdt + SEGM_TASK, addr, sizeof(struct task_state) - 1, 3);
82 set_task_reg(selector(SEGM_TASK, 0));
85 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
87 desc->d[0] = limit & 0xffff; /* low order 16bits of limit */
88 desc->d[1] = base & 0xffff; /* low order 16bits of base */
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
94 desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
95 BIT_NOSYS | (type == TYPE_DATA ? BIT_WR : (BIT_RD | BIT_CODE));
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.
100 desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN | BIT_BIG;
103 static void segm_desc16(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
105 desc->d[0] = limit & 0xffff; /* low order 16bits of limit */
106 desc->d[1] = base & 0xffff; /* low order 16bits of base */
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
112 desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
113 BIT_NOSYS | (type == TYPE_DATA ? BIT_WR : (BIT_RD | BIT_CODE));
115 /* 16bit descriptors have the upper word 0 */
119 static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl)
121 desc->d[0] = limit & 0xffff;
122 desc->d[1] = base & 0xffff;
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;
129 static void dbg_print_gdt(void)
133 printf("Global Descriptor Table\n");
134 printf("-----------------------\n");
141 static void print_desc(desc_t *desc)
143 uint32_t base, limit;
144 int dpl, g, db, l, avl, p, s, type;
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;
156 p = (desc->d[2] >> 15) & 1;
157 s = (desc->d[2] >> 12) & 1;