Skip to content

Commit

Permalink
Changes to UEFI, ACPI, and VGA logic to support ASUS ZenBook
Browse files Browse the repository at this point in the history
  • Loading branch information
fintelia committed Sep 9, 2020
1 parent f4d6457 commit 8499a0b
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 116 deletions.
5 changes: 5 additions & 0 deletions include/multiboot.hh
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ struct multiboot_saved

// Only ever provided by multiboot2. Available if MULTIBOOT2_FLAG_EFI_SYSTEM_TABLE is set.
u64 efi_system_table;

u8 acpi_rsdpv1[20]; // If MULTIBOOT2_FLAG_ACPI_RSDP_V1 set
u8 acpi_rsdpv2[36]; // If MULTIBOOT2_FLAG_ACPI_RSDP_V2 set
};
extern multiboot_saved multiboot;

Expand All @@ -105,6 +108,8 @@ extern multiboot_saved multiboot;
#define MULTIBOOT_FLAG_VBE (1 << 11)
#define MULTIBOOT_FLAG_FRAMEBUFFER (1 << 12)

#define MULTIBOOT2_FLAG_ACPI_RSDP_V1 (1 << 27)
#define MULTIBOOT2_FLAG_ACPI_RSDP_V2 (1 << 28)
#define MULTIBOOT2_FLAG_EFI_IMAGE_HANDLE (1 << 29)
#define MULTIBOOT2_FLAG_EFI_MMAP (1 << 30)
#define MULTIBOOT2_FLAG_EFI_SYSTEM_TABLE (1 << 31)
Expand Down
2 changes: 1 addition & 1 deletion include/uefi.hh
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ struct efi_system_table {
void* console_err_handle;
void* console_err_prot;
efi_runtime_services* runtime_services;
paddr boot_services;
efi_boot_services* boot_services;
u64 num_table_entries;
void* configuration_table;
};
Expand Down
6 changes: 6 additions & 0 deletions kernel/acpiosl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern "C" {
#include "semaphore.hh"
#include "spinlock.hh"
#include "pci.hh"
#include "multiboot.hh"
#include <new>

// Environment
Expand All @@ -31,6 +32,11 @@ AcpiOsTerminate(void)
ACPI_PHYSICAL_ADDRESS
AcpiOsGetRootPointer(void)
{
if (multiboot.flags & MULTIBOOT2_FLAG_ACPI_RSDP_V2)
return v2p(multiboot.acpi_rsdpv2);
if (multiboot.flags & MULTIBOOT2_FLAG_ACPI_RSDP_V1)
return v2p(multiboot.acpi_rsdpv1);

ACPI_SIZE ret;
AcpiFindRootPointer(&ret);
return ret;
Expand Down
61 changes: 31 additions & 30 deletions kernel/hwvm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,16 @@ refresh_pcid_mask(void) {
}
}

// Create a direct mapping starting at PA 0 to VA KBASE up to
// KBASEEND. This augments the KCODE mapping created by the
// bootloader. Perform per-core control register set up.

void
initdirectmap()
{
int level = cpuid::features().page1GB ? pgmap::L_1G : pgmap::L_2M;
for (auto it = kpml4.find(KBASE, level); it.index() < KBASEEND; it += it.span()) {
*it.create(0) = (it.index() - KBASE) | PTE_W | PTE_P | PTE_PS | PTE_NX;
}
}

void
initpg(struct cpu *c)
{
Expand All @@ -410,12 +417,6 @@ initpg(struct cpu *c)
*kpml4.find(KTEXT, pgmap::L_2M).create(0) = v2p((void*)KTEXT) | PTE_P | PTE_PS;
reload_cr3();

// Create direct map region
for (auto it = kpml4.find(KBASE, level); it.index() < KBASEEND; it += it.span()) {
*it.create(0) = (it.index() - KBASE) | PTE_W | PTE_P | PTE_PS | PTE_NX;
}
assert(!kpml4.find(KBASEEND, level).is_set());

// Memory mapped I/O region might have MTRRs to set its caching mode, so we
// can't use 1GB pages. This also lets us set the framebuffer with write
// combining mappings.
Expand Down Expand Up @@ -452,27 +453,27 @@ initpg(struct cpu *c)
assert(!it.is_set());
}

// Create UEFI area.
if (multiboot.flags & MULTIBOOT2_FLAG_EFI_MMAP) {
for (int i = 0; i < multiboot.efi_mmap_descriptor_count; i++) {
auto d = (efi_memory_descriptor*)&multiboot.efi_mmap[multiboot.efi_mmap_descriptor_size*i];
if (!(d->attributes & EFI_MEMORY_RUNTIME))
continue;

u64 perm = PTE_P;
if (!(d->attributes & EFI_MEMORY_WB)) {
if (d->attributes & EFI_MEMORY_WT) perm |= PTE_PWT;
else if (d->attributes & EFI_MEMORY_UC) perm |= PTE_PCD;
else panic("No supported cache mode for region");
}
if (d->attributes & EFI_MEMORY_XP) perm |= PTE_NX;
if (!(d->attributes & EFI_MEMORY_WP)) perm |= PTE_W;

for (int offset = 0; offset < d->npages*PGSIZE; offset += PGSIZE) {
*kpml4.find(d->vaddr+offset).create(0) = (d->paddr + offset) | perm;
}
}
}
// // Create UEFI area.
// if (multiboot.flags & MULTIBOOT2_FLAG_EFI_MMAP) {
// for (int i = 0; i < multiboot.efi_mmap_descriptor_count; i++) {
// auto d = (efi_memory_descriptor*)&multiboot.efi_mmap[multiboot.efi_mmap_descriptor_size*i];
// if (!(d->attributes & EFI_MEMORY_RUNTIME))
// continue;

// u64 perm = PTE_P;
// if (!(d->attributes & EFI_MEMORY_WB)) {
// if (d->attributes & EFI_MEMORY_WT) perm |= PTE_PWT;
// else if (d->attributes & EFI_MEMORY_UC) perm |= PTE_PCD;
// else panic("No supported cache mode for region");
// }
// if (d->attributes & EFI_MEMORY_XP) perm |= PTE_NX;
// if (!(d->attributes & EFI_MEMORY_WP)) perm |= PTE_W;

// for (int offset = 0; offset < d->npages*PGSIZE; offset += PGSIZE) {
// *kpml4.find(d->vaddr+offset).create(0) = (d->paddr + offset) | perm;
// }
// }
// }

use_invpcid = cpuid::features().invpcid;

Expand Down
25 changes: 11 additions & 14 deletions kernel/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ void initcga(void);
void initvga(void);
void initdoublebuffer(void);
void initconsole(void);
void initdirectmap();
void initpg(struct cpu *c);
void inithz(void);
void cleanuppg(void);
Expand Down Expand Up @@ -91,10 +92,6 @@ mpboot(void)
for (size_t i = 0; i < __percpuinit_array_end - __percpuinit_array_start; i++)
(*__percpuinit_array_start[i])(bcpuid);

extern u64 text;
writefs(UDSEG);
writemsr(MSR_FS_BASE, (u64)&text);

initlapic();
inittsc();
initfpu();
Expand Down Expand Up @@ -185,22 +182,21 @@ cmain(u64 mbmagic, u64 mbaddr)
// in the image. *cpu and such won't work until we inittls.
percpu_offsets[0] = __percpu_start;

// Initialize trap handling
initseg(&cpus[0]);
inittls(&cpus[0]); // Requires initseg
inittrap();

// Initialize output
initmultiboot(mbmagic, mbaddr);
inithz();
inituart(); // Requires inithz
debugmultiboot(mbmagic, mbaddr);
initcmdline(); // Requires initmultiboot
initvga(); // Requires initmultiboot, initcmdline
initphysmem();
initdirectmap(); // Requires initmultiboot
initvga(); // Requires initcmdline, initdirectmap

// Initialize trap handling
initseg(&cpus[0]);
inittls(&cpus[0]); // Requires initseg
inittrap();

initphysmem(); // Requires initmultiboot
initpg(&cpus[0]); // Requires initphysmem
initvectoredtrap(); // Requires initpg
initpg(&cpus[0]); // Requires initphysmem, initvga
initdoublebuffer(); // Requires initpg
initacpitables(); // Requires initpg, inittls
initlapic(); // Requires initpg, inithz
Expand All @@ -210,6 +206,7 @@ cmain(u64 mbmagic, u64 mbaddr)
initpic(); // interrupt controller
initiommu(); // Requires initlapic
initextpic(); // Requires initpic
initvectoredtrap(); // Requires initpercpu
// Interrupt routing is now configured

inituartcons(); // Requires interrupt routing
Expand Down
56 changes: 55 additions & 1 deletion kernel/multiboot.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ struct multiboot2_efi_memory_map {
} descriptors[];
};

