From 4965c38de95a9486a61c35e880f9a911d63b7200 Mon Sep 17 00:00:00 2001 From: Thomas Oltmann Date: Tue, 11 Mar 2025 18:46:10 +0100 Subject: [PATCH] Per-processor GDT & IDT --- Makefile | 1 + include/x86/gdt.h | 25 +++++++++++++++++++ include/x86/idt.h | 23 ++++++++++++++++++ run.sh | 3 +++ src/bootstrap.h | 3 +++ src/efi.c | 15 +++++++++++- src/proc.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++ src/procvisor.h | 37 ++++++++++++++++++++++++++++ src/vintel.c | 1 + src/vsegment.h | 5 ++++ 10 files changed, 174 insertions(+), 1 deletion(-) create mode 100755 run.sh create mode 100644 src/bootstrap.h create mode 100644 src/proc.c create mode 100644 src/procvisor.h create mode 100644 src/vsegment.h diff --git a/Makefile b/Makefile index cd956b5..d2132c4 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ CFLAGS += -ggdb # preferentially in alphabetical order. VISOR_SOURCES_x86_64 := \ src/vintel.c \ + src/proc.c \ # end of x86_64 specific sources list # Architecture-agnostic kernel sources. diff --git a/include/x86/gdt.h b/include/x86/gdt.h index cd17a48..6eaf402 100644 --- a/include/x86/gdt.h +++ b/include/x86/gdt.h @@ -3,6 +3,18 @@ #include +__attribute__ ((packed)) +struct segdescr { + uint16_t limit0; + uint16_t base0; + uint8_t base1; + uint8_t access; + uint8_t flags; + uint16_t base2; + uint32_t base3; + uint32_t reserved; +}; + __attribute__ ((packed)) struct GDTR { uint16_t limit; @@ -17,4 +29,17 @@ storegdt(void) return gdtr; } +static inline void +setsegdescr(struct segdescr *descr, uint64_t base, uint32_t limit, uint8_t access, uint8_t flags) +{ + descr->limit0 = limit; + descr->base0 = base; + descr->base1 = base >> 16; + descr->access = access; + descr->flags = flags | (limit >> 16); + descr->base2 = base >> 24; + descr->base3 = base >> 32; + descr->reserved = 0; +} + #endif diff --git a/include/x86/idt.h b/include/x86/idt.h index ae4c20f..4a2a5c4 100644 --- a/include/x86/idt.h +++ b/include/x86/idt.h @@ -3,6 +3,17 @@ #include +__attribute__ ((packed)) +struct intdescr { + uint16_t offset0; + uint16_t seg; + uint8_t ist; + uint8_t access; + uint16_t offset1; + uint32_t offset2; + uint32_t reserved; +}; + __attribute__ ((packed)) struct IDTR { uint16_t limit; @@ -17,4 +28,16 @@ storeidt(void) return idtr; } +static inline void +setintdescr(struct intdescr *descr, uint64_t offset, uint16_t seg, uint8_t ist, uint8_t access) +{ + descr->offset0 = offset; + descr->seg = seg; + descr->ist = ist; + descr->access = access; + descr->offset1 = offset >> 16; + descr->offset2 = offset >> 32; + descr->reserved = 0; +} + #endif diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..63863fc --- /dev/null +++ b/run.sh @@ -0,0 +1,3 @@ +#!/bin/sh +OVMF_BLOB=/usr/share/OVMF/x64/OVMF.fd +uefi-run -d -b "$OVMF_BLOB" build/visor -- -enable-kvm -cpu host "$@" diff --git a/src/bootstrap.h b/src/bootstrap.h new file mode 100644 index 0000000..1f3c93b --- /dev/null +++ b/src/bootstrap.h @@ -0,0 +1,3 @@ +#include + +void *bs_alloc(size_t size); diff --git a/src/efi.c b/src/efi.c index 8d93257..d853e01 100644 --- a/src/efi.c +++ b/src/efi.c @@ -4,18 +4,31 @@ #include #include "virt.h" +#include "bootstrap.h" +#include "procvisor.h" struct virt_vtable *virt = &virt_vtable_intel; static char virt_err[100]; +void * +bs_alloc(size_t size) +{ + size_t npages = (size + (4096 - 1)) / 4096; + void *ptr; + uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiRuntimeServicesData, npages, &ptr); + return ptr; +} + EFIAPI EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE *systemTable) { InitializeLib(imageHandle, systemTable); - Print(L"Hello, World!\n"); + AsciiPrint("* Setting up processor structures\n"); + struct procvisor *pv = proc_setup(); + (void)pv; AsciiPrint("* Checking for VT-x Support\n"); if (!virt->has_support(virt_err, sizeof virt_err)) { diff --git a/src/proc.c b/src/proc.c new file mode 100644 index 0000000..add365d --- /dev/null +++ b/src/proc.c @@ -0,0 +1,62 @@ +#include +#include +#include "procvisor.h" +#include "bootstrap.h" + +#define GDT_SIZE ( 3 * sizeof (struct segdescr)) +#define IDT_SIZE (256 * sizeof (struct intdescr)) + +struct procvisor *procvisors[256]; + +static void +proc_fill_host_gdt(struct GDTR gdtr) +{ + struct segdescr *descrs = (void *)gdtr.base; + setsegdescr(&descrs[0], 0, 0, 0, 0); // null + setsegdescr(&descrs[1], 0, 0xffffff, 0x9B, 0xA0); // code + setsegdescr(&descrs[2], 0, 0xffffff, 0x93, 0xC0); // data +} + +static void +proc_fill_host_idt(struct IDTR idtr) +{ + struct intdescr *descrs = (void *)idtr.base; + for (int i = 0; i < 256; i++) { + setintdescr(&descrs[i], 0, 0, 0, 0); + } +} + +struct procvisor * +proc_setup(void) +{ + // Allocate 2M region for per-processor stuff + char *region = bs_alloc(PROC_REGION_SIZE); + char *top = region + PROC_REGION_SIZE; + + // Carve out struct procvisor + top -= sizeof (struct procvisor); + struct procvisor *pv = (void *)top; + + // Carve out GDT + top -= GDT_SIZE; + pv->host_gdtr.base = (uintptr_t)top; + pv->host_gdtr.limit = GDT_SIZE - 1; + + // Carve out IDT + top -= IDT_SIZE; + pv->host_idtr.base = (uintptr_t)top; + pv->host_idtr.limit = IDT_SIZE - 1; + + // Leave the rest as stack + top -= ((uintptr_t)top & 0xf); // align on 16-byte boundary + pv->host_stack = top; + + // Fill out GDT & IDT structures + proc_fill_host_gdt(pv->host_gdtr); + proc_fill_host_idt(pv->host_idtr); + + // Register procvisor & return + unsigned procid = myprocid(); + procvisors[procid] = pv; + return pv; +} diff --git a/src/procvisor.h b/src/procvisor.h new file mode 100644 index 0000000..a710c0d --- /dev/null +++ b/src/procvisor.h @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +#define PROC_REGION_SIZE (512 * 4096) + +/* Per-processor visor state and structures */ +struct procvisor { + void *host_stack; + struct GDTR host_gdtr; + struct IDTR host_idtr; + //void *host_cr3; + //void *vmctl; +}; + +extern struct procvisor *procvisors[256]; + +/* Get our own LAPIC ID -- the slow way ... */ +static inline unsigned +myprocid(void) +{ + unsigned info[4]; + __get_cpuid(0x1, &info[0], &info[1], &info[2], &info[3]); + unsigned procid = info[1] >> 24; + return procid; +} + +static inline struct procvisor * +myprocvisor(void) +{ + unsigned procid = myprocid(); + if (procid >= 256) return NULL; + return procvisors[procid]; +} + +struct procvisor *proc_setup(void); diff --git a/src/vintel.c b/src/vintel.c index 349d4e7..444d274 100644 --- a/src/vintel.c +++ b/src/vintel.c @@ -211,6 +211,7 @@ vintel_enable(void) Print(L"Extended VMX Error\n"); } + // FIXME Allocate the correct amount of space! Print(L"Allocating VMCS Page\n"); uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiRuntimeServicesData, 1, &vmcs_region); diff --git a/src/vsegment.h b/src/vsegment.h new file mode 100644 index 0000000..c3bea92 --- /dev/null +++ b/src/vsegment.h @@ -0,0 +1,5 @@ +struct vsegment { + uint64_t gpa; + uint64_t ha; + uint64_t count; +};