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

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

Use pause().

File size: 15.7 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_kentry.h>
29#include <hal_internal.h>
30#include <hal_register.h>
31
32#include <hal_remote.h>
33#include <hal_irqmask.h>
34
35#include <memcpy.h>
36#include <thread.h>
37#include <string.h>
38#include <process.h>
39#include <printk.h>
40#include <vmm.h>
41#include <core.h>
42#include <cluster.h>
43#include <chdev.h>
44
45#include <boot_info.h>
46
47void kernel_init(boot_info_t *info);
48
49static void gdt_create();
50static void idt_create();
51void cpu_tls_init(size_t lid);
52void cpu_identify();
53void cpu_attach(size_t lid);
54
55size_t mytest __in_kdata = 0;
56
57struct multiboot_info mb_info __in_kdata;
58char mb_loader_name[PAGE_SIZE] __in_kdata;
59uint8_t mb_mmap[PAGE_SIZE] __in_kdata;
60
61size_t ncpu __in_kdata = 0;
62static boot_info_t btinfo __in_kdata;
63
64/* x86-specific per-cluster structures */
65uint8_t gdtstore[PAGE_SIZE] __in_kdata;
66uint8_t idtstore[PAGE_SIZE] __in_kdata;
67
68/* x86-specific per-cpu structures */
69typedef struct {
70        bool_t valid;
71        struct tss tss;
72        struct tls tls;
73        uint8_t boot_stack[STKSIZE];
74        uint8_t intr_stack[STKSIZE];
75        uint8_t dbfl_stack[STKSIZE];
76        uint8_t nmfl_stack[STKSIZE];
77} percpu_archdata_t;
78percpu_archdata_t cpudata[CONFIG_MAX_LOCAL_CORES] __in_kdata;
79
80/* -------------------------------------------------------------------------- */
81
82static void
83dump_memmap()
84{
85        size_t mmap_length = mb_info.mi_mmap_length;
86        uint8_t *mmap_addr = (uint8_t *)&mb_mmap;
87        size_t i;
88
89        if (!(mb_info.mi_flags & MULTIBOOT_INFO_HAS_MMAP))
90                x86_panic("No mmap");
91
92        i = 0;
93        while (i < mmap_length) {
94                struct multiboot_mmap *mm;
95
96                mm = (struct multiboot_mmap *)(mmap_addr + i);
97
98                x86_printf("-> [%Z, %Z] %s\n", mm->mm_base_addr,
99                    mm->mm_base_addr + mm->mm_length,
100                    (mm->mm_type == 1) ? "ram" : "rsv" );
101
102                i += mm->mm_size + 4;
103        }
104}
105
106/* -------------------------------------------------------------------------- */
107
108static size_t init_bootinfo_pages_nr()
109{
110        size_t mmap_length = mb_info.mi_mmap_length;
111        uint8_t *mmap_addr = (uint8_t *)&mb_mmap;
112        paddr_t maxpa, pa;
113        size_t i;
114
115        i = 0;
116        maxpa = 0;
117        while (i < mmap_length) {
118                struct multiboot_mmap *mm;
119
120                mm = (struct multiboot_mmap *)(mmap_addr + i);
121
122                if (mm->mm_type == 1) {
123                        pa = mm->mm_base_addr + mm->mm_length;
124                        if (pa > maxpa)
125                                maxpa = pa;
126                }
127
128                i += mm->mm_size + 4;
129        }
130
131        return (maxpa / PAGE_SIZE);
132}
133
134static size_t init_bootinfo_rsvd(boot_rsvd_t *rsvd)
135{
136        size_t mmap_length = mb_info.mi_mmap_length;
137        uint8_t *mmap_addr = (uint8_t *)&mb_mmap;
138        size_t i, rsvd_nr;
139
140        memset(rsvd, 0, sizeof(boot_rsvd_t) * CONFIG_PPM_MAX_RSVD);
141
142        i = 0, rsvd_nr = 0;
143        while (i < mmap_length) {
144                struct multiboot_mmap *mm;
145
146                mm = (struct multiboot_mmap *)(mmap_addr + i);
147
148                if (mm->mm_type != 1) {
149                        rsvd[rsvd_nr].first_page =
150                            rounddown(mm->mm_base_addr, PAGE_SIZE) / PAGE_SIZE;
151                        rsvd[rsvd_nr].npages =
152                            roundup(mm->mm_length, PAGE_SIZE) / PAGE_SIZE;
153                        rsvd_nr++;
154                        if (rsvd_nr == CONFIG_PPM_MAX_RSVD)
155                                x86_panic("too many memory holes");
156                }
157
158                i += mm->mm_size + 4;
159        }
160
161        return rsvd_nr;
162}
163
164static void init_bootinfo_core(boot_core_t *core)
165{
166        size_t i;
167
168        // XXX: not necessarily contiguous
169        for (i = 0; i < ncpu; i++) {
170                memset(&core[i], 0, sizeof(boot_core_t));
171
172                core[i].gid = i;
173                core[i].lid = i;
174                core[i].cxy = 0;
175        }
176}
177
178static void init_bootinfo_ioc(boot_device_t *dev)
179{
180        memset(dev, 0, sizeof(boot_device_t));
181
182        dev->base = 0;
183        dev->type = (DEV_FUNC_IOC << 16) | IMPL_IOC_BDV;
184        dev->channels = 1;
185}
186
187static void init_bootinfo_pic(boot_device_t *dev)
188{
189        memset(dev, 0, sizeof(boot_device_t));
190
191        dev->base = 0;
192        dev->type = (DEV_FUNC_PIC << 16) | IMPL_PIC_I86;
193        dev->channels = 1;
194        dev->param0 = 0;
195        dev->param1 = 0;
196        dev->param2 = 0;
197        dev->param3 = 0;
198
199        dev->irqs = 16;
200
201        /* ATA */
202        dev->irq[IRQ_ATA0].dev_type = (DEV_FUNC_IOC << 16) | IMPL_IOC_BDV;
203        dev->irq[IRQ_ATA0].channel = 0;
204        dev->irq[IRQ_ATA0].is_rx = 0;
205        dev->irq[IRQ_ATA0].valid = 1;
206}
207
208static void init_bootinfo_txt(boot_device_t *dev)
209{
210        memset(dev, 0, sizeof(boot_device_t));
211
212        dev->base = 0;
213        dev->type = (DEV_FUNC_TXT << 16) | IMPL_TXT_RS2;
214        dev->channels = 4;
215        dev->param0 = 0;
216        dev->param1 = 0;
217        dev->param2 = 0;
218        dev->param3 = 0;
219}
220
221static void init_bootinfo(boot_info_t *info)
222{
223        size_t offset;
224
225        memset(info, 0, sizeof(boot_info_t));
226
227        info->signature = 0;
228
229        info->paddr_width = 0;
230        info->x_width = 1;
231        info->y_width = 1;
232        info->x_size = 1;
233        info->y_size = 1;
234        info->io_cxy = 0;
235
236        info->ext_dev_nr = 3;
237        init_bootinfo_txt(&info->ext_dev[0]);
238        init_bootinfo_pic(&info->ext_dev[1]);
239        init_bootinfo_ioc(&info->ext_dev[2]);
240
241        info->cxy = 0;
242        info->cores_nr = ncpu;
243        init_bootinfo_core((boot_core_t *)&info->core);
244
245        info->rsvd_nr = init_bootinfo_rsvd((boot_rsvd_t *)&info->rsvd);
246
247        /* TODO: dev_mmc */
248        /* TODO: dev_dma */
249
250        offset = hal_gpt_bootstrap_uniformize();
251        info->pages_offset = offset / PAGE_SIZE;
252        info->pages_nr = init_bootinfo_pages_nr();
253}
254
255/* -------------------------------------------------------------------------- */
256
257static uint32_t cpuN_booted __in_kdata;
258
259void start_secondary_cpus()
260{
261        pt_entry_t flags = PG_V | PG_KW;
262        extern vaddr_t cpuN_boot_trampoline;
263        extern vaddr_t cpuN_boot_trampoline_end;
264        extern paddr_t smp_L4pa;
265        extern vaddr_t smp_stkva;
266        extern paddr_t L4paddr;
267        size_t i, sz;
268
269        smp_L4pa = L4paddr;
270
271        /* map the SMP trampoline (identity) */
272        vaddr_t trampva = (vaddr_t)SMP_TRAMPOLINE_PA;
273        hal_gpt_maptree_area(trampva, trampva + PAGE_SIZE);
274        hal_gpt_enter(trampva, SMP_TRAMPOLINE_PA, flags);
275
276        /* copy it */
277        sz = (size_t)&cpuN_boot_trampoline_end - (size_t)&cpuN_boot_trampoline;
278        memcpy((void *)trampva, (void *)&cpuN_boot_trampoline, sz);
279
280        for (i = 0; i < CONFIG_MAX_LOCAL_CORES; i++) {
281                if (i == 0 || !cpudata[i].valid) {
282                        continue;
283                }
284
285                smp_stkva = ((vaddr_t)&cpudata[i].boot_stack + STKSIZE) & ~0xF;
286
287                cpuN_booted = 0;
288                boot_cpuN(i, SMP_TRAMPOLINE_PA);
289                while (!hal_atomic_cas(&cpuN_booted, 1, 0)) {
290                        pause();
291                }
292        }
293
294        // XXX: unmap the trampoline
295}
296
297void init_x86_64_cpuN()
298{
299        lid_t lid;
300
301        cli();
302
303        lid = hal_lapic_gid();
304
305        cpu_attach(lid);
306        x86_printf("[cpu%z] cpu_attach called\n", (uint64_t)lid);
307
308        cpu_tls_init(lid);
309        x86_printf("[cpu%z] cput_tls_init called\n", (uint64_t)lid);
310
311        cpu_lapic_init();
312        x86_printf("[cpu%z] cpu_lapic_init called\n", (uint64_t)lid);
313
314        cpuN_booted = 1;
315
316        if (lid == 1) {
317                hal_ioapic_disable_irq(IRQ_KEYBOARD);
318                hal_ioapic_bind_irq(IRQ_KEYBOARD, IOAPIC_KEYBOARD_VECTOR, 1);
319                hal_ioapic_enable_irq(IRQ_KEYBOARD);
320        }
321
322        kernel_init(&btinfo);
323
324        reg_t dummy;
325        hal_enable_irq(&dummy);
326
327        while (1);
328}
329
330/* -------------------------------------------------------------------------- */
331
332static void apic_map()
333{
334        extern vaddr_t lapic_va, ioapic_va;
335        extern paddr_t lapic_pa, ioapic_pa;
336
337        lapic_va = hal_gpt_bootstrap_valloc(1); // XXX: should be shared
338        hal_gpt_enter(lapic_va, lapic_pa, PG_V|PG_KW|PG_NX|PG_N);
339
340        ioapic_va = hal_gpt_bootstrap_valloc(1); // XXX: should be shared
341        hal_gpt_enter(ioapic_va, ioapic_pa, PG_V|PG_KW|PG_NX|PG_N);
342}
343
344void init_x86_64(paddr_t firstpa)
345{
346        cli();
347
348        /* Initialize the serial port */
349        hal_com_init_early();
350
351        x86_printf("[+] init_x86_64 called\n");
352
353        /* Create the global structures */
354        gdt_create();
355        idt_create();
356
357        /* Identify the features of the cpu */
358        cpu_identify();
359
360        /* Attach cpu0 */
361        cpu_attach(0);
362        x86_printf("[+] cpu_attach called\n");
363
364        x86_printf("[+] bootloader: '%s'\n", mb_loader_name);
365
366        dump_memmap();
367        x86_printf("[+] dump finished\n");
368
369        hal_gpt_init(firstpa);
370        x86_printf("[+] hal_gpt_init called\n");
371
372        hal_acpi_init();
373        x86_printf("[+] hal_acpi_init called\n");
374
375        hal_gpt_bootstrap_reset();
376        x86_printf("[+] hal_gpt_bootstrap_reset called\n");
377
378        apic_map();
379        x86_printf("[+] apic_map called\n");
380
381        hal_apic_init();
382        cpu_lapic_init();
383        x86_printf("[+] hal_apic_init called\n");
384
385        cpu_tls_init(0);
386        x86_printf("[+] cput_tls_init called\n");
387
388        mytest = 0;
389        x86_printf("-> mytest = %z\n", mytest);
390        void *hoho = &init_x86_64;
391        xptr_t myptr = XPTR(0, &mytest);
392
393        hal_remote_spt(myptr, hoho);
394        x86_printf("-> mytest = %Z\n", hal_remote_lpt(myptr));
395
396        init_bootinfo(&btinfo);
397
398        start_secondary_cpus();
399
400        kernel_init(&btinfo);
401
402        x86_printf("[+] kernel_init called\n");
403
404        reg_t dummy;
405        hal_enable_irq(&dummy);
406
407        while (1);
408
409/*
410        void *ptr;
411
412        khm_t *khm = &LOCAL_CLUSTER->khm;
413        ptr = khm_alloc(khm, 10);
414        memset(ptr, 0, 10);
415        khm_free(ptr);
416
417
418        kcm_t *kcm = &LOCAL_CLUSTER->kcm;
419        ptr = kcm_alloc(kcm);
420        memset(ptr, 0, 1);
421        kcm_free(ptr);
422
423        ptr = ppm_alloc_pages(1);
424        ppm_free_pages(ptr);
425*/
426
427
428//      void x86_stop();
429//      x86_stop();
430}
431
432/* -------------------------------------------------------------------------- */
433
434void cpu_activate(uint32_t gid)
435{
436        cpudata[gid].valid = true;
437}
438
439static void
440setregion(struct region_descriptor *rd, void *base, uint16_t limit)
441{
442        rd->rd_limit = limit;
443        rd->rd_base = (uint64_t)base;
444}
445
446/* -------------------------------------------------------------------------- */
447
448static void
449gdt_set_memseg(struct gdt_memseg *sd, void *base, size_t limit,
450        int type, int dpl, int gran, bool_t is64)
451{
452        sd->sd_lolimit = (unsigned)limit;
453        sd->sd_lobase = (unsigned long)base;
454        sd->sd_type = type;
455        sd->sd_dpl = dpl;
456        sd->sd_p = 1;
457        sd->sd_hilimit = (unsigned)limit >> 16;
458        sd->sd_avl = 0;
459        sd->sd_long = is64;
460        sd->sd_def32 = !is64;
461        sd->sd_gran = gran;
462        sd->sd_hibase = (unsigned long)base >> 24;
463}
464
465static void
466gdt_set_sysseg(struct gdt_sysseg *sd, void *base, size_t limit,
467        int type, int dpl, int gran)
468{
469        memset(sd, 0, sizeof *sd);
470        sd->sd_lolimit = (unsigned)limit;
471        sd->sd_lobase = (uint64_t)base;
472        sd->sd_type = type;
473        sd->sd_dpl = dpl;
474        sd->sd_p = 1;
475        sd->sd_hilimit = (unsigned)limit >> 16;
476        sd->sd_gran = gran;
477        sd->sd_hibase = (uint64_t)base >> 24;
478}
479
480static void gdt_create()
481{
482        memset(&gdtstore, 0, PAGE_SIZE);
483
484        /* Flat segments */
485        gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_KCODE_SEL), 0,
486            0xfffff, SDT_MEMERA, SEL_KPL, 1, true);
487        gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_KDATA_SEL), 0,
488            0xfffff, SDT_MEMRWA, SEL_KPL, 1, true);
489        gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_UCODE32_SEL), 0,
490            0xfffff, SDT_MEMERA, SEL_UPL, 1, false);
491        gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_UCODE_SEL), 0,
492            0xfffff, SDT_MEMERA, SEL_UPL, 1, true);
493        gdt_set_memseg(GDT_ADDR_MEM(gdtstore, GDT_UDATA_SEL), 0,
494            0xfffff, SDT_MEMRWA, SEL_UPL, 1, true);
495}
496
497void cpu_load_gdt()
498{
499        struct region_descriptor region;
500        setregion(&region, &gdtstore, PAGE_SIZE - 1);
501        lgdt(&region);
502}
503
504/* -------------------------------------------------------------------------- */
505
506struct {
507        bool_t busy[256];
508} idt_bitmap __in_kdata;
509
510int idt_slot_alloc()
511{
512        size_t i;
513
514        for (i = 0; i < 256; i++) {
515                if (!idt_bitmap.busy[i])
516                        break;
517        }
518        if (i == 256) {
519                return -1;
520        }
521
522        idt_bitmap.busy[i] = true;
523        return (int)i;
524}
525
526void idt_slot_free(int slot)
527{
528        idt_bitmap.busy[slot] = false;
529}
530
531static void
532idt_set_seg(struct idt_seg *seg, void *func, int ist, int type, int dpl, int sel)
533{
534        seg->gd_looffset = (uint64_t)func & 0xffff;
535        seg->gd_selector = sel;
536        seg->gd_ist = ist;
537        seg->gd_type = type;
538        seg->gd_dpl = dpl;
539        seg->gd_p = 1;
540        seg->gd_hioffset = (uint64_t)func >> 16;
541        seg->gd_zero = 0;
542        seg->gd_xx1 = 0;
543        seg->gd_xx2 = 0;
544        seg->gd_xx3 = 0;
545}
546
547static void idt_create()
548{
549        extern uint64_t x86_traps[], x86_intrs[], x86_rsvd;
550        struct idt_seg *idt;
551        size_t i;
552        int ist;
553
554        memset(&idt_bitmap, 0, sizeof(idt_bitmap));
555        idt = (struct idt_seg *)&idtstore;
556
557        /* First, put a dead entry */
558        for (i = 0; i < NIDT; i++) {
559                idt_set_seg(&idt[i], (void *)&x86_rsvd, 0,
560                    SDT_SYS386IGT, SEL_KPL, GDT_FIXED_SEL(GDT_KCODE_SEL, SEL_KPL));
561        }
562
563        /* General exceptions */
564        for (i = CPUVEC_MIN; i < CPUVEC_MAX; i++) {
565                if (i == 2) { /* NMI */
566                        ist = 3;
567                } else if (i == 8) { /* Double Fault */
568                        ist = 2;
569                } else {
570                        ist = 0;
571                }
572                idt_set_seg(&idt[i], (void *)x86_traps[i - CPUVEC_MIN], ist,
573                    SDT_SYS386IGT, SEL_KPL, GDT_FIXED_SEL(GDT_KCODE_SEL, SEL_KPL));
574                idt_bitmap.busy[i] = true;
575        }
576
577        /* Dynamically configured interrupts */
578        for (i = DYNVEC_MIN; i < DYNVEC_MAX; i++) {
579                idt_set_seg(&idt[i], (void *)x86_intrs[i - DYNVEC_MIN], 0,
580                    SDT_SYS386IGT, SEL_KPL, GDT_FIXED_SEL(GDT_KCODE_SEL, SEL_KPL));
581                idt_bitmap.busy[i] = true;
582        }
583}
584
585void cpu_load_idt()
586{
587        struct region_descriptor region;
588        setregion(&region, &idtstore, PAGE_SIZE - 1);
589        lidt(&region);
590}
591
592/* -------------------------------------------------------------------------- */
593
594int tss_alloc(struct tss *tss, size_t lid)
595{
596        int slot;
597
598        slot = GDT_CPUTSS_SEL + lid;
599
600        gdt_set_sysseg(GDT_ADDR_SYS(gdtstore, slot), tss,
601            sizeof(*tss) - 1, SDT_SYS386TSS, SEL_KPL, 0);
602
603        return GDT_DYNAM_SEL(slot, SEL_KPL);
604}
605
606void cpu_create_tss(size_t lid)
607{
608        percpu_archdata_t *data = &cpudata[lid];
609        struct tss *tss = &data->tss;
610        int sel;
611
612        /* Create the tss */
613        memset(tss, 0, sizeof(*tss));
614
615        /* tss->tss_rsp0 */
616        tss->tss_ist[0] = ((uint64_t)&data->intr_stack + STKSIZE) & ~0xF;
617        tss->tss_ist[1] = ((uint64_t)&data->dbfl_stack + STKSIZE) & ~0xF;
618        tss->tss_ist[2] = ((uint64_t)&data->nmfl_stack + STKSIZE) & ~0xF;
619        tss->tss_iobase = IOMAP_INVALOFF << 16;
620        sel = tss_alloc(tss, lid);
621
622        /* Load it */
623        ltr(sel);
624}
625
626/* -------------------------------------------------------------------------- */
627
628void cpu_tls_init(size_t lid)
629{
630        extern uint64_t x86_syscall;
631        extern uint64_t x86_syscall32;
632
633        percpu_archdata_t *data = &cpudata[lid];
634        tls_t *cputls = &data->tls;
635
636        memset(cputls, 0, sizeof(tls_t));
637
638        cputls->tls_self = cputls;
639        cputls->tls_gid = hal_lapic_gid();
640        cputls->tls_lid = lid;
641        cputls->tls_intr = INTRS_DISABLED;
642
643        /* syscall */
644        wrmsr(MSR_STAR,
645            ((uint64_t)GDT_FIXED_SEL(GDT_KCODE_SEL, SEL_KPL) << 32) |
646            ((uint64_t)GDT_FIXED_SEL(GDT_UCODE32_SEL, SEL_UPL) << 48));
647        wrmsr(MSR_LSTAR, (uint64_t)&x86_syscall);
648        wrmsr(MSR_CSTAR, (uint64_t)&x86_syscall32);
649        wrmsr(MSR_SFMASK, PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D);
650
651        /* TLS */
652        wrmsr(MSR_FSBASE, 0);
653        wrmsr(MSR_GSBASE, (uint64_t)cputls);
654        wrmsr(MSR_KERNELGSBASE, 0);
655}
656
657/* -------------------------------------------------------------------------- */
658
659uint64_t cpu_features[4] __in_kdata;
660
661void cpu_identify()
662{
663        /*
664         * desc[0] = eax
665         * desc[1] = ebx
666         * desc[2] = ecx
667         * desc[3] = edx
668         */
669        uint32_t desc[4];
670        char vendor[13];
671        size_t lvl;
672
673        /*
674         * Get information from the standard cpuid leafs
675         */
676        cpuid(0, 0, (uint32_t *)&desc);
677
678        lvl = (uint64_t)desc[0];
679        x86_printf("-> cpuid standard level: %z\n", lvl);
680
681        memcpy(vendor + 0, &desc[1], sizeof(uint32_t));
682        memcpy(vendor + 8, &desc[2], sizeof(uint32_t));
683        memcpy(vendor + 4, &desc[3], sizeof(uint32_t));
684        vendor[12] = '\0';
685        x86_printf("-> CPU vendor: '%s'\n", vendor);
686
687        if (lvl >= 1) {
688                cpuid(1, 0, (uint32_t *)&desc);
689                cpu_features[0] = desc[3];
690                cpu_features[1] = desc[2];
691        }
692
693        /*
694         * Get information from the extended cpuid leafs
695         */
696        cpuid(0x80000000, 0, desc);
697
698        lvl = (uint64_t)desc[0];
699        x86_printf("-> cpuid extended level: %Z\n", lvl);
700}
701
702/* -------------------------------------------------------------------------- */
703
704void cpu_attach(size_t lid)
705{
706        /* Per-cluster structures */
707        cpu_load_gdt();
708        cpu_load_idt();
709
710        /* Per-cpu structures */
711        cpu_create_tss(lid);
712
713        if (cpu_features[0] & CPUID_PSE) {
714                lcr4(rcr4() | CR4_PSE);
715                tlbflushg();
716        } else {
717                /*
718                 * amd64 supports PSE by default, if it's not here we have a
719                 * problem
720                 */
721                x86_panic("PSE not supported");
722        }
723}
724
Note: See TracBrowser for help on using the repository browser.