| 1 | /* | 
|---|
| 2 |  * hal_init.c - C initialization procedure for x86. | 
|---|
| 3 |  * | 
|---|
| 4 |  * Copyright (c) 2017 Maxime Villard | 
|---|
| 5 |  * | 
|---|
| 6 |  * This file is part of ALMOS-MKH. | 
|---|
| 7 |  * | 
|---|
| 8 |  * ALMOS-MKH is free software; you can redistribute it and/or modify it | 
|---|
| 9 |  * under the terms of the GNU General Public License as published by | 
|---|
| 10 |  * the Free Software Foundation; version 2.0 of the License. | 
|---|
| 11 |  * | 
|---|
| 12 |  * ALMOS-MKH is distributed in the hope that it will be useful, but | 
|---|
| 13 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 14 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
| 15 |  * General Public License for more details. | 
|---|
| 16 |  * | 
|---|
| 17 |  * You should have received a copy of the GNU General Public License | 
|---|
| 18 |  * along with ALMOS-MKH.; if not, write to the Free Software Foundation, | 
|---|
| 19 |  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 
|---|
| 20 |  */ | 
|---|
| 21 |  | 
|---|
| 22 | #include <hal_types.h> | 
|---|
| 23 | #include <hal_boot.h> | 
|---|
| 24 | #include <hal_multiboot.h> | 
|---|
| 25 | #include <hal_segmentation.h> | 
|---|
| 26 |  | 
|---|
| 27 | #include <memcpy.h> | 
|---|
| 28 | #include <thread.h> | 
|---|
| 29 | #include <string.h> | 
|---|
| 30 | #include <process.h> | 
|---|
| 31 | #include <printk.h> | 
|---|
| 32 | #include <vmm.h> | 
|---|
| 33 | #include <core.h> | 
|---|
| 34 | #include <cluster.h> | 
|---|
| 35 |  | 
|---|
| 36 | void x86_printf(char *s, ...); | 
|---|
| 37 |  | 
|---|
| 38 | static void gdt_create(); | 
|---|
| 39 | static void idt_create(); | 
|---|
| 40 | void cpu_attach(); | 
|---|
| 41 |  | 
|---|
| 42 |  | 
|---|
| 43 | struct multiboot_info mb_info __in_kdata; | 
|---|
| 44 | char mb_loader_name[PAGE_SIZE] __in_kdata; | 
|---|
| 45 | uint8_t mb_mmap[PAGE_SIZE] __in_kdata; | 
|---|
| 46 |  | 
|---|
| 47 | #define offsetof(type, member) __builtin_offsetof(type, member) | 
|---|
| 48 |  | 
|---|
| 49 |  | 
|---|
| 50 | /* -------------------------------------------------------------------------- */ | 
|---|
| 51 |  | 
|---|
| 52 | static void | 
|---|
| 53 | dump_memmap() | 
|---|
| 54 | { | 
|---|
| 55 |         size_t mmap_length = mb_info.mi_mmap_length; | 
|---|
| 56 |         uint8_t *mmap_addr = (uint8_t *)&mb_mmap; | 
|---|
| 57 |         size_t i; | 
|---|
| 58 |  | 
|---|
| 59 |         if (!(mb_info.mi_flags & MULTIBOOT_INFO_HAS_MMAP)) | 
|---|
| 60 |                 x86_printf("SHIT!!\n"); | 
|---|
| 61 |  | 
|---|
| 62 |         i = 0; | 
|---|
| 63 |         while (i < mmap_length) { | 
|---|
| 64 |                 struct multiboot_mmap *mm; | 
|---|
| 65 |  | 
|---|
| 66 |                 mm = (struct multiboot_mmap *)(mmap_addr + i); | 
|---|
| 67 |  | 
|---|
| 68 |                 x86_printf("-> [%Z, %Z] %s\n", mm->mm_base_addr, | 
|---|
| 69 |                     mm->mm_base_addr + mm->mm_length, | 
|---|
| 70 |                     (mm->mm_type == 1) ? "ram" : "rsv" ); | 
|---|
| 71 |  | 
|---|
| 72 |                 i += mm->mm_size + 4; | 
|---|
| 73 |         } | 
|---|
| 74 | } | 
|---|
| 75 |  | 
|---|
| 76 | void init_x86_64(paddr_t firstpa) | 
|---|
| 77 | { | 
|---|
| 78 |         x86_printf("[+] init_x86_64 called\n"); | 
|---|
| 79 |  | 
|---|
| 80 |         extern uint64_t __kernel_end; | 
|---|
| 81 |         x86_printf("__kernel_end: %Z\n", (uint64_t)&__kernel_end); | 
|---|
| 82 |  | 
|---|
| 83 |         /* Create the global structures */ | 
|---|
| 84 |         gdt_create(); | 
|---|
| 85 |         x86_printf("[+] gdt_create called\n"); | 
|---|
| 86 |  | 
|---|
| 87 |         idt_create(); | 
|---|
| 88 |         x86_printf("[+] idt_create called\n"); | 
|---|
| 89 |  | 
|---|
| 90 |         /* Attach cpu0 */ | 
|---|
| 91 |         cpu_attach(); | 
|---|
| 92 |         x86_printf("[+] cpu_attach called\n"); | 
|---|
| 93 |  | 
|---|
| 94 |         x86_printf("[+] bootloader: %s\n", mb_loader_name); | 
|---|
| 95 |  | 
|---|
| 96 |         dump_memmap(); | 
|---|
| 97 |  | 
|---|
| 98 |         x86_printf("[+] dump finished\n"); | 
|---|
| 99 |  | 
|---|
| 100 |         char *buf = NULL; | 
|---|
| 101 |         *buf = (char)0x01; | 
|---|
| 102 |  | 
|---|
| 103 |         int m = 0; | 
|---|
| 104 |         int v = 1 / m; | 
|---|
| 105 |  | 
|---|
| 106 |         x86_printf("ALIVE!\n"); | 
|---|
| 107 |  | 
|---|
| 108 |         while (1); | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 | /* -------------------------------------------------------------------------- */ | 
|---|
| 112 |  | 
|---|
| 113 | uint8_t gdtstore[PAGE_SIZE] __in_kdata; | 
|---|
| 114 | uint8_t idtstore[PAGE_SIZE] __in_kdata; | 
|---|
| 115 | struct tss cpu0_tss __in_kdata; | 
|---|
| 116 | uint8_t cpu0_intr_stack[STKSIZE] __in_kdata; | 
|---|
| 117 | uint8_t cpu0_dbfl_stack[STKSIZE] __in_kdata; | 
|---|
| 118 | uint8_t cpu0_nmfl_stack[STKSIZE] __in_kdata; | 
|---|
| 119 |  | 
|---|
| 120 | static void | 
|---|
| 121 | setregion(struct region_descriptor *rd, void *base, uint16_t limit) | 
|---|
| 122 | { | 
|---|
| 123 |         rd->rd_limit = limit; | 
|---|
| 124 |         rd->rd_base = (uint64_t)base; | 
|---|
| 125 | } | 
|---|
| 126 |  | 
|---|
| 127 | /* -------------------------------------------------------------------------- */ | 
|---|
| 128 |  | 
|---|
| 129 | static void | 
|---|
| 130 | gdt_set_memseg(struct gdt_memseg *sd, void *base, size_t limit, | 
|---|
| 131 |         int type, int dpl, int gran, int is64) | 
|---|
| 132 | { | 
|---|
| 133 |         sd->sd_lolimit = (unsigned)limit; | 
|---|
| 134 |         sd->sd_lobase = (unsigned long)base; | 
|---|
| 135 |         sd->sd_type = type; | 
|---|
| 136 |         sd->sd_dpl = dpl; | 
|---|
| 137 |         sd->sd_p = 1; | 
|---|
| 138 |         sd->sd_hilimit = (unsigned)limit >> 16; | 
|---|
| 139 |         sd->sd_avl = 0; | 
|---|
| 140 |         sd->sd_long = is64; | 
|---|
| 141 |         sd->sd_def32 = 0; | 
|---|
| 142 |         sd->sd_gran = gran; | 
|---|
| 143 |         sd->sd_hibase = (unsigned long)base >> 24; | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | static void | 
|---|
| 147 | gdt_set_sysseg(struct gdt_sysseg *sd, void *base, size_t limit, | 
|---|
| 148 |         int type, int dpl, int gran) | 
|---|
| 149 | { | 
|---|
| 150 |         memset(sd, 0, sizeof *sd); | 
|---|
| 151 |         sd->sd_lolimit = (unsigned)limit; | 
|---|
| 152 |         sd->sd_lobase = (uint64_t)base; | 
|---|
| 153 |         sd->sd_type = type; | 
|---|
| 154 |         sd->sd_dpl = dpl; | 
|---|
| 155 |         sd->sd_p = 1; | 
|---|
| 156 |         sd->sd_hilimit = (unsigned)limit >> 16; | 
|---|
| 157 |         sd->sd_gran = gran; | 
|---|
| 158 |         sd->sd_hibase = (uint64_t)base >> 24; | 
|---|
| 159 | } | 
|---|
| 160 |  | 
|---|
| 161 | static void gdt_create() | 
|---|
| 162 | { | 
|---|
| 163 |         memset(&gdtstore, 0, PAGE_SIZE); | 
|---|
| 164 |  | 
|---|
| 165 |         /* Flat segments */ | 
|---|
| 166 |         gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_KCODE_SEL), 0, | 
|---|
| 167 |             0xfffff, SDT_MEMERA, SEL_KPL, 1, 1); | 
|---|
| 168 |         gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_KDATA_SEL), 0, | 
|---|
| 169 |             0xfffff, SDT_MEMRWA, SEL_KPL, 1, 1); | 
|---|
| 170 |         gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_UCODE_SEL), 0, | 
|---|
| 171 |             0xfffff, SDT_MEMERA, SEL_UPL, 1, 1); | 
|---|
| 172 |         gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_UDATA_SEL), 0, | 
|---|
| 173 |             0xfffff, SDT_MEMRWA, SEL_UPL, 1, 1); | 
|---|
| 174 | } | 
|---|
| 175 |  | 
|---|
| 176 | void cpu_load_gdt() | 
|---|
| 177 | { | 
|---|
| 178 |         struct region_descriptor region; | 
|---|
| 179 |         setregion(®ion, &gdtstore, PAGE_SIZE - 1); | 
|---|
| 180 |         lgdt(®ion); | 
|---|
| 181 | } | 
|---|
| 182 |  | 
|---|
| 183 | /* -------------------------------------------------------------------------- */ | 
|---|
| 184 |  | 
|---|
| 185 | static void | 
|---|
| 186 | idt_set_seg(struct idt_seg *seg, void *func, int ist, int type, int dpl, int sel) | 
|---|
| 187 | { | 
|---|
| 188 |         seg->gd_looffset = (uint64_t)func & 0xffff; | 
|---|
| 189 |         seg->gd_selector = sel; | 
|---|
| 190 |         seg->gd_ist = ist; | 
|---|
| 191 |         seg->gd_type = type; | 
|---|
| 192 |         seg->gd_dpl = dpl; | 
|---|
| 193 |         seg->gd_p = 1; | 
|---|
| 194 |         seg->gd_hioffset = (uint64_t)func >> 16; | 
|---|
| 195 |         seg->gd_zero = 0; | 
|---|
| 196 |         seg->gd_xx1 = 0; | 
|---|
| 197 |         seg->gd_xx2 = 0; | 
|---|
| 198 |         seg->gd_xx3 = 0; | 
|---|
| 199 | } | 
|---|
| 200 |  | 
|---|
| 201 | static void idt_create() | 
|---|
| 202 | { | 
|---|
| 203 |         extern uint64_t x86_traps[]; | 
|---|
| 204 |         struct idt_seg *idt; | 
|---|
| 205 |         size_t i; | 
|---|
| 206 |  | 
|---|
| 207 |         idt = (struct idt_seg *)&idtstore; | 
|---|
| 208 |         for (i = 0; i < NCPUIDT; i++) { | 
|---|
| 209 |                 idt_set_seg(&idt[i], (void *)x86_traps[i], 0, SDT_SYS386IGT, | 
|---|
| 210 |                     SEL_KPL, GDT_FIXED_SEL(GDT_KCODE_SEL, SEL_KPL)); | 
|---|
| 211 |         } | 
|---|
| 212 | } | 
|---|
| 213 |  | 
|---|
| 214 | void cpu_load_idt() | 
|---|
| 215 | { | 
|---|
| 216 |         struct region_descriptor region; | 
|---|
| 217 |         setregion(®ion, &idtstore, PAGE_SIZE - 1); | 
|---|
| 218 |         lidt(®ion); | 
|---|
| 219 | } | 
|---|
| 220 |  | 
|---|
| 221 | /* -------------------------------------------------------------------------- */ | 
|---|
| 222 |  | 
|---|
| 223 | /* | 
|---|
| 224 |  * The gdt bitmap must be per-cluster. | 
|---|
| 225 |  */ | 
|---|
| 226 | int tss_alloc(struct tss *tss) | 
|---|
| 227 | { | 
|---|
| 228 |         int slot; | 
|---|
| 229 |  | 
|---|
| 230 |         /* Once we have proper SMP support, we will change that */ | 
|---|
| 231 |         slot = GDT_CPU0TSS_SEL; | 
|---|
| 232 |  | 
|---|
| 233 |         gdt_set_sysseg(GDT_ADDR_SYS(gdtstore, slot), tss, | 
|---|
| 234 |             sizeof(*tss) - 1, SDT_SYS386TSS, SEL_KPL, 0); | 
|---|
| 235 |  | 
|---|
| 236 |         return GDT_DYNAM_SEL(slot, SEL_KPL); | 
|---|
| 237 | } | 
|---|
| 238 |  | 
|---|
| 239 | void cpu_create_tss() | 
|---|
| 240 | { | 
|---|
| 241 |         struct tss *tss = &cpu0_tss; | 
|---|
| 242 |         int sel; | 
|---|
| 243 |  | 
|---|
| 244 |         /* Create the tss */ | 
|---|
| 245 |         memset(tss, 0, sizeof(*tss)); | 
|---|
| 246 |         tss->tss_iobase = IOMAP_INVALOFF << 16; | 
|---|
| 247 |         tss->tss_ist[0] = (uint64_t)cpu0_intr_stack + STKSIZE; | 
|---|
| 248 |         tss->tss_ist[1] = (uint64_t)cpu0_dbfl_stack + STKSIZE; | 
|---|
| 249 |         tss->tss_ist[2] = (uint64_t)cpu0_nmfl_stack + STKSIZE; | 
|---|
| 250 |         sel = tss_alloc(tss); | 
|---|
| 251 |  | 
|---|
| 252 |         /* Load it */ | 
|---|
| 253 |         ltr(sel); | 
|---|
| 254 | } | 
|---|
| 255 |  | 
|---|
| 256 | /* -------------------------------------------------------------------------- */ | 
|---|
| 257 |  | 
|---|
| 258 | void cpu_attach() | 
|---|
| 259 | { | 
|---|
| 260 |         cpu_load_gdt(); | 
|---|
| 261 |         cpu_load_idt(); | 
|---|
| 262 |         cpu_create_tss(); | 
|---|
| 263 | } | 
|---|
| 264 |  | 
|---|