struct multiboot2_acpi_rsdpv1_tag {
u32 type;
u32 size;
u8 desc[20];
};

struct multiboot2_acpi_rsdpv2_tag {
u32 type;
u32 size;
u8 desc[36];
};

struct vesa_mode_info {
uint16_t mode_attr;
uint8_t win_attr[2];
Expand Down Expand Up @@ -122,6 +134,40 @@ struct vesa_mode_info {
uint8_t reserved[206];
} __attribute__ ((packed));

void multiboot2_early(u64 mbaddr, multiboot_saved* mb) {
multiboot2_info* info = (multiboot2_info*)mbaddr;
multiboot2_tag* t = (multiboot2_tag*)(mbaddr + sizeof(multiboot2_info));
void* end = (void*)(mbaddr + info->total_size);

while (t < end) {
if (t->type == 8) {
auto tag = (multiboot2_framebuffer_tag*)t;
mb->framebuffer = (u32*)p2v(tag->framebuffer_addr);
mb->framebuffer_pitch = tag->framebuffer_pitch;
mb->framebuffer_width = tag->framebuffer_width;
mb->framebuffer_height = tag->framebuffer_height;
mb->framebuffer_bpp = tag->framebuffer_bpp;
mb->framebuffer_red_field_position = tag->framebuffer_red_field_position;
mb->framebuffer_red_mask_size = tag->framebuffer_red_mask_size;
mb->framebuffer_green_field_position = tag->framebuffer_green_field_position;
mb->framebuffer_green_mask_size = tag->framebuffer_green_mask_size;
mb->framebuffer_blue_field_position = tag->framebuffer_blue_field_position;
mb->framebuffer_blue_mask_size = tag->framebuffer_blue_mask_size;
mb->flags |= MULTIBOOT_FLAG_FRAMEBUFFER;
} else if (t->type == 12) {
auto tag = (multiboot2_pointer_tag*)t;
mb->efi_system_table = tag->addr;
mb->flags |= MULTIBOOT2_FLAG_EFI_SYSTEM_TABLE;
} else if (t->type == 20) {
auto tag = (multiboot2_pointer_tag*)t;
mb->efi_image_handle = tag->addr;
mb->flags |= MULTIBOOT2_FLAG_EFI_IMAGE_HANDLE;
}

t = (multiboot2_tag*)((char*)t + ((t->size + 7) & ~7));
}
}

void initmultiboot(u64 mbmagic, u64 mbaddr) {
if (mbmagic == 0x2BADB002) {
// Multiboot 1
Expand Down Expand Up @@ -242,7 +288,15 @@ void initmultiboot(u64 mbmagic, u64 mbaddr) {
auto tag = (multiboot2_pointer_tag*)t;
multiboot.efi_system_table = tag->addr;
multiboot.flags |= MULTIBOOT2_FLAG_EFI_SYSTEM_TABLE;
} else if (t->type == 17) {
} else if (t->type == 14) {
auto tag = (multiboot2_acpi_rsdpv1_tag*)t;
memcpy(multiboot.acpi_rsdpv1, tag->desc, 20);
multiboot.flags |= MULTIBOOT2_FLAG_ACPI_RSDP_V1;
} else if (t->type == 15) {
auto tag = (multiboot2_acpi_rsdpv2_tag*)t;
memcpy(multiboot.acpi_rsdpv2, tag->desc, 36);
multiboot.flags |= MULTIBOOT2_FLAG_ACPI_RSDP_V2;
} else if (t->type == 17 && !(multiboot.flags & MULTIBOOT2_FLAG_EFI_MMAP)) {
auto tag = (multiboot2_efi_memory_map*)t;
multiboot.efi_mmap_descriptor_size = tag->descriptor_size;
multiboot.efi_mmap_descriptor_version = tag->descriptor_version;
Expand Down
107 changes: 37 additions & 70 deletions kernel/uefi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,88 +4,55 @@
#include "uefi.hh"
#include "multiboot.hh"
#include "cmdline.hh"
#include "amd64.h"

void multiboot2_early(u64 mbaddr, multiboot_saved* mb);

void initvga(void);
void initmultiboot(u64 mbmagic, u64 mbaddr);
extern u64 kpml4[];

extern "C" u64 efi_cmain (u64 mbmagic, u64 mbaddr, void* boot_system_table, void* boot_image_table)
{
// Copy lowest PTE from uefi page table to kpml4, then switch to it. This
// creates an identity mapping for the first 512 GB of memory.
extern u64 kpml4[];
u64* kpml4_cr3 = (u64*)v2p(kpml4);
u64* uefi_cr3 = (u64*)rcr3();
u64 kpml4_pte = kpml4_cr3[0];
kpml4_cr3[0] = uefi_cr3[0];
kpml4_cr3[(KUEFI >> 39) % 512] = kpml4_cr3[0];
lcr3((u64)kpml4_cr3);

initmultiboot(mbmagic, mbaddr);
cmdline_params.use_vga = true;
initvga();

cprintf("Booting in UEFI mode...\n");

auto system_table = (efi_system_table*)p2v(multiboot.efi_system_table);
auto boot_services = (efi_boot_services*)p2v((u64)system_table->boot_services);
EFI_GET_MEMORY_MAP get_memory_map = boot_services->get_memory_map;
EFI_EXIT_BOOT_SERVICES exit_boot_services = boot_services->exit_boot_services;

u64 key, ret=1;
u64 map = v2p(multiboot.efi_mmap);
u64 map_size = sizeof(multiboot.efi_mmap);
while (ret) {
ret = get_memory_map(&map_size, (efi_memory_descriptor*)map, &key,
&multiboot.efi_mmap_descriptor_size,
&multiboot.efi_mmap_descriptor_version);
if (ret) {
cprintf("ERROR: get_memory_map returned %lx\n", ret);
continue;
}

multiboot.efi_mmap_descriptor_count = map_size / multiboot.efi_mmap_descriptor_size;
multiboot.flags |= MULTIBOOT2_FLAG_EFI_MMAP;

ret = exit_boot_services((void*)multiboot.efi_image_handle, key);
if (ret) {
cprintf("ERROR: exit_boot_services returned %lx\n", ret);
} else {
multiboot.flags |= MULTIBOOT2_FLAG_EFI_IMAGE_HANDLE;
cprintf("Exited boot services\n");
}
break;
}

for (int i = 0; i < multiboot.efi_mmap_descriptor_count; i++) {
auto d = (efi_memory_descriptor*)&multiboot.efi_mmap[multiboot.efi_mmap_descriptor_size*i];
d->vaddr = (d->attributes & EFI_MEMORY_RUNTIME) ? d->paddr + KUEFI : 0;
multiboot_saved* mb = (multiboot_saved*)v2p(&multiboot);
multiboot2_early(mbaddr, mb);
efi_system_table* system_table = (efi_system_table*)mb->efi_system_table;

auto get_memory_map = system_table->boot_services->get_memory_map;
auto exit_boot_services = system_table->boot_services->exit_boot_services;


u64 key;
auto mem_descs = (efi_memory_descriptor*)&mb->efi_mmap[0];
u64 map_size = sizeof(mb->efi_mmap);
while (get_memory_map(&map_size, mem_descs, &key,
&mb->efi_mmap_descriptor_size,
&mb->efi_mmap_descriptor_version) ||
exit_boot_services((void*)mb->efi_image_handle, key)) {
// Retry
}
mb->flags |= MULTIBOOT2_FLAG_EFI_MMAP;
mb->efi_mmap_descriptor_count = map_size / mb->efi_mmap_descriptor_size;

// auto set_virtual_address_map = system_table->runtime_services->set_virtual_address_map;
// for (int i = 0; i < mb->efi_mmap_descriptor_count; i++) {
// auto d = (efi_memory_descriptor*)&mb->efi_mmap[mb->efi_mmap_descriptor_size*i];
// d->vaddr = (d->attributes & EFI_MEMORY_RUNTIME) ? d->paddr + KUEFI : 0;
// }
// set_virtual_address_map(map_size,
// mb->efi_mmap_descriptor_size,
// mb->efi_mmap_descriptor_version,
// mem_descs);

auto runtime_services = (efi_runtime_services*)p2v((u64)system_table->runtime_services);
ret = (runtime_services->set_virtual_address_map)(map_size, multiboot.efi_mmap_descriptor_size,
multiboot.efi_mmap_descriptor_version,
(efi_memory_descriptor*)map);

// Restore kpml4 so other code doesn't get confused.
kpml4_cr3[0] = kpml4_pte;
kpml4_cr3[(KUEFI >> 39) % 512] = 0;
lcr3((u64)kpml4_cr3);
// These both normally happen in init32e, but that doesn't run in EFI mode.
writemsr(0xc0000080, readmsr(0xc0000080) | (1<<0) | (1<<11));
lcr4(rcr4() | 0x630); // Set CR4.PAE = CR4.PSE = CR4.OSFXSR = CR4.OSXMMEXCPT = 1.

cprintf("Loading gdt\n");
volatile struct desctr dtr;
dtr.limit = sizeof(bootgdt) - 1;
dtr.base = (u64)bootgdt;
lgdt((void*)&dtr.limit);

// These both normally happen in init32e, but that doesn't run in EFI mode.
cprintf("Initializing IA32_EFER and CR4\n");
writemsr(0xc0000080, readmsr(0xc0000080) | (1<<0) | (1<<11));
lcr4(rcr4() | 0x630); // Set CR4.PAE = CR4.PSE = CR4.OSFXSR = CR4.OSXMMEXCPT = 1.

cprintf("Switching to high addresses\n");
__asm volatile("add %0, %%rsp; movabs $1f, %%rax; jmp *%%rax; 1:" :: "r"(KBASE) : "rax", "memory");

cprintf("About to call cmain(%lx, %lx)\n", mbmagic, mbaddr);
__asm volatile("movabs $(kpml4-%a1), %%rax; mov %%rax, %%cr3; add %0, %%rsp; movabs $1f, %%rax; jmp *%%rax; 1:"
:: "r"(KBASE), "i"(KCODE) : "rax", "memory");
cmain(mbmagic, mbaddr);
panic("cmain should not return?");

Expand Down

0 comments on commit 8499a0b

Please sign in to comment.