From 5c2f21b427878c01c75c2fef04283e960a89e5c3 Mon Sep 17 00:00:00 2001 From: Rian Quinn Date: Sat, 20 Feb 2021 06:55:14 -0700 Subject: [PATCH] add support for more than 64 cores --- kernel/src/mk_main.hpp | 3 +- loader/src/start_vmm.c | 1 - loader/src/start_vmm_per_cpu.c | 1 - loader/src/x64/map_4k_page.c | 81 +++++++--------------------------- loader/windows/src/platform.c | 52 ++++++++++++++++------ 5 files changed, 57 insertions(+), 81 deletions(-) diff --git a/kernel/src/mk_main.hpp b/kernel/src/mk_main.hpp index 10eeadbe..d7ea324b 100644 --- a/kernel/src/mk_main.hpp +++ b/kernel/src/mk_main.hpp @@ -441,12 +441,13 @@ namespace mk // [x] implement error on VMX instructions on Intel // [x] implement error on SVM instructions on AMD // [ ] implement fix for vmexit first crash (vmxoff and check state) + // [x] implement fix for 128 cores on Windows // [x] implement alloc page // [ ] implement free page // [x] implement virt_to_phys // [ ] implement make ack // [ ] implement debugging mutex/transaction support - // [ ] implement Windows support + // [x] implement Windows support // [ ] implement UEFI support // [ ] implement huge_pool // [ ] implement huge diff --git a/loader/src/start_vmm.c b/loader/src/start_vmm.c index 1b6aa986..269f069e 100644 --- a/loader/src/start_vmm.c +++ b/loader/src/start_vmm.c @@ -166,7 +166,6 @@ alloc_and_start_the_vmm(struct start_vmm_args_t const *const args) } g_vmm_status = VMM_STATUS_RUNNING; - return LOADER_SUCCESS; start_vmm_per_cpu_failed: diff --git a/loader/src/start_vmm_per_cpu.c b/loader/src/start_vmm_per_cpu.c index a52e3655..91fdfb1d 100644 --- a/loader/src/start_vmm_per_cpu.c +++ b/loader/src/start_vmm_per_cpu.c @@ -59,7 +59,6 @@ #include #include #include -#include #include /** diff --git a/loader/src/x64/map_4k_page.c b/loader/src/x64/map_4k_page.c index 908709c5..84d54a27 100644 --- a/loader/src/x64/map_4k_page.c +++ b/loader/src/x64/map_4k_page.c @@ -43,46 +43,6 @@ #include #include -/** - * - * @brief The microkernel needs to be able to walk its own page tables and - * to do that, it expects the that all of the page tables are mapped in - * the direct map (allowing the microkernel to look up a virtual address - * given a physical address). When the map function maps a virtual address, - * it might be required to allocate new page tables. These newly allocated - * page tables are recorded and mapped once the map function is complete - * using this function. - * - * - * @param virt the virtual address of the page table - * @param pml4t the root page table to place the resulting map - * @return 0 on success, LOADER_FAILURE on failure. - */ -int64_t -map_4k_page_table(void const *const virt, struct pml4t_t *const pml4t) -{ - uint64_t phys; - uint64_t const base_virt = HYPERVISOR_DIRECT_MAP_ADDR; - bfelf_elf64_word const rw = bfelf_pf_w | bfelf_pf_r; - - if (((void *)0) == virt) { - return LOADER_SUCCESS; - } - - phys = platform_virt_to_phys(virt); - if (((uint64_t)0) == phys) { - BFERROR("platform_virt_to_phys failed\n"); - return LOADER_FAILURE; - } - - if (map_4k_page(phys + base_virt, phys, rw, pml4t)) { - BFERROR("map_4k_page failed\n"); - return LOADER_FAILURE; - } - - return LOADER_SUCCESS; -} - /** * * @brief This function maps a 4k page given a physical address into a @@ -112,9 +72,21 @@ map_4k_page( struct pt_t *pt = ((void *)0); struct pte_t *pte = ((void *)0); - void *pdpt_to_map = ((void *)0); - void *pdt_to_map = ((void *)0); - void *pt_to_map = ((void *)0); + /** + * TODO: + * - We need to map in any page tables that we allocate. The problem is, + * we cannot use a recursive function to do this as it could result + * in a stack overflow in the kernel. Likely, the best option would + * be to convert this function into a private _impl, and provide it + * with a queue that we can push allocated pages to so that the wrapper + * can map any pages that are pushed. This way, as we map, we can + * continue to push pages until the process finally stops. Since this + * code is common between Windows/Linux/UEFI, we will need to implement + * this queue from scratch. For now, we seem to be ok without this + * additional logic, but it is possible that the microkernel could end + * up with a page fault while it is trying to walk page tables as it + * wouldn't have all of the memory properly mapped. + */ if ((virt & (HYPERVISOR_PAGE_SIZE - ((uint64_t)1))) != ((uint64_t)0)) { BFERROR("virt is not page aligned: 0x%" PRIx64 "\n", virt); @@ -137,24 +109,22 @@ map_4k_page( pdpt = pml4t->tables[pml4to(virt)]; if (((void *)0) == pdpt) { pdpt = alloc_pdpt(pml4t, virt); - pdpt_to_map = pdpt; } pdt = pdpt->tables[pdpto(virt)]; if (((void *)0) == pdt) { pdt = alloc_pdt(pdpt, virt); - pdt_to_map = pdt; } pt = pdt->tables[pdto(virt)]; if (((void *)0) == pt) { pt = alloc_pt(pdt, virt); - pt_to_map = pt; } pte = &pt->entires[pto(virt)]; if (pte->p != ((uint64_t)0)) { - goto SUCCESS; + BFERROR("virt already mapped: 0x%" PRIx64 "\n", virt); + return LOADER_FAILURE; } pte->phys = (phys >> HYPERVISOR_PAGE_SHIFT); @@ -169,22 +139,5 @@ map_4k_page( pte->nx = ((uint64_t)1); } -SUCCESS: - - if (map_4k_page_table(pdpt_to_map, pml4t)) { - BFERROR("map_4k_page_table failed\n"); - return LOADER_FAILURE; - } - - if (map_4k_page_table(pdt_to_map, pml4t)) { - BFERROR("map_4k_page_table failed\n"); - return LOADER_FAILURE; - } - - if (map_4k_page_table(pt_to_map, pml4t)) { - BFERROR("map_4k_page_table failed\n"); - return LOADER_FAILURE; - } - return LOADER_SUCCESS; } diff --git a/loader/windows/src/platform.c b/loader/windows/src/platform.c index 269661d8..3e1966d6 100644 --- a/loader/windows/src/platform.c +++ b/loader/windows/src/platform.c @@ -303,8 +303,7 @@ platform_copy_to_user( uint32_t platform_num_online_cpus(void) { - KAFFINITY k_affin; - return KeQueryActiveProcessorCount(&k_affin); + return KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS); } /** @@ -324,17 +323,30 @@ platform_num_online_cpus(void) static int64_t platform_on_each_cpu_forward(platform_per_cpu_func const func) { + (void)func; int64_t ret = 0; - uint32_t cpu; - for (cpu = 0; cpu < platform_num_online_cpus(); ++cpu) { - KAFFINITY old = KeSetSystemAffinityThreadEx(1ULL << cpu); - ret = func(cpu); - KeRevertToUserAffinityThreadEx(old); + ULONG Count; + ULONG ProcIndex; + PROCESSOR_NUMBER ProcNumber; + + Count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS); + for (ProcIndex = 0; ProcIndex < Count; ++ProcIndex) { + GROUP_AFFINITY affinity = {0}; + GROUP_AFFINITY previous = {0}; + + KeGetProcessorNumberFromIndex(ProcIndex, &ProcNumber); + + affinity.Mask = (1ULL << ProcNumber.Number); + affinity.Group = ProcNumber.Group; + + KeSetSystemGroupAffinityThread(&affinity, &previous); + ret = func(ProcIndex); + KeRevertToUserGroupAffinityThread(&previous); if (ret) { BFERROR("platform_per_cpu_func failed\n"); - break; + return ret; } } @@ -359,16 +371,28 @@ static int64_t platform_on_each_cpu_reverse(platform_per_cpu_func const func) { int64_t ret = 0; - uint32_t cpu; - for (cpu = platform_num_online_cpus(); cpu > 0U; --cpu) { - KAFFINITY old = KeSetSystemAffinityThreadEx(1ULL << (cpu - 1U)); - ret = func(cpu - 1U); - KeRevertToUserAffinityThreadEx(old); + ULONG Count; + ULONG ProcIndex; + PROCESSOR_NUMBER ProcNumber; + + Count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS); + for (ProcIndex = Count; ProcIndex > 0; --ProcIndex) { + GROUP_AFFINITY affinity = {0}; + GROUP_AFFINITY previous = {0}; + + KeGetProcessorNumberFromIndex(ProcIndex - 1, &ProcNumber); + + affinity.Mask = (1ULL << ProcNumber.Number); + affinity.Group = ProcNumber.Group; + + KeSetSystemGroupAffinityThread(&affinity, &previous); + ret = func(ProcIndex - 1); + KeRevertToUserGroupAffinityThread(&previous); if (ret) { BFERROR("platform_per_cpu_func failed\n"); - break; + return ret; } }