source: trunk/hal/x86_64/core/hal_init.c @ 167

Last change on this file since 167 was 166, checked in by max@…, 7 years ago

identify the cpu features

File size: 12.6 KB
Line 
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#include <hal_acpi.h>
27#include <hal_apic.h>
28#include <hal_internal.h>
29#include <hal_register.h>
30
31#include <hal_remote.h>
32#include <hal_irqmask.h>
33
34#include <memcpy.h>
35#include <thread.h>
36#include <string.h>
37#include <process.h>
38#include <printk.h>
39#include <vmm.h>
40#include <core.h>
41#include <cluster.h>
42#include <chdev.h>
43
44#include <boot_info.h>
45
46void kernel_init(boot_info_t *info);
47
48static void gdt_create();
49static void idt_create();
50void cpu_identify();
51void cpu_attach();
52
53size_t mytest __in_kdata = 0;
54
55struct multiboot_info mb_info __in_kdata;
56char mb_loader_name[PAGE_SIZE] __in_kdata;
57uint8_t mb_mmap[PAGE_SIZE] __in_kdata;
58
59/* -------------------------------------------------------------------------- */
60
61static void
62dump_memmap()
63{
64        size_t mmap_length = mb_info.mi_mmap_length;
65        uint8_t *mmap_addr = (uint8_t *)&mb_mmap;
66        size_t i;
67
68        if (!(mb_info.mi_flags & MULTIBOOT_INFO_HAS_MMAP))
69                x86_panic("No mmap");
70
71        i = 0;
72        while (i < mmap_length) {
73                struct multiboot_mmap *mm;
74
75                mm = (struct multiboot_mmap *)(mmap_addr + i);
76
77                x86_printf("-> [%Z, %Z] %s\n", mm->mm_base_addr,
78                    mm->mm_base_addr + mm->mm_length,
79                    (mm->mm_type == 1) ? "ram" : "rsv" );
80
81                i += mm->mm_size + 4;
82        }
83}
84
85/* -------------------------------------------------------------------------- */
86
87static void init_bootinfo_icu(boot_device_t *dev)
88{
89        extern uint32_t hwi_baseidx;
90        extern uint32_t wti_baseidx;
91        extern uint32_t pti_baseidx;
92        extern size_t ioapic_pins;
93
94        memset(dev, 0, sizeof(boot_device_t));
95
96        dev->base = 0;
97        dev->type = (DEV_FUNC_ICU << 16) | IMPL_ICU_XCU;
98        dev->channels = 1;
99
100#if NOTYET
101        /*
102         * Give 20% of the pins to HWI, 80% to WTI.
103         */
104        dev->param0 = (ioapic_pins * 20) / 100;  /* hwi_nr */
105        dev->param1 = ioapic_pins - dev->param0; /* wti_nr */
106#else
107        dev->param0 = 1; /* hwi_nr */
108        dev->param1 = 1; /* wti_nr */
109#endif
110
111        /*
112         * We always set 1 for pti_nr. On x86, timer interrupts are handled by
113         * LAPIC, which is per-cpu and not global. Therefore, we always have one
114         * timer for each CPU, and its IRQ number is faked to 0.
115         */
116        dev->param2 = 1; /* pti_nr */
117
118        dev->param3 = 0;
119
120        /* Set the base idx for the XCU driver */
121        hwi_baseidx = 0;
122        wti_baseidx = dev->param0;
123        pti_baseidx = 0xFFFFFFFF;
124
125#ifdef NOTYET
126    uint32_t    irqs;                 /*! number of input IRQs                              */
127    boot_irq_t  irq[32];              /*! array of input IRQS (PIC and ICU only)            */
128#endif
129}
130
131static size_t init_bootinfo_pages_nr()
132{
133        size_t mmap_length = mb_info.mi_mmap_length;
134        uint8_t *mmap_addr = (uint8_t *)&mb_mmap;
135        paddr_t maxpa, pa;
136        size_t i;
137
138        i = 0;
139        maxpa = 0;
140        while (i < mmap_length) {
141                struct multiboot_mmap *mm;
142
143                mm = (struct multiboot_mmap *)(mmap_addr + i);
144
145                if (mm->mm_type == 1) {
146                        pa = mm->mm_base_addr + mm->mm_length;
147                        if (pa > maxpa)
148                                maxpa = pa;
149                }
150
151                i += mm->mm_size + 4;
152        }
153
154        return (maxpa / PAGE_SIZE);
155}
156
157static size_t init_bootinfo_rsvd(boot_rsvd_t *rsvd)
158{
159        size_t mmap_length = mb_info.mi_mmap_length;
160        uint8_t *mmap_addr = (uint8_t *)&mb_mmap;
161        size_t i, rsvd_nr;
162
163        memset(rsvd, 0, sizeof(boot_rsvd_t) * CONFIG_PPM_MAX_RSVD);
164
165        i = 0, rsvd_nr = 0;
166        while (i < mmap_length) {
167                struct multiboot_mmap *mm;
168
169                mm = (struct multiboot_mmap *)(mmap_addr + i);
170
171                if (mm->mm_type != 1) {
172                        rsvd[rsvd_nr].first_page =
173                            rounddown(mm->mm_base_addr, PAGE_SIZE) / PAGE_SIZE;
174                        rsvd[rsvd_nr].npages =
175                            roundup(mm->mm_length, PAGE_SIZE) / PAGE_SIZE;
176                        rsvd_nr++;
177                        if (rsvd_nr == CONFIG_PPM_MAX_RSVD)
178                                x86_panic("too many memory holes");
179                }
180
181                i += mm->mm_size + 4;
182        }
183
184        return rsvd_nr;
185}
186
187static void init_bootinfo_core(boot_core_t *core)
188{
189        memset(core, 0, sizeof(boot_core_t));
190
191        core->gid = hal_lapic_gid();
192        core->lid = 0;
193        core->cxy = 0;
194}
195
196static void init_bootinfo_txt(boot_device_t *dev)
197{
198        memset(dev, 0, sizeof(boot_device_t));
199
200        dev->base = 0xB8000;
201        dev->type = (DEV_FUNC_TXT << 16) | IMPL_TXT_X86;
202        dev->channels = 1;
203        dev->param0 = 0;
204        dev->param1 = 0;
205        dev->param2 = 0;
206        dev->param3 = 0;
207
208#ifdef NOTYET
209    uint32_t    irqs;    /*! number of input IRQs                    */
210    boot_irq_t  irq[32]; /*! array of input IRQS (PIC and ICU only)  */
211#endif
212}
213
214static void init_bootinfo(boot_info_t *info)
215{
216        size_t offset;
217
218        extern uint64_t __kernel_data_start;
219        extern uint64_t __kernel_end;
220
221        memset(info, 0, sizeof(boot_info_t));
222
223        info->signature = 0;
224
225        info->paddr_width = 0;
226        info->x_width = 1;
227        info->y_width = 1;
228        info->x_size = 1;
229        info->y_size = 1;
230        info->io_cxy = 0;
231
232        info->ext_dev_nr = 1;
233        init_bootinfo_txt(&info->ext_dev[0]);
234
235        info->cxy = 0;
236        info->cores_nr = 1;
237        init_bootinfo_core(&info->core[0]);
238
239        info->rsvd_nr = init_bootinfo_rsvd((boot_rsvd_t *)&info->rsvd);
240
241        init_bootinfo_icu(&info->dev_icu);
242        /* TODO: dev_mmc */
243        /* TODO: dev_dma */
244
245        offset = hal_gpt_bootstrap_uniformize();
246        info->pages_offset = offset / PAGE_SIZE;
247        info->pages_nr = init_bootinfo_pages_nr();
248
249        info->kernel_code_start = (intptr_t)(KERNTEXTOFF - KERNBASE);
250        info->kernel_code_end = (intptr_t)(&__kernel_data_start - KERNBASE) - 1;
251        info->kernel_data_start = (intptr_t)(&__kernel_data_start - KERNBASE);
252        info->kernel_code_end = (intptr_t)(&__kernel_end - KERNBASE) - 1;
253}
254
255/* -------------------------------------------------------------------------- */
256
257void init_x86_64(paddr_t firstpa)
258{
259        boot_info_t btinfo;
260
261        /* Initialize the serial port */
262        hal_com_init_early();
263
264        x86_printf("[+] init_x86_64 called\n");
265
266        /* Create the global structures */
267        gdt_create();
268        idt_create();
269
270        /* Identify the features of the cpu */
271        cpu_identify();
272
273        /* Attach cpu0 */
274        cpu_attach(0);
275        x86_printf("[+] cpu_attach called\n");
276
277        x86_printf("[+] bootloader: '%s'\n", mb_loader_name);
278
279        dump_memmap();
280        x86_printf("[+] dump finished\n");
281
282        hal_gpt_init(firstpa);
283        x86_printf("[+] hal_gpt_init called\n");
284
285        hal_acpi_init();
286        x86_printf("[+] hal_acpi_init called\n");
287
288        hal_gpt_bootstrap_reset();
289        x86_printf("[+] hal_gpt_bootstrap_reset called\n");
290
291        hal_apic_init();
292        x86_printf("[+] hal_apic_init called\n");
293
294        hal_tls_init_cpu0();
295        x86_printf("[+] hal_tls_init_cpu0 called\n");
296
297        x86_printf("-> mytest = %z\n", mytest);
298        void *hoho = &init_x86_64;
299        xptr_t myptr = XPTR(0, &mytest);
300
301        hal_remote_spt(myptr, hoho);
302        x86_printf("-> mytest = %Z\n", hal_remote_lpt(myptr));
303
304        init_bootinfo(&btinfo);
305
306        reg_t dummy;
307        hal_enable_irq(&dummy);
308
309        while (1);
310
311        kernel_init(&btinfo);
312
313        x86_printf("[+] kernel_init called\n");
314
315        while (1);
316
317//      void x86_stop();
318//      x86_stop();
319}
320
321/* -------------------------------------------------------------------------- */
322
323/* x86-specific per-cluster structures */
324uint8_t gdtstore[PAGE_SIZE] __in_kdata;
325uint8_t idtstore[PAGE_SIZE] __in_kdata;
326
327/* x86-specific per-cpu structures */
328typedef struct {
329        struct tss tss;
330        uint8_t intr_stack[STKSIZE];
331        uint8_t dbfl_stack[STKSIZE];
332        uint8_t nmfl_stack[STKSIZE];
333} percpu_archdata_t;
334percpu_archdata_t cpudata[CONFIG_MAX_LOCAL_CORES] __in_kdata;
335
336static void
337setregion(struct region_descriptor *rd, void *base, uint16_t limit)
338{
339        rd->rd_limit = limit;
340        rd->rd_base = (uint64_t)base;
341}
342
343/* -------------------------------------------------------------------------- */
344
345static void
346gdt_set_memseg(struct gdt_memseg *sd, void *base, size_t limit,
347        int type, int dpl, int gran, int is64)
348{
349        sd->sd_lolimit = (unsigned)limit;
350        sd->sd_lobase = (unsigned long)base;
351        sd->sd_type = type;
352        sd->sd_dpl = dpl;
353        sd->sd_p = 1;
354        sd->sd_hilimit = (unsigned)limit >> 16;
355        sd->sd_avl = 0;
356        sd->sd_long = is64;
357        sd->sd_def32 = 0;
358        sd->sd_gran = gran;
359        sd->sd_hibase = (unsigned long)base >> 24;
360}
361
362static void
363gdt_set_sysseg(struct gdt_sysseg *sd, void *base, size_t limit,
364        int type, int dpl, int gran)
365{
366        memset(sd, 0, sizeof *sd);
367        sd->sd_lolimit = (unsigned)limit;
368        sd->sd_lobase = (uint64_t)base;
369        sd->sd_type = type;
370        sd->sd_dpl = dpl;
371        sd->sd_p = 1;
372        sd->sd_hilimit = (unsigned)limit >> 16;
373        sd->sd_gran = gran;
374        sd->sd_hibase = (uint64_t)base >> 24;
375}
376
377static void gdt_create()
378{
379        memset(&gdtstore, 0, PAGE_SIZE);
380
381        /* Flat segments */
382        gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_KCODE_SEL), 0,
383            0xfffff, SDT_MEMERA, SEL_KPL, 1, 1);
384        gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_KDATA_SEL), 0,
385            0xfffff, SDT_MEMRWA, SEL_KPL, 1, 1);
386        gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_UCODE_SEL), 0,
387            0xfffff, SDT_MEMERA, SEL_UPL, 1, 1);
388        gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_UDATA_SEL), 0,
389            0xfffff, SDT_MEMRWA, SEL_UPL, 1, 1);
390}
391
392void cpu_load_gdt()
393{
394        struct region_descriptor region;
395        setregion(&region, &gdtstore, PAGE_SIZE - 1);
396        lgdt(&region);
397}
398
399/* -------------------------------------------------------------------------- */
400
401static void
402idt_set_seg(struct idt_seg *seg, void *func, int ist, int type, int dpl, int sel)
403{
404        seg->gd_looffset = (uint64_t)func & 0xffff;
405        seg->gd_selector = sel;
406        seg->gd_ist = ist;
407        seg->gd_type = type;
408        seg->gd_dpl = dpl;
409        seg->gd_p = 1;
410        seg->gd_hioffset = (uint64_t)func >> 16;
411        seg->gd_zero = 0;
412        seg->gd_xx1 = 0;
413        seg->gd_xx2 = 0;
414        seg->gd_xx3 = 0;
415}
416
417static void idt_create()
418{
419        extern uint64_t x86_traps[], x86_intrs[], x86_rsvd;
420        struct idt_seg *idt;
421        size_t i;
422
423        idt = (struct idt_seg *)&idtstore;
424
425        /* First, put a dead entry */
426        for (i = 0; i < NIDT; i++) {
427                idt_set_seg(&idt[i], (void *)&x86_rsvd, 0,
428                    SDT_SYS386IGT, SEL_KPL, GDT_FIXED_SEL(GDT_KCODE_SEL, SEL_KPL));
429        }
430
431        /* General exceptions */
432        for (i = CPUVEC_MIN; i < CPUVEC_MAX; i++) {
433                idt_set_seg(&idt[i], (void *)x86_traps[i - CPUVEC_MIN], 0,
434                    SDT_SYS386IGT, SEL_KPL, GDT_FIXED_SEL(GDT_KCODE_SEL, SEL_KPL));
435        }
436
437        /* Dynamically configured interrupts */
438        for (i = DYNVEC_MIN; i < DYNVEC_MAX; i++) {
439                idt_set_seg(&idt[i], (void *)x86_intrs[i - DYNVEC_MIN], 0,
440                    SDT_SYS386IGT, SEL_KPL, GDT_FIXED_SEL(GDT_KCODE_SEL, SEL_KPL));
441        }
442}
443
444void cpu_load_idt()
445{
446        struct region_descriptor region;
447        setregion(&region, &idtstore, PAGE_SIZE - 1);
448        lidt(&region);
449}
450
451/* -------------------------------------------------------------------------- */
452
453int tss_alloc(struct tss *tss, size_t lid)
454{
455        int slot;
456
457        slot = GDT_CPUTSS_SEL + lid;
458
459        gdt_set_sysseg(GDT_ADDR_SYS(gdtstore, slot), tss,
460            sizeof(*tss) - 1, SDT_SYS386TSS, SEL_KPL, 0);
461
462        return GDT_DYNAM_SEL(slot, SEL_KPL);
463}
464
465void cpu_create_tss(size_t lid)
466{
467        percpu_archdata_t *data = &cpudata[lid];
468        struct tss *tss = &data->tss;
469        int sel;
470
471        /* Create the tss */
472        memset(tss, 0, sizeof(*tss));
473
474        /* tss->tss_rsp0 */
475        tss->tss_ist[0] = (uint64_t)data->intr_stack[lid] + STKSIZE;
476        tss->tss_ist[1] = (uint64_t)data->dbfl_stack[lid] + STKSIZE;
477        tss->tss_ist[2] = (uint64_t)data->nmfl_stack[lid] + STKSIZE;
478        tss->tss_iobase = IOMAP_INVALOFF << 16;
479        sel = tss_alloc(tss, lid);
480
481        /* Load it */
482        ltr(sel);
483}
484
485/* -------------------------------------------------------------------------- */
486
487uint64_t cpu_features[4] __in_kdata;
488
489void cpu_identify()
490{
491        /*
492         * desc[0] = eax
493         * desc[1] = ebx
494         * desc[2] = ecx
495         * desc[3] = edx
496         */
497        uint32_t desc[4];
498        char vendor[13];
499        size_t lvl;
500
501        /*
502         * Get information from the standard cpuid leafs
503         */
504        cpuid(0, 0, (uint32_t *)&desc);
505
506        lvl = (uint64_t)desc[0];
507        x86_printf("-> cpuid standard level: %z\n", lvl);
508
509        memcpy(vendor + 0, &desc[1], sizeof(uint32_t));
510        memcpy(vendor + 8, &desc[2], sizeof(uint32_t));
511        memcpy(vendor + 4, &desc[3], sizeof(uint32_t));
512        vendor[12] = '\0';
513        x86_printf("-> CPU vendor: '%s'\n", vendor);
514
515        if (lvl >= 1) {
516                cpuid(1, 0, (uint32_t *)&desc);
517                cpu_features[0] = desc[3];
518                cpu_features[1] = desc[2];
519        }
520
521        /*
522         * Get information from the extended cpuid leafs
523         */
524        cpuid(0x80000000, 0, desc);
525
526        lvl = (uint64_t)desc[0];
527        x86_printf("-> cpuid extended level: %Z\n", lvl);
528}
529
530/* -------------------------------------------------------------------------- */
531
532void cpu_attach(size_t lid)
533{
534        cpu_load_gdt();
535        cpu_load_idt();
536        cpu_create_tss(lid);
537
538        if (cpu_features[0] & CPUID_PSE) {
539                lcr4(rcr4() | CR4_PSE);
540                tlbflushg();
541        } else {
542                /*
543                 * amd64 supports PSE by default, if it's not here we have a
544                 * problem
545                 */
546                x86_panic("PSE not supported");
547        }
548}
549
Note: See TracBrowser for help on using the repository browser.