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/>.
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)
34 #define BIT_BUSY (1 << 9)
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)
41 enum {TYPE_DATA, TYPE_CODE};
43 /* we need the following bit pattern at the 8th bit excluding the busy bit: 1001 */
44 #define TSS_TYPE_BITS (9 << 8)
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);*/
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);
56 static void dbg_print_gdt(void);
57 static void print_desc(desc_t *desc);
60 /* our global descriptor table */
61 static desc_t gdt[NUM_SEGMENTS] __attribute__((aligned(8)));
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);
77 set_gdt((uint32_t)gdt, sizeof gdt - 1);
79 setup_selectors(selector(SEGM_CODE, 0), selector(SEGM_DATA, 0));
82 /* constructs a GDT selector based on index and priviledge level */
83 uint16_t selector(int idx, int rpl)
85 return (idx << 3) | (rpl & 3);
89 void set_tss(uint32_t addr)
91 task_desc(gdt + SEGM_TASK, addr, sizeof(struct task_state) - 1, 3);
92 set_task_reg(selector(SEGM_TASK, 0));
96 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
98 desc->d[0] = limit & 0xffff; /* low order 16bits of limit */
99 desc->d[1] = base & 0xffff; /* low order 16bits of base */
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
105 desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
106 BIT_NOSYS | (type == TYPE_DATA ? BIT_WR : (BIT_RD | BIT_CODE));
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.
111 desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN | BIT_BIG;
114 static void segm_desc16(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
116 desc->d[0] = limit & 0xffff; /* low order 16bits of limit */
117 desc->d[1] = base & 0xffff; /* low order 16bits of base */
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
123 desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
124 BIT_NOSYS | (type == TYPE_DATA ? BIT_WR : (BIT_RD | BIT_CODE));
126 /* 16bit descriptors have the upper word 0 */
131 static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl)
133 desc->d[0] = limit & 0xffff;
134 desc->d[1] = base & 0xffff;
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;
141 static void dbg_print_gdt(void)
145 printf("Global Descriptor Table\n");
146 printf("-----------------------\n");
148 for(i=0; i<NUM_SEGMENTS; i++) {
154 static void print_desc(desc_t *desc)
156 uint32_t base, limit;
159 if((desc->d[0] | desc->d[1] | desc->d[2] | desc->d[3]) == 0) {
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;
168 if(g) limit = ((limit + 1) << 12) - 1;
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);