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 <[email protected]>
This commit is contained in:
X512
2021-05-27 17:35:27 +00:00
committed by Alex von Gluck IV
parent 44a8696dc5
commit a182bd6eb5
29 changed files with 2007 additions and 8 deletions
+4 -1
View File
@@ -276,7 +276,7 @@ rule KernelArchitectureSetup architecture
case riscv64 : case riscv64 :
HAIKU_KERNEL_PLATFORM ?= efi ; HAIKU_KERNEL_PLATFORM ?= efi ;
HAIKU_BOOT_TARGETS += efi ; HAIKU_BOOT_TARGETS += efi riscv ;
HAIKU_BOOT_SDIMAGE_BEGIN = 2 ; # KiB HAIKU_BOOT_SDIMAGE_BEGIN = 2 ; # KiB
@@ -526,6 +526,9 @@ rule KernelArchitectureSetup architecture
HAIKU_BOOT_$(bootTarget:U)_C++FLAGS += -m68020-60 ; HAIKU_BOOT_$(bootTarget:U)_C++FLAGS += -m68020-60 ;
# TODO: coldfire (FireBee) # 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 * : case * :
# all other bootloaders are non-PIC # all other bootloaders are non-PIC
HAIKU_BOOT_$(bootTarget:U)_CCFLAGS += -fno-pic -Wno-error=main ; HAIKU_BOOT_$(bootTarget:U)_CCFLAGS += -fno-pic -Wno-error=main ;
+7
View File
@@ -310,6 +310,10 @@ for platform in [ MultiBootSubDirSetup ] {
ldflags += -Map=efi.map ; ldflags += -Map=efi.map ;
} }
if $(TARGET_BOOT_PLATFORM) = riscv {
ldflags += -z,notext ;
}
BootLd boot_loader_$(platform:G=) : BootLd boot_loader_$(platform:G=) :
boot_platform_$(platform:G=).o boot_platform_$(platform:G=).o
$(archObject:G=$(archGrist)) $(archObject:G=$(archGrist))
@@ -384,6 +388,9 @@ for platform in [ MultiBootSubDirSetup ] {
: -Bstatic : -Bstatic
; ;
case riscv :
BuildBiosLoader haiku_loader.$(TARGET_BOOT_PLATFORM) : boot_loader_$(TARGET_BOOT_PLATFORM) ;
case next_m68k : case next_m68k :
BuildAoutLoader haiku_loader.$(TARGET_BOOT_PLATFORM) : boot_loader_$(TARGET_BOOT_PLATFORM) ; BuildAoutLoader haiku_loader.$(TARGET_BOOT_PLATFORM) : boot_loader_$(TARGET_BOOT_PLATFORM) ;
+1 -1
View File
@@ -29,7 +29,7 @@ local kernelGenericDriverSources =
; ;
local platform ; local platform ;
for platform in [ MultiBootSubDirSetup u-boot efi ] { for platform in [ MultiBootSubDirSetup u-boot efi riscv ] {
on $(platform) { on $(platform) {
DEFINES += _BOOT_MODE ; DEFINES += _BOOT_MODE ;
BootMergeObject [ FGristFiles boot_arch_$(TARGET_KERNEL_ARCH).o ] : BootMergeObject [ FGristFiles boot_arch_$(TARGET_KERNEL_ARCH).o ] :
+5 -6
View File
@@ -58,16 +58,15 @@ arch_ucode_load(BootVolume& volume)
extern "C" bigtime_t extern "C" bigtime_t
system_time() system_time()
{ {
#warning Implement system_time in RISCV bootloader! // TODO: units conversion
return 0; return CpuTime();
} }
extern "C" void extern "C" void
spin(bigtime_t microseconds) spin(bigtime_t microseconds)
{ {
#warning Implment spin in RISCV bootloader! bigtime_t time = system_time();
//bigtime_t time = system_time(); while ((system_time() - time) < microseconds)
//while ((system_time() - time) < microseconds) asm volatile ("nop;");
// asm volatile ("nop;");
} }
+58
View File
@@ -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 ] ;
+254
View File
@@ -0,0 +1,254 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Copyright 2011, Rene Gollent, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "console.h"
#include "video.h"
#include "graphics.h"
#include <Htif.h>
#include "virtio.h"
#include <SupportDefs.h>
#include <util/kernel_cpp.h>
#include <boot/stage2.h>
#include <string.h>
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;
}
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT license.
*
* Author:
* François Revol, [email protected].
*/
#ifndef CONSOLE_H
#define CONSOLE_H
#include <boot/platform/generic/text_console.h>
#ifdef __cplusplus
extern "C" {
#endif
extern struct Screen* gScreen;
extern status_t console_init(void);
#ifdef __cplusplus
}
#endif
#endif /* CONSOLE_H */
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "cpu.h"
#include <OS.h>
#include <boot/platform.h>
#include <boot/stdio.h>
#include <boot/kernel_args.h>
#include <boot/stage2.h>
#include <arch/cpu.h>
#include <arch_kernel.h>
#include <arch_system_info.h>
#include <string.h>
//#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
}
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef CPU_H
#define CPU_H
#include <SupportDefs.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void cpu_init(void);
#ifdef __cplusplus
}
#endif
#endif /* CPU_H */
+20
View File
@@ -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 .
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright 2004-2007, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#include <Htif.h>
#include <boot/platform.h>
#include <boot/stdio.h>
#include <stdarg.h>
#include <string.h>
#include <Errors.h>
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;
}
+228
View File
@@ -0,0 +1,228 @@
/*
* Copyright 2003-2006, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "bios.h"
#include "virtio.h"
#include <KernelExport.h>
#include <boot/platform.h>
#include <boot/partitions.h>
#include <boot/stdio.h>
#include <boot/stage2.h>
#include <AutoDeleter.h>
#include <string.h>
#include <new>
//#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<VirtioDevice> 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<char> 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<VirtioDevice> virtioDev(
new(std::nothrow) VirtioDevice(*devRes));
if (!virtioDev.IsSet())
panic("Can't allocate memory for VirtioDevice!");
ObjectDeleter<VirtioBlockDevice> 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<VirtioBlockDevice> 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()
{
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright 2020-2021, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <asm_defs.h>
.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)
+92
View File
@@ -0,0 +1,92 @@
/*
* Copyright 2021, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#include "fdt.h"
#include <SupportDefs.h>
#include <ByteOrder.h>
#include <KernelExport.h>
#include <boot/stage2.h>
extern "C" {
#include <libfdt.h>
}
#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");
}
+18
View File
@@ -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_
@@ -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
Binary file not shown.
@@ -0,0 +1,97 @@
/*
* Copyright 2021, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#include "graphics.h"
RasBuf32 gFramebuf = {NULL, 0, 0, 0};
void
Clear(RasBuf32 vb, uint32_t c)
{
vb.stride -= vb.width;
for (; vb.height > 0; vb.height--) {
for (int x = 0; x < vb.width; x++) {
*vb.colors = c;
vb.colors++;
}
vb.colors += vb.stride;
}
}
template <typename Color>
RasBuf<Color>
RasBuf<Color>::Clip(int x, int y, int w, int h) const
{
RasBuf<Color> 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<uint8>;
template class RasBuf<uint32>;
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;
}
}
+45
View File
@@ -0,0 +1,45 @@
/*
* Copyright 2021, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef _GRAPHICS_H_
#define _GRAPHICS_H_
#include <SupportDefs.h>
template <typename Color>
struct RasBuf {
Color* colors;
int32 stride, width, height;
RasBuf<Color> Clip(int x, int y, int w, int h) const;
};
typedef RasBuf<uint8> RasBuf8;
typedef RasBuf<uint32> 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_
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright 2021, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#include <Htif.h>
// 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);
}
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright 2004-2007, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "smp.h"
#include "video.h"
#include <boot/menu.h>
#include <boot/platform/generic/text_menu.h>
#include <safemode.h>
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);
}
+123
View File
@@ -0,0 +1,123 @@
/*
* Copyright 2004-2007, Axel Dörfler, [email protected].
* Based on code written by Travis Geiselbrecht for NewOS.
*
* Distributed under the terms of the MIT License.
*/
#include "mmu.h"
#include <boot/platform.h>
#include <boot/stdio.h>
#include <boot/kernel_args.h>
#include <boot/stage2.h>
#include <arch/cpu.h>
#include <arch_kernel.h>
#include <kernel.h>
#include <OS.h>
#include <string.h>
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;
}
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright 2021, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef MMU_H
#define MMU_H
#include <SupportDefs.h>
extern uint8* gMemBase;
extern size_t gTotalMem;
void mmu_init();
void mmu_init_for_kernel();
#endif /* MMU_H */
+150
View File
@@ -0,0 +1,150 @@
/*
* Copyright 2003-2010, Axel Dörfler, [email protected].
* Copyright 2008, François Revol, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h>
#include <boot/platform.h>
#include <boot/heap.h>
#include <boot/stage2.h>
#include <arch/cpu.h>
#include <string.h>
#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<preloaded_elf64_image*>(
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);
}
+117
View File
@@ -0,0 +1,117 @@
/*
* Copyright 2004-2007, Axel Dörfler, [email protected].
* 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 <arch/cpu.h>
#include <boot/stage2.h>
#include <boot/platform.h>
#include <boot/menu.h>
#include <boot/kernel_args.h>
#include <boot/platform/generic/video.h>
#include <util/list.h>
#include <drivers/driver_settings.h>
#include <GraphicsDefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#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;
}
+18
View File
@@ -0,0 +1,18 @@
/*
** Copyright 2004, Axel Dörfler, [email protected]. All rights reserved.
** Distributed under the terms of the MIT License.
*/
#ifndef VIDEO_H
#define VIDEO_H
#include <SupportDefs.h>
class Menu;
class MenuItem;
bool video_mode_hook(Menu* menu, MenuItem* item);
Menu* video_mode_menu();
#endif /* VIDEO_H */
+301
View File
@@ -0,0 +1,301 @@
/*
* Copyright 2021, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#include "virtio.h"
#include <new>
#include <string.h>
#include <malloc.h>
#include <KernelExport.h>
enum {
maxVirtioDevices = 32,
};
VirtioResources gVirtioDevList[maxVirtioDevices];
int32_t gVirtioDevListLen = 0;
DoublyLinkedList<VirtioDevice> 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*)(&regs->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;
}
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright 2021, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef _VIRTIO_H_
#define _VIRTIO_H_
#include <virtio_defs.h>
#include <util/DoublyLinkedList.h>
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<VirtioDevice> {
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_
@@ -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*) }
}