Per-processor GDT & IDT

This commit is contained in:
Thomas Oltmann 2025-03-11 18:46:10 +01:00
parent 3704e95c64
commit 4965c38de9
10 changed files with 174 additions and 1 deletions

View file

@ -9,6 +9,7 @@ CFLAGS += -ggdb
# preferentially in alphabetical order. # preferentially in alphabetical order.
VISOR_SOURCES_x86_64 := \ VISOR_SOURCES_x86_64 := \
src/vintel.c \ src/vintel.c \
src/proc.c \
# end of x86_64 specific sources list # end of x86_64 specific sources list
# Architecture-agnostic kernel sources. # Architecture-agnostic kernel sources.

View file

@ -3,6 +3,18 @@
#include <stdint.h> #include <stdint.h>
__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)) __attribute__ ((packed))
struct GDTR { struct GDTR {
uint16_t limit; uint16_t limit;
@ -17,4 +29,17 @@ storegdt(void)
return gdtr; 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 #endif

View file

@ -3,6 +3,17 @@
#include <stdint.h> #include <stdint.h>
__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)) __attribute__ ((packed))
struct IDTR { struct IDTR {
uint16_t limit; uint16_t limit;
@ -17,4 +28,16 @@ storeidt(void)
return idtr; 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 #endif

3
run.sh Executable file
View file

@ -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 "$@"

3
src/bootstrap.h Normal file
View file

@ -0,0 +1,3 @@
#include <stddef.h>
void *bs_alloc(size_t size);

View file

@ -4,18 +4,31 @@
#include <efilib.h> #include <efilib.h>
#include "virt.h" #include "virt.h"
#include "bootstrap.h"
#include "procvisor.h"
struct virt_vtable *virt = &virt_vtable_intel; struct virt_vtable *virt = &virt_vtable_intel;
static char virt_err[100]; 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 EFIAPI
EFI_STATUS EFI_STATUS
efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE *systemTable) efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE *systemTable)
{ {
InitializeLib(imageHandle, 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"); AsciiPrint("* Checking for VT-x Support\n");
if (!virt->has_support(virt_err, sizeof virt_err)) { if (!virt->has_support(virt_err, sizeof virt_err)) {

62
src/proc.c Normal file
View file

@ -0,0 +1,62 @@
#include <x86/idt.h>
#include <x86/gdt.h>
#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;
}

37
src/procvisor.h Normal file
View file

@ -0,0 +1,37 @@
#include <stddef.h>
#include <cpuid.h>
#include <x86/gdt.h>
#include <x86/idt.h>
#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);

View file

@ -211,6 +211,7 @@ vintel_enable(void)
Print(L"Extended VMX Error\n"); Print(L"Extended VMX Error\n");
} }
// FIXME Allocate the correct amount of space!
Print(L"Allocating VMCS Page\n"); Print(L"Allocating VMCS Page\n");
uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiRuntimeServicesData, 1, &vmcs_region); uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiRuntimeServicesData, 1, &vmcs_region);

5
src/vsegment.h Normal file
View file

@ -0,0 +1,5 @@
struct vsegment {
uint64_t gpa;
uint64_t ha;
uint64_t count;
};