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:
@@ -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 ;
|
||||
|
||||
@@ -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) ;
|
||||
|
||||
|
||||
@@ -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 ] :
|
||||
|
||||
@@ -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;");
|
||||
}
|
||||
|
||||
@@ -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 ] ;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 <SupportDefs.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void cpu_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CPU_H */
|
||||
@@ -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 .
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
|
||||
* 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;
|
||||
}
|
||||
@@ -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 <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()
|
||||
{
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 <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);
|
||||
}
|
||||
@@ -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 <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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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 <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);
|
||||
}
|
||||
@@ -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 <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;
|
||||
}
|
||||
@@ -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 <SupportDefs.h>
|
||||
|
||||
|
||||
class Menu;
|
||||
class MenuItem;
|
||||
|
||||
bool video_mode_hook(Menu* menu, MenuItem* item);
|
||||
Menu* video_mode_menu();
|
||||
|
||||
#endif /* VIDEO_H */
|
||||
@@ -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*)(®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;
|
||||
}
|
||||
@@ -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*) }
|
||||
}
|
||||
Reference in New Issue
Block a user