From 9ba143a5d09d1da4befaf5d4440bacb0c95a4e08 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Wed, 19 Aug 2020 14:44:25 -0500 Subject: [PATCH] riscv64: Finish initial work on an EFI loader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ia386d9155dda37ff6608a33dee349bf5332890c3 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3162 Reviewed-by: Alex von Gluck IV Reviewed-by: François Revol --- src/system/boot/arch/riscv64/Jamfile | 3 +- src/system/boot/arch/riscv64/kernel_stubs.cpp | 61 +++++++ .../boot/platform/efi/arch/riscv64/Jamfile | 9 +- .../platform/efi/arch/riscv64/arch_mmu.cpp | 10 ++ .../platform/efi/arch/riscv64/arch_smp.cpp | 72 ++++++++ .../platform/efi/arch/riscv64/arch_start.cpp | 97 +++++++++++ .../efi/arch/riscv64/crt0-efi-riscv64.S | 156 ++++++++++++++++++ .../boot/platform/efi/arch/riscv64/entry.S | 35 ++++ .../efi/arch/riscv64/relocation_func.cpp | 2 +- .../ldscripts/riscv64/boot_loader_efi.ld | 4 + 10 files changed, 443 insertions(+), 6 deletions(-) create mode 100644 src/system/boot/arch/riscv64/kernel_stubs.cpp create mode 100644 src/system/boot/platform/efi/arch/riscv64/arch_mmu.cpp create mode 100644 src/system/boot/platform/efi/arch/riscv64/arch_smp.cpp create mode 100644 src/system/boot/platform/efi/arch/riscv64/arch_start.cpp create mode 100644 src/system/boot/platform/efi/arch/riscv64/crt0-efi-riscv64.S create mode 100644 src/system/boot/platform/efi/arch/riscv64/entry.S diff --git a/src/system/boot/arch/riscv64/Jamfile b/src/system/boot/arch/riscv64/Jamfile index c8dd186300..3b546c9f52 100644 --- a/src/system/boot/arch/riscv64/Jamfile +++ b/src/system/boot/arch/riscv64/Jamfile @@ -22,7 +22,6 @@ local kernelDebugSources = local kernelArchDriverSources = arch_elf.cpp - arch_cpu.cpp # Serial UART Drivers #arch_uart_8250.cpp @@ -42,6 +41,8 @@ for platform in [ MultiBootSubDirSetup u-boot efi ] { $(kernelDebugSources) $(kernelArchDriverSources) $(kernelGenericDriverSources) + arch_cpu.cpp + kernel_stubs.cpp : # additional flags : $(kernelArchObjects) diff --git a/src/system/boot/arch/riscv64/kernel_stubs.cpp b/src/system/boot/arch/riscv64/kernel_stubs.cpp new file mode 100644 index 0000000000..817b779e2c --- /dev/null +++ b/src/system/boot/arch/riscv64/kernel_stubs.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ + +// This file just collects stubs that allow kernel sources to be used in the +// bootloader more easily. + +#include +#include +#include + + +extern "C" bool +in_command_invocation() +{ + return false; +} + + +extern "C" void +abort_debugger_command() +{ +} + + +extern "C" char +kgetc() +{ + return -1; +} + + +extern "C" status_t +_mutex_lock(mutex*, void*) +{ + return B_OK; +} + + +extern "C" void +_mutex_unlock(mutex*) +{ +} + + +#ifdef ATOMIC_FUNCS_ARE_SYSCALLS + +/* needed by packagefs */ +extern "C" int32 +atomic_add(vint32 *value, int32 addValue) +{ + int32 old = *value; + *value += addValue; + return old; +} + +#endif /*ATOMIC_FUNCS_ARE_SYSCALLS*/ diff --git a/src/system/boot/platform/efi/arch/riscv64/Jamfile b/src/system/boot/platform/efi/arch/riscv64/Jamfile index b14e789269..464c7e47ae 100644 --- a/src/system/boot/platform/efi/arch/riscv64/Jamfile +++ b/src/system/boot/platform/efi/arch/riscv64/Jamfile @@ -11,11 +11,12 @@ for platform in [ MultiBootSubDirSetup efi ] { local arch_src = crt0-efi-$(TARGET_ARCH).S - #entry.S + entry.S relocation_func.cpp - #arch_smp.cpp - #arch_mmu.cpp - #arch_timer.cpp + arch_start.cpp + arch_smp.cpp + arch_mmu.cpp + arch_timer.cpp ; BootMergeObject boot_platform_efi_riscv64.o : diff --git a/src/system/boot/platform/efi/arch/riscv64/arch_mmu.cpp b/src/system/boot/platform/efi/arch/riscv64/arch_mmu.cpp new file mode 100644 index 0000000000..9a86a8590b --- /dev/null +++ b/src/system/boot/platform/efi/arch/riscv64/arch_mmu.cpp @@ -0,0 +1,10 @@ +/* + * Copyright 2019-2020 Haiku, Inc. All rights reserved. + * Released under the terms of the MIT License. + */ + +void +arch_mmu_init() +{ + // Stub +} diff --git a/src/system/boot/platform/efi/arch/riscv64/arch_smp.cpp b/src/system/boot/platform/efi/arch/riscv64/arch_smp.cpp new file mode 100644 index 0000000000..84e25b57ac --- /dev/null +++ b/src/system/boot/platform/efi/arch/riscv64/arch_smp.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2019-2020, Haiku, Inc. All rights reserved. + * Released under the terms of the MIT License. +*/ + + +#include "arch_smp.h" + +#include + +#include + +#include +#include +#include +#include +#include + + +//#define TRACE_SMP +#ifdef TRACE_SMP +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +int +arch_smp_get_current_cpu(void) +{ + // One cpu for now. + return 0; +} + + +void +arch_smp_init_other_cpus(void) +{ + // One cpu for now. + gKernelArgs.num_cpus = 1; + return; +} + + +void +arch_smp_boot_other_cpus(uint32 pml4, uint64 kernel_entry) +{ + // One cpu for now. +} + + +void +arch_smp_add_safemode_menus(Menu *menu) +{ + MenuItem *item; + + if (gKernelArgs.num_cpus < 2) + return; + + item = new(nothrow) MenuItem("Disable SMP"); + menu->AddItem(item); + item->SetData(B_SAFEMODE_DISABLE_SMP); + item->SetType(MENU_ITEM_MARKABLE); + item->SetHelpText("Disables all but one CPU core."); +} + + +void +arch_smp_init(void) +{ + // One cpu for now. +} diff --git a/src/system/boot/platform/efi/arch/riscv64/arch_start.cpp b/src/system/boot/platform/efi/arch/riscv64/arch_start.cpp new file mode 100644 index 0000000000..17a25044f7 --- /dev/null +++ b/src/system/boot/platform/efi/arch/riscv64/arch_start.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2019-2020 Haiku, Inc. All rights reserved. + * Released under the terms of the MIT License. + */ + + +#include +#include +#include + +#include "efi_platform.h" + + +extern "C" void arch_enter_kernel(struct kernel_args *kernelArgs, + addr_t kernelEntry, addr_t kernelStackTop); + +void +arch_start_kernel(addr_t kernelEntry) +{ + // Prepare to exit EFI boot services. + // Read the memory map. + // First call is to determine the buffer size. + size_t memory_map_size = 0; + efi_memory_descriptor dummy; + efi_memory_descriptor *memory_map; + size_t map_key; + size_t descriptor_size; + uint32_t descriptor_version; + if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key, + &descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) { + panic("Unable to determine size of system memory map"); + } + + // Allocate a buffer twice as large as needed just in case it gets bigger + // between calls to ExitBootServices. + size_t actual_memory_map_size = memory_map_size * 2; + memory_map + = (efi_memory_descriptor *)kernel_args_malloc(actual_memory_map_size); + + if (memory_map == NULL) + panic("Unable to allocate memory map."); + + // Read (and print) the memory map. + memory_map_size = actual_memory_map_size; + if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, + &descriptor_size, &descriptor_version) != EFI_SUCCESS) { + panic("Unable to fetch system memory map."); + } + + addr_t addr = (addr_t)memory_map; + dprintf("System provided memory map:\n"); + for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) { + efi_memory_descriptor *entry + = (efi_memory_descriptor *)(addr + i * descriptor_size); + dprintf(" %#lx-%#lx %#lx %#x %#lx\n", entry->PhysicalStart, + entry->PhysicalStart + entry->NumberOfPages * B_PAGE_SIZE, + entry->VirtualStart, entry->Type, entry->Attribute); + } + + // Attempt to fetch the memory map and exit boot services. + // This needs to be done in a loop, as ExitBootServices can change the + // memory map. + // Even better: Only GetMemoryMap and ExitBootServices can be called after + // the first call to ExitBootServices, as the firmware is permitted to + // partially exit. This is why twice as much space was allocated for the + // memory map, as it's impossible to allocate more now. + // A changing memory map shouldn't affect the generated page tables, as + // they only needed to know about the maximum address, not any specific + // entry. + dprintf("Calling ExitBootServices. So long, EFI!\n"); + while (true) { + if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) { + // The console was provided by boot services, disable it. + stdout = NULL; + stderr = NULL; + // Can we adjust gKernelArgs.platform_args.serial_base_ports[0] + // to something fixed in qemu for debugging? + break; + } + + memory_map_size = actual_memory_map_size; + if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, + &descriptor_size, &descriptor_version) != EFI_SUCCESS) { + panic("Unable to fetch system memory map."); + } + } + + // Update EFI, generate final kernel physical memory map, etc. + //arch_mmu_post_efi_setup(memory_map_size, memory_map, + // descriptor_size, descriptor_version); + + //smp_boot_other_cpus(final_pml4, kernelEntry); + + // Enter the kernel! + arch_enter_kernel(&gKernelArgs, kernelEntry, + gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size); +} diff --git a/src/system/boot/platform/efi/arch/riscv64/crt0-efi-riscv64.S b/src/system/boot/platform/efi/arch/riscv64/crt0-efi-riscv64.S new file mode 100644 index 0000000000..6b034e8a62 --- /dev/null +++ b/src/system/boot/platform/efi/arch/riscv64/crt0-efi-riscv64.S @@ -0,0 +1,156 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Mitchell Horne + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + + .section .text.head + + /* + * Magic "MZ" signature for PE/COFF + */ + .globl ImageBase +ImageBase: + .ascii "MZ" + .skip 58 // 'MZ' + pad + offset == 64 + .long pe_header - ImageBase // Offset to the PE header. +pe_header: + .ascii "PE" + .short 0 +coff_header: + .short 0x5064 // RISCV64 + .short 2 // nr_sections + .long 0 // TimeDateStamp + .long 0 // PointerToSymbolTable + .long 1 // NumberOfSymbols + .short section_table - optional_header // SizeOfOptionalHeader + .short 0x206 // Characteristics. + // IMAGE_FILE_DEBUG_STRIPPED | + // IMAGE_FILE_EXECUTABLE_IMAGE | + // IMAGE_FILE_LINE_NUMS_STRIPPED +optional_header: + .short 0x20b // PE32+ format + .byte 0x02 // MajorLinkerVersion + .byte 0x14 // MinorLinkerVersion + .long _edata - _start // SizeOfCode + .long 0 // SizeOfInitializedData + .long 0 // SizeOfUninitializedData + .long _start - ImageBase // AddressOfEntryPoint + .long _start - ImageBase // BaseOfCode + +extra_header_fields: + .quad 0 // ImageBase + .long 32 // SectionAlignment + .long 8 // FileAlignment + + .short 0 // MajorOperatingSystemVersion + .short 0 // MinorOperatingSystemVersion + .short 0 // MajorImageVersion + .short 0 // MinorImageVersion + .short 0 // MajorSubsystemVersion + .short 0 // MinorSubsystemVersion + .long 0 // Win32VersionValue + + .long _edata - ImageBase // SizeOfImage + + // Everything before the kernel image is considered part of the header + .long _start - ImageBase // SizeOfHeaders + .long 0 // CheckSum + .short 10 // Subsystem (EFI) + .short 0 // DllCharacteristics + .quad 0 // SizeOfStackReserve + .quad 0 // SizeOfStackCommit + .quad 0 // SizeOfHeapReserve + .quad 0 // SizeOfHeapCommit + .long 0 // LoaderFlags + .long 0x6 // NumberOfRvaAndSizes + + .quad 0 // ExportTable + .quad 0 // ImportTable + .quad 0 // ResourceTable + .quad 0 // ExceptionTable + .quad 0 // CertificationTable + .quad 0 // BaseRelocationTable + + // Section table +section_table: + + /* + * The EFI application loader requires a relocation section + * because EFI applications must be relocatable. This is a + * dummy section as far as we are concerned. + */ + .ascii ".reloc" + .byte 0 + .byte 0 // end of 0 padding of section name + .long 0 + .long 0 + .long 0 // SizeOfRawData + .long 0 // PointerToRawData + .long 0 // PointerToRelocations + .long 0 // PointerToLineNumbers + .short 0 // NumberOfRelocations + .short 0 // NumberOfLineNumbers + .long 0x42100040 // Characteristics (section flags) + + + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 // end of 0 padding of section name + .long _edata - _start // VirtualSize + .long _start - ImageBase // VirtualAddress + .long _edata - _start // SizeOfRawData + .long _start - ImageBase // PointerToRawData + + .long 0 // PointerToRelocations (0 for executables) + .long 0 // PointerToLineNumbers (0 for executables) + .short 0 // NumberOfRelocations (0 for executables) + .short 0 // NumberOfLineNumbers (0 for executables) + .long 0xe0500020 // Characteristics (section flags) + + .globl _start +_start: + /* Save boot parameters to the stack */ + addi sp, sp, -16 + sd a0, 0(sp) + sd a1, 8(sp) + + /* Run relocation */ + lla a0, ImageBase + lla a1, .L_DYNAMIC + call _relocate + + /* Call EFI code */ + ld a1, 8(sp) + ld a0, 0(sp) + tail efi_main + +2: wfi + j 2b + +.L_DYNAMIC: + .word _DYNAMIC - . diff --git a/src/system/boot/platform/efi/arch/riscv64/entry.S b/src/system/boot/platform/efi/arch/riscv64/entry.S new file mode 100644 index 0000000000..3399ae9931 --- /dev/null +++ b/src/system/boot/platform/efi/arch/riscv64/entry.S @@ -0,0 +1,35 @@ +/* + * Copyright 2011, François Revol . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + + + .text + +/* status_t arch_enter_kernel(struct kernel_args *kernelArgs, + addr_t kernelEntry, addr_t kernelStackTop); + + r0 - kernelArgs + r1 - kernelEntry + r2 - kernelStackTop +*/ +FUNCTION(arch_enter_kernel): + nop + +// // set the kernel stack +// mov sp,r2 +// +// // set up kernel _start args +// //mov r0,r0 // kernelArgs +// mov r4,r1 +// mov r1,#0 // currentCPU=0 +// +// // call the kernel +// mov pc,r4 +// +// // return +// mov r0,#-1 // B_ERROR +// mov pc,lr +FUNCTION_END(arch_enter_kernel) diff --git a/src/system/boot/platform/efi/arch/riscv64/relocation_func.cpp b/src/system/boot/platform/efi/arch/riscv64/relocation_func.cpp index ca56132589..0b03af9d49 100644 --- a/src/system/boot/platform/efi/arch/riscv64/relocation_func.cpp +++ b/src/system/boot/platform/efi/arch/riscv64/relocation_func.cpp @@ -52,7 +52,7 @@ #endif -efi_status _relocate(long ldbase, Elf_Dyn *dyn, +extern "C" efi_status _relocate(long ldbase, Elf_Dyn *dyn, efi_handle image __attribute__((__unused__)), efi_system_table *systab __attribute__((__unused__))) { diff --git a/src/system/ldscripts/riscv64/boot_loader_efi.ld b/src/system/ldscripts/riscv64/boot_loader_efi.ld index 455ba0dff9..8915baab81 100644 --- a/src/system/ldscripts/riscv64/boot_loader_efi.ld +++ b/src/system/ldscripts/riscv64/boot_loader_efi.ld @@ -26,6 +26,10 @@ SECTIONS _text_size = . - _text; .dynamic : { *(.dynamic) } .data : { + __ctor_list = .; + *(.init_array) + *(.ctors) + __ctor_end = .; _data = .; *(.sdata) *(.data)