From a182bd6eb5656b9fa14556fd0006bd514c6516fe Mon Sep 17 00:00:00 2001 From: X512 Date: Sun, 18 Apr 2021 12:05:19 +0900 Subject: [PATCH] haiku_loader: initial support for RISC-V TinyEMU Change-Id: Ie102f466725f45072db25a9629fa8e28526484eb Reviewed-on: https://review.haiku-os.org/c/haiku/+/3882 Reviewed-by: Alex von Gluck IV --- build/jam/ArchitectureRules | 5 +- src/system/boot/Jamfile | 7 + src/system/boot/arch/riscv64/Jamfile | 2 +- src/system/boot/arch/riscv64/arch_cpu.cpp | 11 +- src/system/boot/platform/riscv/Jamfile | 58 ++++ src/system/boot/platform/riscv/console.cpp | 254 +++++++++++++++ src/system/boot/platform/riscv/console.h | 26 ++ src/system/boot/platform/riscv/cpu.cpp | 48 +++ src/system/boot/platform/riscv/cpu.h | 22 ++ src/system/boot/platform/riscv/crt0.S | 20 ++ src/system/boot/platform/riscv/debug.cpp | 62 ++++ src/system/boot/platform/riscv/devices.cpp | 228 +++++++++++++ src/system/boot/platform/riscv/entry.S | 32 ++ src/system/boot/platform/riscv/fdt.cpp | 92 ++++++ src/system/boot/platform/riscv/fdt.h | 18 ++ src/system/boot/platform/riscv/fixed_font.S | 12 + src/system/boot/platform/riscv/fixed_font.bin | Bin 0 -> 8649 bytes src/system/boot/platform/riscv/graphics.cpp | 97 ++++++ src/system/boot/platform/riscv/graphics.h | 45 +++ src/system/boot/platform/riscv/htif.cpp | 51 +++ src/system/boot/platform/riscv/menu.cpp | 70 ++++ src/system/boot/platform/riscv/mmu.cpp | 123 +++++++ src/system/boot/platform/riscv/mmu.h | 22 ++ src/system/boot/platform/riscv/start.cpp | 150 +++++++++ src/system/boot/platform/riscv/video.cpp | 117 +++++++ src/system/boot/platform/riscv/video.h | 18 ++ src/system/boot/platform/riscv/virtio.cpp | 301 ++++++++++++++++++ src/system/boot/platform/riscv/virtio.h | 78 +++++ .../ldscripts/riscv64/boot_loader_riscv.ld | 46 +++ 29 files changed, 2007 insertions(+), 8 deletions(-) create mode 100644 src/system/boot/platform/riscv/Jamfile create mode 100644 src/system/boot/platform/riscv/console.cpp create mode 100644 src/system/boot/platform/riscv/console.h create mode 100644 src/system/boot/platform/riscv/cpu.cpp create mode 100644 src/system/boot/platform/riscv/cpu.h create mode 100644 src/system/boot/platform/riscv/crt0.S create mode 100644 src/system/boot/platform/riscv/debug.cpp create mode 100644 src/system/boot/platform/riscv/devices.cpp create mode 100644 src/system/boot/platform/riscv/entry.S create mode 100644 src/system/boot/platform/riscv/fdt.cpp create mode 100644 src/system/boot/platform/riscv/fdt.h create mode 100644 src/system/boot/platform/riscv/fixed_font.S create mode 100644 src/system/boot/platform/riscv/fixed_font.bin create mode 100644 src/system/boot/platform/riscv/graphics.cpp create mode 100644 src/system/boot/platform/riscv/graphics.h create mode 100644 src/system/boot/platform/riscv/htif.cpp create mode 100644 src/system/boot/platform/riscv/menu.cpp create mode 100644 src/system/boot/platform/riscv/mmu.cpp create mode 100644 src/system/boot/platform/riscv/mmu.h create mode 100644 src/system/boot/platform/riscv/start.cpp create mode 100644 src/system/boot/platform/riscv/video.cpp create mode 100644 src/system/boot/platform/riscv/video.h create mode 100644 src/system/boot/platform/riscv/virtio.cpp create mode 100644 src/system/boot/platform/riscv/virtio.h create mode 100644 src/system/ldscripts/riscv64/boot_loader_riscv.ld diff --git a/build/jam/ArchitectureRules b/build/jam/ArchitectureRules index 95b65528ea..697b6bfd70 100644 --- a/build/jam/ArchitectureRules +++ b/build/jam/ArchitectureRules @@ -276,7 +276,7 @@ rule KernelArchitectureSetup architecture case riscv64 : HAIKU_KERNEL_PLATFORM ?= efi ; - HAIKU_BOOT_TARGETS += efi ; + HAIKU_BOOT_TARGETS += efi riscv ; HAIKU_BOOT_SDIMAGE_BEGIN = 2 ; # KiB @@ -526,6 +526,9 @@ rule KernelArchitectureSetup architecture HAIKU_BOOT_$(bootTarget:U)_C++FLAGS += -m68020-60 ; # TODO: coldfire (FireBee) } + case riscv : + HAIKU_BOOT_$(bootTarget:U)_CCFLAGS += -mcmodel=medany -fno-omit-frame-pointer -fno-plt -fno-pic -fno-semantic-interposition ; + HAIKU_BOOT_$(bootTarget:U)_C++FLAGS += -mcmodel=medany -fno-omit-frame-pointer -fno-plt -fno-pic -fno-semantic-interposition ; case * : # all other bootloaders are non-PIC HAIKU_BOOT_$(bootTarget:U)_CCFLAGS += -fno-pic -Wno-error=main ; diff --git a/src/system/boot/Jamfile b/src/system/boot/Jamfile index 47826a0f39..cb1303471a 100644 --- a/src/system/boot/Jamfile +++ b/src/system/boot/Jamfile @@ -310,6 +310,10 @@ for platform in [ MultiBootSubDirSetup ] { ldflags += -Map=efi.map ; } + if $(TARGET_BOOT_PLATFORM) = riscv { + ldflags += -z,notext ; + } + BootLd boot_loader_$(platform:G=) : boot_platform_$(platform:G=).o $(archObject:G=$(archGrist)) @@ -384,6 +388,9 @@ for platform in [ MultiBootSubDirSetup ] { : -Bstatic ; + case riscv : + BuildBiosLoader haiku_loader.$(TARGET_BOOT_PLATFORM) : boot_loader_$(TARGET_BOOT_PLATFORM) ; + case next_m68k : BuildAoutLoader haiku_loader.$(TARGET_BOOT_PLATFORM) : boot_loader_$(TARGET_BOOT_PLATFORM) ; diff --git a/src/system/boot/arch/riscv64/Jamfile b/src/system/boot/arch/riscv64/Jamfile index 9c52e023d9..9e20dbe708 100644 --- a/src/system/boot/arch/riscv64/Jamfile +++ b/src/system/boot/arch/riscv64/Jamfile @@ -29,7 +29,7 @@ local kernelGenericDriverSources = ; local platform ; -for platform in [ MultiBootSubDirSetup u-boot efi ] { +for platform in [ MultiBootSubDirSetup u-boot efi riscv ] { on $(platform) { DEFINES += _BOOT_MODE ; BootMergeObject [ FGristFiles boot_arch_$(TARGET_KERNEL_ARCH).o ] : diff --git a/src/system/boot/arch/riscv64/arch_cpu.cpp b/src/system/boot/arch/riscv64/arch_cpu.cpp index 0b1ace2b85..1a35889aff 100644 --- a/src/system/boot/arch/riscv64/arch_cpu.cpp +++ b/src/system/boot/arch/riscv64/arch_cpu.cpp @@ -58,16 +58,15 @@ arch_ucode_load(BootVolume& volume) extern "C" bigtime_t system_time() { - #warning Implement system_time in RISCV bootloader! - return 0; + // TODO: units conversion + return CpuTime(); } extern "C" void spin(bigtime_t microseconds) { - #warning Implment spin in RISCV bootloader! - //bigtime_t time = system_time(); - //while ((system_time() - time) < microseconds) - // asm volatile ("nop;"); + bigtime_t time = system_time(); + while ((system_time() - time) < microseconds) + asm volatile ("nop;"); } diff --git a/src/system/boot/platform/riscv/Jamfile b/src/system/boot/platform/riscv/Jamfile new file mode 100644 index 0000000000..f68b501b0f --- /dev/null +++ b/src/system/boot/platform/riscv/Jamfile @@ -0,0 +1,58 @@ +SubDir HAIKU_TOP src system boot platform riscv ; + +SubDirHdrs $(HAIKU_TOP) headers private kernel boot platform riscv ; + +UsePrivateHeaders [ FDirName kernel boot platform riscv ] ; +UsePrivateHeaders [ FDirName kernel platform $(TARGET_BOOT_PLATFORM) ] ; +UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; +UsePrivateHeaders [ FDirName graphics common ] ; +UsePrivateHeaders [ FDirName storage ] ; +UsePrivateHeaders [ FDirName virtio ] ; +UseLibraryHeaders [ FDirName libfdt ] ; + +{ + local defines = _BOOT_MODE ; + + defines = [ FDefines $(defines) ] ; + SubDirCcFlags $(defines) ; + SubDirC++Flags $(defines) -fno-rtti ; + SubDirAsFlags -I $(SUBDIR) ; +} + +local platform ; +for platform in [ MultiBootSubDirSetup riscv ] { + on $(platform) { + + BootMergeObject boot_platform_riscv_other.o : + crt0.S + start.cpp + debug.cpp + console.cpp + devices.cpp + menu.cpp + mmu.cpp + cpu.cpp + video.cpp + + fdt.cpp + graphics.cpp + fixed_font.S + htif.cpp + virtio.cpp + entry.S + + : : + boot_platform_generic_riscv.a + boot_fdt.a + ; + + + BootMergeObject boot_platform_riscv.o : + : : + boot_platform_riscv_other.o + ; + } +} + +SEARCH on [ FGristFiles $(genericPlatformSources) ] + = [ FDirName $(HAIKU_TOP) src system boot platform generic ] ; diff --git a/src/system/boot/platform/riscv/console.cpp b/src/system/boot/platform/riscv/console.cpp new file mode 100644 index 0000000000..acad8653c5 --- /dev/null +++ b/src/system/boot/platform/riscv/console.cpp @@ -0,0 +1,254 @@ +/* + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2011, Rene Gollent, rene@gollent.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "console.h" +#include "video.h" +#include "graphics.h" +#include +#include "virtio.h" + +#include +#include +#include + +#include + + +class Console : public ConsoleNode { + public: + Console(); + + virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, + size_t bufferSize); + virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, + size_t bufferSize); +}; + +static uint16* sScreenBase; +static uint32 sScreenOfsX = 0; +static uint32 sScreenOfsY = 0; +static uint32 sScreenWidth = 80; +static uint32 sScreenHeight = 25; +static uint32 sScreenOffset = 0; +static uint16 sColor = 0x0f00; + +static Console sInput, sOutput; +FILE *stdin, *stdout, *stderr; + + +static const uint32 kPalette[] = { + 0x000000, + 0x0000aa, + 0x00aa00, + 0x00aaaa, + 0xaa0000, + 0xaa00aa, + 0xaa5500, + 0xaaaaaa, + 0x555555, + 0x5555ff, + 0x55ff55, + 0x55ffff, + 0xff5555, + 0xff55ff, + 0xffff55, + 0xffffff +}; + + +static void +RefreshFramebuf(int32 x0, int32 y0, int32 w, int32 h) +{ + for (int32 y = y0; y < y0 + h; y++) + for (int32 x = x0; x < x0 + w; x++) { + uint16 cell = sScreenBase[x + y * sScreenWidth]; + int32 charX = sScreenOfsX + x*gFixedFont.charWidth; + int32 charY = sScreenOfsY + y*gFixedFont.charHeight; + uint32 bgColor = kPalette[cell / 0x1000 % 0x10]; + uint32 fontColor = kPalette[cell / 0x100 % 0x10]; + Clear(gFramebuf.Clip(charX, charY, gFixedFont.charWidth, + gFixedFont.charHeight), bgColor); + BlitMaskRgb(gFramebuf, gFixedFont.ThisGlyph(cell % 0x100), + charX, charY, fontColor); + } +} + + +static void +scroll_up() +{ + memcpy(sScreenBase, sScreenBase + sScreenWidth, + sScreenWidth * sScreenHeight * 2 - sScreenWidth * 2); + sScreenOffset = (sScreenHeight - 1) * sScreenWidth; + + for (uint32 i = 0; i < sScreenWidth; i++) + sScreenBase[sScreenOffset + i] = sColor | ' '; +} + + +// #pragma mark - + + +Console::Console() + : ConsoleNode() +{ +} + + +ssize_t +Console::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) +{ + // don't seek in character devices + // not implemented (and not yet? needed) + return B_ERROR; +} + + +ssize_t +Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, + size_t bufferSize) +{ + const char *string = (const char *)buffer; + + if (gKernelArgs.frame_buffer.enabled) + return bufferSize; + + for (uint32 i = 0; i < bufferSize; i++) { + if (string[0] == '\n') { + sScreenOffset += sScreenWidth - (sScreenOffset % sScreenWidth); + } else { + sScreenBase[sScreenOffset++] = sColor | string[0]; + RefreshFramebuf((sScreenOffset - 1) % sScreenWidth, + (sScreenOffset - 1) / sScreenWidth, 1, 1); + } + + if (sScreenOffset >= sScreenWidth * sScreenHeight) { + scroll_up(); + RefreshFramebuf(0, 0, sScreenWidth, sScreenHeight); + } + + string++; + } + + return bufferSize; +} + + +// #pragma mark - + + +void +console_clear_screen(void) +{ + if (gKernelArgs.frame_buffer.enabled) + return; + + for (uint32 i = 0; i < sScreenWidth * sScreenHeight; i++) + sScreenBase[i] = sColor; + + // reset cursor position as well + sScreenOffset = 0; + + RefreshFramebuf(0, 0, sScreenWidth, sScreenHeight); +} + + +int32 +console_width(void) +{ + return sScreenWidth; +} + + +int32 +console_height(void) +{ + return sScreenHeight; +} + + +void +console_set_cursor(int32 x, int32 y) +{ + if (y >= (int32)sScreenHeight) + y = sScreenHeight - 1; + else if (y < 0) + y = 0; + if (x >= (int32)sScreenWidth) + x = sScreenWidth - 1; + else if (x < 0) + x = 0; + + sScreenOffset = x + y * sScreenWidth; +} + + +void +console_show_cursor(void) +{ + // TODO: implement +} + + +void +console_hide_cursor(void) +{ + // TODO: implement +} + + +void +console_set_color(int32 foreground, int32 background) +{ + sColor = (background & 0xf) << 12 | (foreground & 0xf) << 8; +} + + +int +console_wait_for_key(void) +{ + int key = virtio_input_wait_for_key(); + + switch (key) { + case 71: return TEXT_CONSOLE_KEY_RETURN; + case 30: return TEXT_CONSOLE_KEY_BACKSPACE; + case 1: return TEXT_CONSOLE_KEY_ESCAPE; + case 94: return TEXT_CONSOLE_KEY_SPACE; + + case 87: return TEXT_CONSOLE_KEY_UP; + case 98: return TEXT_CONSOLE_KEY_DOWN; + case 97: return TEXT_CONSOLE_KEY_LEFT; + case 99: return TEXT_CONSOLE_KEY_RIGHT; + case 33: return TEXT_CONSOLE_KEY_PAGE_UP; + case 54: return TEXT_CONSOLE_KEY_PAGE_DOWN; + case 32: return TEXT_CONSOLE_KEY_HOME; + case 53: return TEXT_CONSOLE_KEY_END; + + default: + return TEXT_CONSOLE_NO_KEY; + } +} + + +status_t +console_init(void) +{ + sScreenWidth = 80; + sScreenHeight = 25; + sScreenOfsX = gFramebuf.width/2 - sScreenWidth*gFixedFont.charWidth/2; + sScreenOfsY = gFramebuf.height/2 - sScreenHeight*gFixedFont.charHeight/2; + + sScreenBase = new(std::nothrow) uint16[sScreenWidth * sScreenHeight]; + + console_clear_screen(); + + // enable stdio functionality + stdin = (FILE *)&sInput; + stdout = stderr = (FILE *)&sOutput; + + return B_OK; +} diff --git a/src/system/boot/platform/riscv/console.h b/src/system/boot/platform/riscv/console.h new file mode 100644 index 0000000000..4cb1785889 --- /dev/null +++ b/src/system/boot/platform/riscv/console.h @@ -0,0 +1,26 @@ +/* + * Copyright 2007, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * François Revol, revol@free.fr. + */ + +#ifndef CONSOLE_H +#define CONSOLE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct Screen* gScreen; + +extern status_t console_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* CONSOLE_H */ diff --git a/src/system/boot/platform/riscv/cpu.cpp b/src/system/boot/platform/riscv/cpu.cpp new file mode 100644 index 0000000000..2f15c6d99c --- /dev/null +++ b/src/system/boot/platform/riscv/cpu.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "cpu.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +//#define TRACE_CPU +#ifdef TRACE_CPU +# define TRACE(x...) dprintf(x) +#else +# define TRACE(x...) ; +#endif + + +// #pragma mark - + + +extern "C" void +cpu_init() +{ + gKernelArgs.num_cpus = 1; + + // enable FPU + MstatusReg status(Mstatus()); + status.fs = extStatusInitial; + SetMstatus(status.val); +} + + +extern "C" void +platform_load_ucode(BootVolume& volume) +{ + // we have no ucode +} diff --git a/src/system/boot/platform/riscv/cpu.h b/src/system/boot/platform/riscv/cpu.h new file mode 100644 index 0000000000..f8eff4f44a --- /dev/null +++ b/src/system/boot/platform/riscv/cpu.h @@ -0,0 +1,22 @@ +/* + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef CPU_H +#define CPU_H + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void cpu_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_H */ diff --git a/src/system/boot/platform/riscv/crt0.S b/src/system/boot/platform/riscv/crt0.S new file mode 100644 index 0000000000..74ef66bca9 --- /dev/null +++ b/src/system/boot/platform/riscv/crt0.S @@ -0,0 +1,20 @@ +/* + * Copyright 2021, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ + + + .section .bss.stack +.globl gStack +.type gStack, @object +gStack: + .skip 1*1024*1024 +.size gStack, .-gStack +.globl gStackEnd +gStackEnd: + + .section .text.head + la sp, gStackEnd + li fp, 0 + call _start + j . diff --git a/src/system/boot/platform/riscv/debug.cpp b/src/system/boot/platform/riscv/debug.cpp new file mode 100644 index 0000000000..5ec3c5cb9c --- /dev/null +++ b/src/system/boot/platform/riscv/debug.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include +#include + +#include + +extern FILE *dbgerr; + + +static void +dprintf_args(const char* format, va_list args) +{ + char buffer[512]; + int length = vsnprintf(buffer, sizeof(buffer), format, args); + if (length == 0) + return; + + //syslog_write(buffer, length); + HtifOutString(buffer); +} + + +extern "C" void +dprintf(const char* format, ...) +{ + va_list args; + + va_start(args, format); + dprintf_args(format, args); + va_end(args); +} + + +void +panic(const char* format, ...) +{ + va_list args; + + dprintf("*** PANIC ***\n"); + + va_start(args, format); + dprintf_args(format, args); + va_end(args); + + for(;;) {} +} + + +char* +platform_debug_get_log_buffer(size_t* _size) +{ + return NULL; +} diff --git a/src/system/boot/platform/riscv/devices.cpp b/src/system/boot/platform/riscv/devices.cpp new file mode 100644 index 0000000000..56add58e2e --- /dev/null +++ b/src/system/boot/platform/riscv/devices.cpp @@ -0,0 +1,228 @@ +/* + * Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "bios.h" +#include "virtio.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +//#define TRACE_DEVICES +#ifdef TRACE_DEVICES +# define TRACE(x...) dprintf(x) +#else +# define TRACE(x...) ; +#endif + + +void* aligned_malloc(size_t required_bytes, size_t alignment); +void aligned_free(void* p); + + +class VirtioBlockDevice : public Node +{ + public: + VirtioBlockDevice(VirtioDevice* blockIo); + virtual ~VirtioBlockDevice(); + + virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer, + size_t bufferSize); + virtual ssize_t WriteAt(void* cookie, off_t pos, const void* buffer, + size_t bufferSize) { return B_UNSUPPORTED; } + virtual off_t Size() const { + return (*(uint32*)(&fBlockIo->Regs()->config[0]) + + ((uint64)(*(uint32*)(&fBlockIo->Regs()->config[4])) << 32) + )*kVirtioBlockSectorSize; + } + + uint32 BlockSize() const { return kVirtioBlockSectorSize; } + bool ReadOnly() const { return false; } + private: + ObjectDeleter fBlockIo; +}; + + +VirtioBlockDevice::VirtioBlockDevice(VirtioDevice* blockIo) + : + fBlockIo(blockIo) +{ + dprintf("+VirtioBlockDevice\n"); +} + + +VirtioBlockDevice::~VirtioBlockDevice() +{ + dprintf("-VirtioBlockDevice\n"); +} + + +ssize_t +VirtioBlockDevice::ReadAt(void* cookie, off_t pos, void* buffer, + size_t bufferSize) +{ + // dprintf("ReadAt(%p, %ld, %p, %ld)\n", cookie, pos, buffer, bufferSize); + + off_t offset = pos % BlockSize(); + pos /= BlockSize(); + + uint32 numBlocks = (offset + bufferSize + BlockSize() - 1) / BlockSize(); + + ArrayDeleter readBuffer( + new(std::nothrow) char[numBlocks * BlockSize() + 1]); + if (!readBuffer.IsSet()) + return B_NO_MEMORY; + + VirtioBlockRequest blkReq; + blkReq.type = kVirtioBlockTypeIn; + blkReq.ioprio = 0; + blkReq.sectorNum = pos; + IORequest req(ioOpRead, &blkReq, sizeof(blkReq)); + IORequest reply(ioOpWrite, readBuffer.Get(), numBlocks * BlockSize() + 1); + IORequest* reqs[] = {&req, &reply}; + fBlockIo->ScheduleIO(reqs, 2); + fBlockIo->WaitIO(); + + if (readBuffer[numBlocks * BlockSize()] != kVirtioBlockStatusOk) { + dprintf("%s: blockIo error reading from device!\n", __func__); + return B_ERROR; + } + + memcpy(buffer, readBuffer.Get() + offset, bufferSize); + + return bufferSize; +} + + +static VirtioBlockDevice* +CreateVirtioBlockDev(int id) +{ + VirtioResources* devRes = ThisVirtioDev(kVirtioDevBlock, id); + if (devRes == NULL) return NULL; + + ObjectDeleter virtioDev( + new(std::nothrow) VirtioDevice(*devRes)); + if (!virtioDev.IsSet()) + panic("Can't allocate memory for VirtioDevice!"); + + ObjectDeleter device( + new(std::nothrow) VirtioBlockDevice(virtioDev.Detach())); + if (!device.IsSet()) + panic("Can't allocate memory for VirtioBlockDevice!"); + + return device.Detach(); +} + + +static off_t +get_next_check_sum_offset(int32 index, off_t maxSize) +{ + if (index < 2) + return index * 512; + + if (index < 4) + return (maxSize >> 10) + index * 2048; + + return ((system_time() + index) % (maxSize >> 9)) * 512; +} + + +static uint32 +compute_check_sum(Node* device, off_t offset) +{ + char buffer[512]; + ssize_t bytesRead = device->ReadAt(NULL, offset, buffer, sizeof(buffer)); + if (bytesRead < B_OK) + return 0; + + if (bytesRead < (ssize_t)sizeof(buffer)) + memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead); + + uint32* array = (uint32*)buffer; + uint32 sum = 0; + + for (uint32 i = 0; i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); + i++) + sum += array[i]; + + return sum; +} + + +//#pragma mark - + +status_t +platform_add_boot_device(struct stage2_args* args, NodeList* devicesList) +{ + for (int i = 0;; i++) { + ObjectDeleter device(CreateVirtioBlockDev(i)); + if (!device.IsSet()) break; + dprintf("virtio_block[%d]\n", i); + devicesList->Insert(device.Detach()); + } + return devicesList->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND; +} + + +status_t +platform_add_block_devices(struct stage2_args* args, NodeList* devicesList) +{ + return B_ENTRY_NOT_FOUND; +} + + +status_t +platform_get_boot_partition( + struct stage2_args* args, Node* bootDevice, + NodeList* partitions, boot::Partition** _partition +) +{ + // return B_ENTRY_NOT_FOUND; + + *_partition = (boot::Partition*)partitions->GetIterator().Next(); + dprintf("*_partition: %p\n", *_partition); + return *_partition != NULL ? B_OK : B_ENTRY_NOT_FOUND; +} + + +status_t +platform_register_boot_device(Node* device) +{ + TRACE("%s: called\n", __func__); + + disk_identifier identifier; + + identifier.bus_type = UNKNOWN_BUS; + identifier.device_type = UNKNOWN_DEVICE; + identifier.device.unknown.size = device->Size(); + + for (uint32 i = 0; i < NUM_DISK_CHECK_SUMS; ++i) { + off_t offset = get_next_check_sum_offset(i, device->Size()); + identifier.device.unknown.check_sums[i].offset = offset; + identifier.device.unknown.check_sums[i].sum = compute_check_sum(device, + offset); + } + + gBootVolume.SetInt32(BOOT_METHOD, BOOT_METHOD_HARD_DISK); + gBootVolume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, false); + gBootVolume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE, + &identifier, sizeof(disk_identifier)); + + return B_OK; +} + + +void +platform_cleanup_devices() +{ +} diff --git a/src/system/boot/platform/riscv/entry.S b/src/system/boot/platform/riscv/entry.S new file mode 100644 index 0000000000..185c000ddb --- /dev/null +++ b/src/system/boot/platform/riscv/entry.S @@ -0,0 +1,32 @@ +/* + * Copyright 2020-2021, Haiku, Inc. 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); + + a0 - kernelArgs + a1 - kernelEntry + a2 - kernelStackTop +*/ +FUNCTION(arch_enter_kernel): + // set the kernel stack + mv sp,a2 + + // Setup kernel args + //mv a0,a0 // kernelArgs + mv a4,a1 + li a1,0 // currentCPU=0 + + // call the kernel + jr a4 + + // return + li a0,-1 // B_ERROR + ret +FUNCTION_END(arch_enter_kernel) diff --git a/src/system/boot/platform/riscv/fdt.cpp b/src/system/boot/platform/riscv/fdt.cpp new file mode 100644 index 0000000000..d7d656a873 --- /dev/null +++ b/src/system/boot/platform/riscv/fdt.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2021, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ + + +#include "fdt.h" +#include +#include +#include +#include + +extern "C" { +#include +} + +#include "mmu.h" +#include "graphics.h" +#include "virtio.h" + + +void* gFdt = NULL; + + +static void +HandleFdt(const void* fdt, int node, uint32_t addressCells, uint32_t sizeCells, + uint32_t interruptCells /* from parent node */) +{ + // TODO: handle different field sizes + + const char* device_type = (const char*)fdt_getprop(fdt, node, + "device_type", NULL); + if (device_type != NULL && strcmp(device_type, "memory") == 0) { + gMemBase = (uint8*)fdt64_to_cpu(*((uint64_t*)fdt_getprop(fdt, node, + "reg", NULL) + 0)); + gTotalMem = fdt64_to_cpu(*((uint64_t*)fdt_getprop(fdt, node, + "reg", NULL) + 1)); + return; + } + const char* compatible = (const char*)fdt_getprop(fdt, node, + "compatible", NULL); + if (compatible == NULL) return; + if (strcmp(compatible, "virtio,mmio") == 0) { + virtio_register( + fdt64_to_cpu(*((uint64_t*)fdt_getprop(fdt, node, "reg", NULL) + 0)), + fdt64_to_cpu(*((uint64_t*)fdt_getprop(fdt, node, "reg", NULL) + 1)), + fdt32_to_cpu(*((uint32_t*)fdt_getprop(fdt, node, + "interrupts-extended", NULL) + 1)) + ); + } else if (strcmp(compatible, "simple-framebuffer") == 0) { + gFramebuf.colors = (uint32_t*)fdt64_to_cpu( + *(uint64_t*)fdt_getprop(fdt, node, "reg", NULL)); + gFramebuf.stride = fdt32_to_cpu( + *(uint32_t*)fdt_getprop(fdt, node, "stride", NULL)) / 4; + gFramebuf.width = fdt32_to_cpu( + *(uint32_t*)fdt_getprop(fdt, node, "width", NULL)); + gFramebuf.height = fdt32_to_cpu( + *(uint32_t*)fdt_getprop(fdt, node, "height", NULL)); + } +} + + +void +fdt_init(void* fdt) +{ + dprintf("FDT: %p\n", fdt); + gFdt = fdt; + + int res = fdt_check_header(gFdt); + if (res != 0) { + panic("Invalid FDT: %s\n", fdt_strerror(res)); + } + + dprintf("FDT valid, size: %" B_PRIu32 "\n", fdt_totalsize(gFdt)); + + int node = -1; + int depth = 0; + while ((node = fdt_next_node(gFdt, node, &depth)) >= 0) { + HandleFdt(gFdt, node, 2, 2, 2); + } +} + + +void +fdt_set_kernel_args() +{ + gKernelArgs.arch_args.fdt = kernel_args_malloc(fdt_totalsize(gFdt)); + if (gKernelArgs.arch_args.fdt != NULL) { + memcpy(gKernelArgs.arch_args.fdt, gFdt, fdt_totalsize(gFdt)); + } else + panic("unable to malloc for FDT!\n"); +} diff --git a/src/system/boot/platform/riscv/fdt.h b/src/system/boot/platform/riscv/fdt.h new file mode 100644 index 0000000000..8c96cf9121 --- /dev/null +++ b/src/system/boot/platform/riscv/fdt.h @@ -0,0 +1,18 @@ +/* + * Copyright 2021, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ + + +#ifndef _FDT_H_ +#define _FDT_H_ + + +extern void* gFdt; + + +void fdt_init(void* fdt); +void fdt_set_kernel_args(); + + +#endif // _FDT_H_ diff --git a/src/system/boot/platform/riscv/fixed_font.S b/src/system/boot/platform/riscv/fixed_font.S new file mode 100644 index 0000000000..76601450f4 --- /dev/null +++ b/src/system/boot/platform/riscv/fixed_font.S @@ -0,0 +1,12 @@ +/* + * Copyright 2021, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ + + +.global gFixedFont +.type gFixedFont, @object +.data +gFixedFont: +.incbin "fixed_font.bin" +.size gFixedFont, .-gFixedFont diff --git a/src/system/boot/platform/riscv/fixed_font.bin b/src/system/boot/platform/riscv/fixed_font.bin new file mode 100644 index 0000000000000000000000000000000000000000..3764a7b53c14cc18de6c212d9049d02a2dba337d GIT binary patch literal 8649 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 qAh;K%Lr~>N9Aut7c-*m)6 0; vb.height--) { + for (int x = 0; x < vb.width; x++) { + *vb.colors = c; + vb.colors++; + } + vb.colors += vb.stride; + } +} + + +template +RasBuf +RasBuf::Clip(int x, int y, int w, int h) const +{ + RasBuf vb = *this; + if (x < 0) {w += x; x = 0;} + if (y < 0) {h += y; y = 0;} + if (x + w > vb.width) {w = vb.width - x;} + if (y + h > vb.height) {h = vb.height - y;} + if (w > 0 && h > 0) { + vb.colors += y*vb.stride + x; + vb.width = w; + vb.height = h; + } else { + vb.colors = 0; + vb.width = 0; + vb.height = 0; + } + return vb; +} + +template class RasBuf; +template class RasBuf; + + +RasBuf8 +Font::ThisGlyph(uint32 ch) +{ + if (ch < firstChar || ch >= firstChar + charCnt) + return ThisGlyph(' '); + + RasBuf8 rb; + rb.colors = data + (ch - firstChar) * charWidth * charHeight; + rb.stride = charWidth; + rb.width = charWidth; + rb.height = charHeight; + return rb; +} + + +void +BlitMaskRgb(RasBuf32 dst, RasBuf8 src, int32 x, int32 y, uint32_t c) +{ + int dstW, dstH; + uint32_t dc, a; + dstW = dst.width; dstH = dst.height; + dst = dst.Clip(x, y, src.width, src.height); + src = src.Clip(-x, -y, dstW, dstH); + dst.stride -= dst.width; + src.stride -= src.width; + for (; dst.height > 0; dst.height--) { + for (x = dst.width; x > 0; x--) { + dc = *dst.colors; + a = *src.colors; + if (a != 0) { + *dst.colors = + ((((dc >> 0) % 0x100) * (0xff - a) / 0xff + + ((c >> 0) % 0x100) * a / 0xff) << 0) + + ((((dc >> 8) % 0x100) * (0xff - a) / 0xff + + ((c >> 8) % 0x100) * a / 0xff) << 8) + + ((((dc >> 16) % 0x100) * (0xff - a) / 0xff + + ((c >> 16) % 0x100) * a / 0xff) << 16) + + (dc & 0xff000000); + } + dst.colors++; + src.colors++; + } + dst.colors += dst.stride; + src.colors += src.stride; + } +} diff --git a/src/system/boot/platform/riscv/graphics.h b/src/system/boot/platform/riscv/graphics.h new file mode 100644 index 0000000000..e7c2d72da3 --- /dev/null +++ b/src/system/boot/platform/riscv/graphics.h @@ -0,0 +1,45 @@ +/* + * Copyright 2021, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ + + +#ifndef _GRAPHICS_H_ +#define _GRAPHICS_H_ + + +#include + + +template +struct RasBuf { + Color* colors; + int32 stride, width, height; + + RasBuf Clip(int x, int y, int w, int h) const; +}; + +typedef RasBuf RasBuf8; +typedef RasBuf RasBuf32; + + +struct Font { + uint8 charWidth; + uint8 charHeight; + uint8 firstChar, charCnt; + uint8 data[0]; + + RasBuf8 ThisGlyph(uint32 ch); +}; + + +extern RasBuf32 gFramebuf; +extern Font gFixedFont; + + +void Clear(RasBuf32 vb, uint32_t c); + +void BlitMaskRgb(RasBuf32 dst, RasBuf8 src, int32 x, int32 y, uint32_t c); + + +#endif // _GRAPHICS_H_ diff --git a/src/system/boot/platform/riscv/htif.cpp b/src/system/boot/platform/riscv/htif.cpp new file mode 100644 index 0000000000..c34cf06c1e --- /dev/null +++ b/src/system/boot/platform/riscv/htif.cpp @@ -0,0 +1,51 @@ +/* + * Copyright 2021, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ + + +#include + + +// This address is used by TinyEMU and it is not present in FDT. +HtifRegs* volatile gHtifRegs = (HtifRegs* volatile)0x40008000; + + +uint64_t +HtifCmd(uint32_t device, uint8_t cmd, uint32_t arg) +{ + uint64_t htifTohost = ((uint64_t)device << 56) + + ((uint64_t)cmd << 48) + arg; + gHtifRegs->toHostLo = htifTohost % ((uint64_t)1 << 32); + gHtifRegs->toHostHi = htifTohost / ((uint64_t)1 << 32); + return (uint64_t)gHtifRegs->fromHostLo + + ((uint64_t)gHtifRegs->fromHostHi << 32); +} + + +void +HtifShutdown() +{ + HtifCmd(0, 0, 1); +} + + +void +HtifOutChar(char ch) +{ + HtifCmd(1, 1, ch); +} + + +void +HtifOutString(const char* str) +{ + for (; *str != '\0'; str++) HtifOutChar(*str); +} + + +void +HtifOutString(const char* str, size_t len) +{ + for (; len > 0; str++, len--) HtifOutChar(*str); +} diff --git a/src/system/boot/platform/riscv/menu.cpp b/src/system/boot/platform/riscv/menu.cpp new file mode 100644 index 0000000000..cc6e1956fa --- /dev/null +++ b/src/system/boot/platform/riscv/menu.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "smp.h" +#include "video.h" + +#include +#include +#include + + +void +platform_add_menus(Menu* menu) +{ + MenuItem* item; + + switch (menu->Type()) { + case MAIN_MENU: + menu->AddItem(item = new(nothrow) MenuItem( + "Select screen resolution", video_mode_menu())); + item->SetTarget(video_mode_hook); + break; + case SAFE_MODE_MENU: + menu->AddItem(item = new(nothrow) MenuItem( + "Use fail-safe graphics driver")); + item->SetType(MENU_ITEM_MARKABLE); + item->SetData(B_SAFEMODE_FAIL_SAFE_VIDEO_MODE); + item->SetHelpText("The system will use VESA mode and won't try to " + "open any video graphics driver"); + +#if 0 + smp_add_safemode_menus(menu); + + menu->AddItem(item = new(nothrow) MenuItem("Disable ACPI")); + item->SetType(MENU_ITEM_MARKABLE); + item->SetData(B_SAFEMODE_DISABLE_ACPI); + item->SetHelpText("This overrides the ACPI setting in the kernel " + "settings file"); +#endif + break; + default: + break; + } +} + + +void +platform_update_menu_item(Menu* menu, MenuItem* item) +{ + platform_generic_update_text_menu_item(menu, item); +} + + +void +platform_run_menu(Menu* menu) +{ + platform_generic_run_text_menu(menu); +} + + +size_t +platform_get_user_input_text(Menu* menu, MenuItem* item, char* buffer, + size_t bufferSize) +{ + return platform_generic_get_user_input_text(menu, item, buffer, + bufferSize); +} diff --git a/src/system/boot/platform/riscv/mmu.cpp b/src/system/boot/platform/riscv/mmu.cpp new file mode 100644 index 0000000000..4a9a95f744 --- /dev/null +++ b/src/system/boot/platform/riscv/mmu.cpp @@ -0,0 +1,123 @@ +/* + * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. + * Based on code written by Travis Geiselbrecht for NewOS. + * + * Distributed under the terms of the MIT License. + */ + + +#include "mmu.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +extern uint8 gStackEnd; + +uint8* gMemBase = NULL; +size_t gTotalMem = 0; +uint8* gFreeMem = &gStackEnd; + + +// #pragma mark - + +extern "C" status_t +platform_allocate_region(void** _address, size_t size, uint8 protection, + bool exactAddress) +{ + if (exactAddress) + return B_ERROR; + + gFreeMem = (uint8*)(((addr_t)gFreeMem + + (B_PAGE_SIZE - 1)) / B_PAGE_SIZE * B_PAGE_SIZE); + *_address = gFreeMem; + gFreeMem += size; + + return B_OK; +} + + +extern "C" status_t +platform_free_region(void* address, size_t size) +{ + return B_OK; +} + + +void +platform_release_heap(struct stage2_args* args, void* base) +{ +} + + +status_t +platform_init_heap(struct stage2_args* args, void** _base, void** _top) +{ + void* heap = (void*)gFreeMem; + gFreeMem += args->heap_size; + + *_base = heap; + *_top = (void*)((int8*)heap + args->heap_size); + return B_OK; +} + + +status_t +platform_bootloader_address_to_kernel_address(void* address, addr_t* _result) +{ + *_result = (addr_t)address; + return B_OK; +} + + +status_t +platform_kernel_address_to_bootloader_address(addr_t address, void** _result) +{ + *_result = (void*)address; + return B_OK; +} + + +// #pragma mark - + +void +mmu_init(void) +{ +} + + +void +mmu_init_for_kernel(void) +{ + // map in a kernel stack + void* stack_address = NULL; + if (platform_allocate_region(&stack_address, + KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE, 0, false) + != B_OK) { + panic("Unabled to allocate a stack"); + } + gKernelArgs.cpu_kstack[0].start = (addr_t)stack_address; + gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE + + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; + dprintf("Kernel stack at %#lx\n", gKernelArgs.cpu_kstack[0].start); + + gKernelArgs.physical_memory_range[0].start = (addr_t)gMemBase; + gKernelArgs.physical_memory_range[0].size = gTotalMem; + gKernelArgs.num_physical_memory_ranges = 1; + + gKernelArgs.physical_allocated_range[0].start = (addr_t)gMemBase; + gKernelArgs.physical_allocated_range[0].size = gFreeMem - gMemBase; + gKernelArgs.num_physical_allocated_ranges = 1; + + gKernelArgs.virtual_allocated_range[0].start = (addr_t)gMemBase; + gKernelArgs.virtual_allocated_range[0].size = gFreeMem - gMemBase; + gKernelArgs.num_virtual_allocated_ranges = 1; +} diff --git a/src/system/boot/platform/riscv/mmu.h b/src/system/boot/platform/riscv/mmu.h new file mode 100644 index 0000000000..17f202f987 --- /dev/null +++ b/src/system/boot/platform/riscv/mmu.h @@ -0,0 +1,22 @@ +/* + * Copyright 2021, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ + + +#ifndef MMU_H +#define MMU_H + + +#include + + +extern uint8* gMemBase; +extern size_t gTotalMem; + + +void mmu_init(); +void mmu_init_for_kernel(); + + +#endif /* MMU_H */ diff --git a/src/system/boot/platform/riscv/start.cpp b/src/system/boot/platform/riscv/start.cpp new file mode 100644 index 0000000000..fc21aa14d6 --- /dev/null +++ b/src/system/boot/platform/riscv/start.cpp @@ -0,0 +1,150 @@ +/* + * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2008, François Revol, revol@free.fr. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include +#include + +#include + +#include "console.h" +#include "cpu.h" +#include "mmu.h" +#include "fdt.h" +#include "Htif.h" +#include "virtio.h" +#include "graphics.h" + + +#define HEAP_SIZE (1024*1024) + +// GCC defined globals +extern void (*__ctor_list)(void); +extern void (*__ctor_end)(void); +extern uint8 __bss_start; +extern uint8 _end; + +extern "C" int main(stage2_args* args); +extern "C" void _start(int hartId, void* fdt); +extern "C" status_t arch_enter_kernel(struct kernel_args* kernelArgs, + addr_t kernelEntry, addr_t kernelStackTop);; + + +static uint32 sBootOptions; +static bool sBootOptionsValid = false; + + +static void +clear_bss(void) +{ + memset(&__bss_start, 0, &_end - &__bss_start); +} + + +static void +call_ctors(void) +{ + void (**f)(void); + + for (f = &__ctor_list; f < &__ctor_end; f++) + (**f)(); +} + + +static uint32 +check_for_boot_keys() +{ + uint32 options = 0; + bigtime_t t0 = system_time(); + while (system_time() - t0 < 100000) { + int key = virtio_input_get_key(); + switch(key) { + case 94 /* space */: + options |= BOOT_OPTION_MENU; + break; + } + } + return options; +} + + +extern "C" uint32 +platform_boot_options(void) +{ + if (!sBootOptionsValid) { + sBootOptions = check_for_boot_keys(); + sBootOptionsValid = true; +/* + if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT) + serial_enable(); +*/ + } + + return sBootOptions; +} + + +extern "C" void +platform_start_kernel(void) +{ + static struct kernel_args* args = &gKernelArgs; + preloaded_elf64_image* image = static_cast( + gKernelArgs.kernel_image.Pointer()); + + //smp_init_other_cpus(); + //serial_cleanup(); + //mmu_init_for_kernel(); + //smp_boot_other_cpus(); + + // Avoid interrupts from virtio devices before kernel driver takes control. + virtio_fini(); + + fdt_set_kernel_args(); + mmu_init_for_kernel(); + + dprintf("kernel entry at %lx\n", image->elf_header.e_entry); + + addr_t stackTop + = gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size; + arch_enter_kernel(args, image->elf_header.e_entry, stackTop); + + panic("kernel returned!\n"); + +} + + +extern "C" void +platform_exit(void) +{ + HtifShutdown(); +} + + +extern "C" void +_start(int hartId, void* fdt) +{ + HtifOutString("haiku_loader entry point\n"); + + clear_bss(); + fdt_init(fdt); + call_ctors(); + + stage2_args args; + args.heap_size = HEAP_SIZE; + args.arguments = NULL; + + // console_init(); + // virtio_init(); + cpu_init(); + mmu_init(); + //apm_init(); + //smp_init(); + + main(&args); +} diff --git a/src/system/boot/platform/riscv/video.cpp b/src/system/boot/platform/riscv/video.cpp new file mode 100644 index 0000000000..95ceb8a9c2 --- /dev/null +++ b/src/system/boot/platform/riscv/video.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "console.h" +#include "video.h" +//#include "mmu.h" +//#include "images.h" +#include "graphics.h" +#include "virtio.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +//#define TRACE_VIDEO +#ifdef TRACE_VIDEO +# define TRACE(x...) dprintf(x) +#else +# define TRACE(x...) ; +#endif + + +// #pragma mark - + +bool +video_mode_hook(Menu* menu, MenuItem* item) +{ + // nothing yet + return true; +} + + +Menu* +video_mode_menu() +{ + Menu* menu = new(nothrow) Menu(CHOICE_MENU, "Select Video Mode"); + MenuItem* item; + + menu->AddItem(item = new(nothrow) MenuItem("Default")); + item->SetMarked(true); + item->Select(true); + item->SetHelpText("The Default video mode is the one currently configured " + "in the system. If there is no mode configured yet, a viable mode will " + "be chosen automatically."); + + menu->AddSeparatorItem(); + menu->AddItem(item = new(nothrow) MenuItem("Return to main menu")); + item->SetType(MENU_ITEM_NO_CHOICE); + + return menu; +} + + +// #pragma mark - blit + + +extern "C" void +platform_blit4(addr_t frameBuffer, const uint8* data, + uint16 width, uint16 height, uint16 imageWidth, uint16 left, uint16 top) +{ +} + + +extern "C" void +platform_set_palette(const uint8* palette) +{ +} + + +// #pragma mark - + + +extern "C" void +platform_switch_to_logo(void) +{ + gKernelArgs.frame_buffer.physical_buffer.start = (addr_t)gFramebuf.colors; + gKernelArgs.frame_buffer.physical_buffer.size + = 4 * gFramebuf.stride * gFramebuf.height; + gKernelArgs.frame_buffer.width = gFramebuf.width; + gKernelArgs.frame_buffer.height = gFramebuf.height; + gKernelArgs.frame_buffer.depth = 32; + gKernelArgs.frame_buffer.bytes_per_row = 4 * gFramebuf.stride; + gKernelArgs.frame_buffer.enabled = true; + + video_display_splash(gKernelArgs.frame_buffer.physical_buffer.start); +} + + +extern "C" void +platform_switch_to_text_mode(void) +{ + gKernelArgs.frame_buffer.enabled = false; +} + + +extern "C" status_t +platform_init_video(void) +{ + virtio_init(); // we want heap initalized + Clear(gFramebuf, 0xff000000); + console_init(); + return B_OK; +} diff --git a/src/system/boot/platform/riscv/video.h b/src/system/boot/platform/riscv/video.h new file mode 100644 index 0000000000..041dc6219b --- /dev/null +++ b/src/system/boot/platform/riscv/video.h @@ -0,0 +1,18 @@ +/* +** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Distributed under the terms of the MIT License. +*/ +#ifndef VIDEO_H +#define VIDEO_H + + +#include + + +class Menu; +class MenuItem; + +bool video_mode_hook(Menu* menu, MenuItem* item); +Menu* video_mode_menu(); + +#endif /* VIDEO_H */ diff --git a/src/system/boot/platform/riscv/virtio.cpp b/src/system/boot/platform/riscv/virtio.cpp new file mode 100644 index 0000000000..091546abb9 --- /dev/null +++ b/src/system/boot/platform/riscv/virtio.cpp @@ -0,0 +1,301 @@ +/* + * Copyright 2021, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ + + +#include "virtio.h" + +#include +#include +#include +#include + + +enum { + maxVirtioDevices = 32, +}; + + +VirtioResources gVirtioDevList[maxVirtioDevices]; +int32_t gVirtioDevListLen = 0; + +DoublyLinkedList gVirtioDevices; +VirtioDevice* gKeyboardDev = NULL; +VirtioDevice* gDiskDev = NULL; + + +void* +aligned_malloc(size_t required_bytes, size_t alignment) +{ + void* p1; // original block + void** p2; // aligned block + int offset = alignment - 1 + sizeof(void*); + if ((p1 = (void*)malloc(required_bytes + offset)) == NULL) { + return NULL; + } + p2 = (void**)(((size_t)(p1) + offset) & ~(alignment - 1)); + p2[-1] = p1; + return p2; +} + + +void +aligned_free(void* p) +{ + free(((void**)p)[-1]); +} + + +VirtioResources* +ThisVirtioDev(uint32 deviceId, int n) +{ + for (int i = 0; i < gVirtioDevListLen; i++) { + VirtioRegs* volatile regs = gVirtioDevList[i].regs; + if (regs->signature != kVirtioSignature) continue; + if (regs->deviceId == deviceId) { + if (n == 0) return &gVirtioDevList[i]; else n--; + } + } + return NULL; +} + + +//#pragma mark VirtioDevice + +int32_t +VirtioDevice::AllocDesc() +{ + for (size_t i = 0; i < fQueueLen; i++) { + if ((fFreeDescs[i/32] & (1 << (i % 32))) != 0) { + fFreeDescs[i/32] &= ~((uint32_t)1 << (i % 32)); + return i; + } + } + return -1; +} + + +void +VirtioDevice::FreeDesc(int32_t idx) +{ + fFreeDescs[idx/32] |= (uint32_t)1 << (idx % 32); +} + + +VirtioDevice::VirtioDevice(const VirtioResources& devRes): fRegs(devRes.regs) +{ + gVirtioDevices.Insert(this); + + dprintf("+VirtioDevice\n"); + + fRegs->status = 0; // reset + + fRegs->status |= kVirtioConfigSAcknowledge; + fRegs->status |= kVirtioConfigSDriver; + dprintf("features: %08x\n", fRegs->deviceFeatures); + fRegs->status |= kVirtioConfigSFeaturesOk; + fRegs->status |= kVirtioConfigSDriverOk; + + fRegs->queueSel = 0; +// dprintf("queueNumMax: %d\n", fRegs->queueNumMax); + fQueueLen = fRegs->queueNumMax; + fRegs->queueNum = fQueueLen; + fLastUsed = 0; + + fDescs = (VirtioDesc*)aligned_malloc(sizeof(VirtioDesc) * fQueueLen, 4096); + memset(fDescs, 0, sizeof(VirtioDesc) * fQueueLen); + fAvail = (VirtioAvail*)aligned_malloc(sizeof(VirtioAvail) + + sizeof(uint16_t) * fQueueLen, 4096); + memset(fAvail, 0, sizeof(VirtioAvail) + sizeof(uint16_t) * fQueueLen); + fUsed = (VirtioUsed*)aligned_malloc(sizeof(VirtioUsed) + + sizeof(VirtioUsedItem) * fQueueLen, 4096); + memset(fUsed, 0, sizeof(VirtioUsed) + sizeof(VirtioUsedItem) * fQueueLen); + fFreeDescs = new(std::nothrow) uint32_t[(fQueueLen + 31)/32]; + memset(fFreeDescs, 0xff, sizeof(uint32_t) * ((fQueueLen + 31)/32)); + + fReqs = new(std::nothrow) IORequest*[fQueueLen]; + + fRegs->queueDescLow = (uint32_t)(uint64_t)fDescs; + fRegs->queueDescHi = (uint32_t)((uint64_t)fDescs >> 32); + fRegs->queueAvailLow = (uint32_t)(uint64_t)fAvail; + fRegs->queueAvailHi = (uint32_t)((uint64_t)fAvail >> 32); + fRegs->queueUsedLow = (uint32_t)(uint64_t)fUsed; + fRegs->queueUsedHi = (uint32_t)((uint64_t)fUsed >> 32); +/* + dprintf("fDescs: %p\n", fDescs); + dprintf("fAvail: %p\n", fAvail); + dprintf("fUsed: %p\n", fUsed); +*/ + fRegs->queueReady = 1; + + fRegs->config[0] = kVirtioInputCfgIdName; +// dprintf("name: %s\n", (const char*)(&fRegs->config[8])); +} + + +VirtioDevice::~VirtioDevice() +{ + gVirtioDevices.Remove(this); + fRegs->status = 0; // reset +} + + +void +VirtioDevice::ScheduleIO(IORequest** reqs, uint32 cnt) +{ + if (cnt < 1) return; + int32_t firstDesc, lastDesc; + for (uint32 i = 0; i < cnt; i++) { + int32_t desc = AllocDesc(); + if (desc < 0) {panic("virtio: no more descs"); return;} + if (i == 0) { + firstDesc = desc; + } else { + fDescs[lastDesc].flags |= kVringDescFlagsNext; + fDescs[lastDesc].next = desc; + reqs[i - 1]->next = reqs[i]; + } + fDescs[desc].addr = (uint64_t)(reqs[i]->buf); + fDescs[desc].len = reqs[i]->len; + fDescs[desc].flags = 0; + fDescs[desc].next = 0; + switch (reqs[i]->op) { + case ioOpRead: break; + case ioOpWrite: fDescs[desc].flags |= kVringDescFlagsWrite; break; + } + reqs[i]->state = ioStatePending; + lastDesc = desc; + } + int32_t idx = fAvail->idx % fQueueLen; + fReqs[idx] = reqs[0]; + fAvail->ring[idx] = firstDesc; + fAvail->idx++; + fRegs->queueNotify = 0; +} + + +void +VirtioDevice::ScheduleIO(IORequest* req) +{ + ScheduleIO(&req, 1); +} + + +IORequest* +VirtioDevice::ConsumeIO() +{ + if (fUsed->idx == fLastUsed) + return NULL; + + IORequest* req = fReqs[fLastUsed % fQueueLen]; + fReqs[fLastUsed % fQueueLen] = NULL; + req->state = ioStateDone; + int32 desc = fUsed->ring[fLastUsed % fQueueLen].id; + while (kVringDescFlagsNext & fDescs[desc].flags) { + int32 nextDesc = fDescs[desc].next; + FreeDesc(desc); + desc = nextDesc; + } + FreeDesc(desc); + fLastUsed++; + return req; +} + + +IORequest* +VirtioDevice::WaitIO() +{ + while (fUsed->idx == fLastUsed) {} + return ConsumeIO(); +} + + +//#pragma mark - + +void +virtio_register(addr_t base, size_t len, uint32 irq) +{ + VirtioRegs* volatile regs = (VirtioRegs* volatile)base; + + dprintf("virtio_register(0x%" B_PRIxADDR ", 0x%" B_PRIxSIZE ", " + "%" B_PRIu32 ")\n", base, len, irq); + dprintf(" signature: 0x%" B_PRIx32 "\n", regs->signature); + dprintf(" version: %" B_PRIu32 "\n", regs->version); + dprintf(" device id: %" B_PRIu32 "\n", regs->deviceId); + + if (!(gVirtioDevListLen < maxVirtioDevices)) { + dprintf("too many VirtIO devices\n"); + return; + } + gVirtioDevList[gVirtioDevListLen].regs = regs; + gVirtioDevList[gVirtioDevListLen].regsSize = len; + gVirtioDevList[gVirtioDevListLen].irq = irq; + gVirtioDevListLen++; +} + + +void +virtio_init() +{ + dprintf("virtio_init()\n"); + + int i = 0; + for (; ; i++) { + VirtioResources* devRes = ThisVirtioDev(kVirtioDevInput, i); + if (devRes == NULL) break; + VirtioRegs* volatile regs = devRes->regs; + regs->config[0] = kVirtioInputCfgIdName; + dprintf("virtio_input[%d]: %s\n", i, (const char*)(®s->config[8])); + if (i == 0) + gKeyboardDev = new(std::nothrow) VirtioDevice(*devRes); + } + dprintf("virtio_input count: %d\n", i); + for (int i = 0; i < 4; i++) + gKeyboardDev->ScheduleIO(new(std::nothrow) IORequest(ioOpWrite, + malloc(sizeof(VirtioInputPacket)), sizeof(VirtioInputPacket))); +} + + +void +virtio_fini() +{ + auto it = gVirtioDevices.GetIterator(); + while (VirtioDevice* dev = it.Next()) { + dev->Regs()->status = 0; // reset + } +} + + +int +virtio_input_get_key() +{ + IORequest* req = gKeyboardDev->ConsumeIO(); + if (req == NULL) + return 0; + + VirtioInputPacket &pkt = *(VirtioInputPacket*)req->buf; + + int key = 0; + if (pkt.type == 1 && pkt.value == 1) + key = pkt.code; + + free(req->buf); req->buf = NULL; delete req; + gKeyboardDev->ScheduleIO(new(std::nothrow) IORequest(ioOpWrite, + malloc(sizeof(VirtioInputPacket)), sizeof(VirtioInputPacket))); + + return key; +} + + +int +virtio_input_wait_for_key() +{ + int key = 0; + + do { + key = virtio_input_get_key(); + } while (key == 0); + + return key; +} diff --git a/src/system/boot/platform/riscv/virtio.h b/src/system/boot/platform/riscv/virtio.h new file mode 100644 index 0000000000..a0edf8c20a --- /dev/null +++ b/src/system/boot/platform/riscv/virtio.h @@ -0,0 +1,78 @@ +/* + * Copyright 2021, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ + + +#ifndef _VIRTIO_H_ +#define _VIRTIO_H_ + + +#include +#include + + +struct VirtioResources { + VirtioRegs* volatile regs; + size_t regsSize; + int32_t irq; +}; + +enum IOState { + ioStateInactive, + ioStatePending, + ioStateDone, + ioStateFailed, +}; + +enum IOOperation { + ioOpRead, + ioOpWrite, +}; + +struct IORequest { + IOState state; + IOOperation op; + void* buf; + size_t len; + IORequest* next; + + IORequest(IOOperation op, void* buf, size_t len): state(ioStateInactive), + op(op), buf(buf), len(len), next(NULL) {} +}; + +class VirtioDevice : public DoublyLinkedListLinkImpl { +private: + VirtioRegs* volatile fRegs; + size_t fQueueLen; + VirtioDesc* volatile fDescs; + VirtioAvail* volatile fAvail; + VirtioUsed* volatile fUsed; + uint32_t* fFreeDescs; + uint32_t fLastUsed; + IORequest** fReqs; + + int32_t AllocDesc(); + void FreeDesc(int32_t idx); + +public: + VirtioDevice(const VirtioResources& devRes); + ~VirtioDevice(); + inline VirtioRegs* volatile Regs() {return fRegs;} + void ScheduleIO(IORequest** reqs, uint32 cnt); + void ScheduleIO(IORequest* req); + IORequest* ConsumeIO(); + IORequest* WaitIO(); +}; + + +void virtio_init(); +void virtio_fini(); +void virtio_register(addr_t base, size_t len, uint32 irq); + +VirtioResources* ThisVirtioDev(uint32 deviceId, int n); + +int virtio_input_get_key(); +int virtio_input_wait_for_key(); + +#endif // _VIRTIO_H_ diff --git a/src/system/ldscripts/riscv64/boot_loader_riscv.ld b/src/system/ldscripts/riscv64/boot_loader_riscv.ld new file mode 100644 index 0000000000..716c3a54d0 --- /dev/null +++ b/src/system/ldscripts/riscv64/boot_loader_riscv.ld @@ -0,0 +1,46 @@ +OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv") +OUTPUT_ARCH(riscv) + +ENTRY(_start) +SECTIONS +{ + . = 0x80000000; + + /* text/read-only data */ + .text : { + *(.text.head) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + } + + . = ALIGN(0x8); + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + .rodata : { *(.rodata .rodata.*) } + + /* writable data */ + . = ALIGN(0x1000); + __data_start = .; + .data : { + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + } + .got : { *(.got.plt) *(.got) } + .dynamic : { gDynamic = .; *(.dynamic) } + + /* uninitialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + .bss.stack : { *(.bss.stack) } + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors .stab .stabstr .debug*) } +}