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 :
|
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 ;
|
||||||
|
|||||||
@@ -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) ;
|
||||||
|
|
||||||
|
|||||||
@@ -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 ] :
|
||||||
|
|||||||
@@ -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;");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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, [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 */
|
||||||
@@ -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, [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;
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -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, [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);
|
||||||
|
}
|
||||||
@@ -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