Skip to content

Commit

Permalink
[riscv64] Add support for qemu-ramfb and enable framebuffer
Browse files Browse the repository at this point in the history
  • Loading branch information
aenrbes committed Nov 18, 2024
1 parent fa29c4c commit 66137b1
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 6 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ elseif (${ARCH} STREQUAL "x86_64")
elseif (${ARCH} STREQUAL "riscv64")

set(QEMU_ARCH_OPTS "-device virtio-blk-device,drive=img1")
set(QEMU_ARCH_OPTS "${QEMU_ARCH_OPTS} -nographic")
set(QEMU_ARCH_OPTS "${QEMU_ARCH_OPTS} -M virt")
set(QEMU_ARCH_OPTS "${QEMU_ARCH_OPTS} -vga none -device ramfb")
set(QEMU_ARCH_OPTS "${QEMU_ARCH_OPTS} -serial stdio -M virt")
set(QEMU_ARCH_OPTS "${QEMU_ARCH_OPTS} -kernel ${U_BOOT_BIN}")

endif()
Expand Down
10 changes: 10 additions & 0 deletions config/mod_ramfb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: BSD-2-Clause */

/*
* This is a TEMPLATE. The actual config header file is generated by CMake
* and put in <BUILD_DIR>/tilck_gen_headers/.
*/

#pragma once

#cmakedefine01 MOD_ramfb
9 changes: 9 additions & 0 deletions kernel/arch/riscv/early_fdt.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: BSD-2-Clause */

#include <tilck_gen_headers/mod_ramfb.h>
#include <tilck/common/basic_defs.h>
#include <tilck/common/boot.h>
#include <tilck/common/string_util.h>
Expand Down Expand Up @@ -28,6 +29,8 @@ struct simplefb_format {
struct simplefb_bitfield alpha;
};

int init_ramfb(void *fdt);

void *fdt_blob; //save virtual address of fdt

static ulong initrd_paddr;
Expand Down Expand Up @@ -393,6 +396,12 @@ multiboot_info_t *parse_fdt(void *fdt_pa)
fdt_parse_reserved_memory(fdt_pa);
fdt_parse_framebuffer(fdt_pa);

if (MOD_ramfb) {
if (init_ramfb(fdt_pa) == -ENODEV) {
strcat(cmdline_buf, " -sercon");

Check warning on line 401 in kernel/arch/riscv/early_fdt.c

View check run for this annotation

Codecov / codecov/patch

kernel/arch/riscv/early_fdt.c#L400-L401

Added lines #L400 - L401 were not covered by tests
}
}

setup_multiboot_info(initrd_paddr, initrd_size);

fdt_blob = PA_TO_LIN_VA(fdt_pa);
Expand Down
196 changes: 196 additions & 0 deletions modules/ramfb/riscv/ramfb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/* SPDX-License-Identifier: BSD-2-Clause */

#include <tilck/common/basic_defs.h>
#include <tilck/common/string_util.h>
#include <tilck/common/printk.h>
#include <tilck/common/utils.h>
#include <tilck/kernel/errno.h>
#include <tilck/kernel/hal.h>
#include <tilck/kernel/modules.h>

#include <3rd_party/fdt_helper.h>
#include <libfdt.h>

#define BE16(x) __builtin_bswap16(x)
#define BE32(x) __builtin_bswap32(x)
#define BE64(x) __builtin_bswap64(x)

#define QEMU_FWCFG_SELECTOR (qemu_fwcfg_base + 0x8UL)
#define QEMU_FWCFG_DATA qemu_fwcfg_base
#define QEMU_FWCFG_ADDR (qemu_fwcfg_base + 0x10UL)

#define fourcc_code(a, b, c, d) ((u32)(a) | ((u32)(b) << 8) | \
((u32)(c) << 16) | ((u32)(d) << 24))

#define QEMU_RAMFB_RGB888 fourcc_code('R', 'G', '2', '4')
#define QEMU_RAMFB_XRGB8888 fourcc_code('X', 'R', '2', '4')
#define QEMU_RAMFB_RGB565 fourcc_code('R', 'G', '1', '6')

struct qemu_ramfb_cfg {
u64 addr;
u32 format;
u32 flags;
u32 width;
u32 height;
u32 stride;
} __attribute__((packed));

struct qemu_fwcfg_dma_access {
u32 cntl;
u32 len;
u64 addr;
} __attribute__((packed));

struct qemu_fwcfg_file {
u32 size;
u16 select;
u16 reserved;
char name[56];
} __attribute__((packed));

static ulong qemu_fwcfg_base;
static ulong simplefb_paddr;
static u32 simplefb_pitch;
static u32 simplefb_width;
static u32 simplefb_height;
static u32 simplefb_format;

static void
qemu_fwcfg_dma_trans(void *addr, u32 len, u32 cntl)

Check warning on line 59 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L59

Added line #L59 was not covered by tests
{
struct qemu_fwcfg_dma_access access;

access.cntl = BE32(cntl);
access.len = BE32(len);
access.addr = BE64((u64)addr);
mmio_writeq((BE64((u64)&access)), (void *)QEMU_FWCFG_ADDR);

Check warning on line 66 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L63-L66

Added lines #L63 - L66 were not covered by tests

while (BE32(access.cntl) & (u32)(~0x1))

Check warning on line 68 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L68

Added line #L68 was not covered by tests
;
}

Check warning on line 70 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L70

Added line #L70 was not covered by tests

static void qemu_fwcfg_dma_sel_read(void *buf, u32 sel, u32 len)

Check warning on line 72 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L72

Added line #L72 was not covered by tests
{
qemu_fwcfg_dma_trans(buf, len, (sel << 16) | 0x08 | 0x02);
}

Check warning on line 75 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L74-L75

Added lines #L74 - L75 were not covered by tests

static void qemu_fwcfg_dma_sel_write(void *buf, u32 sel, u32 len)

Check warning on line 77 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L77

Added line #L77 was not covered by tests
{
qemu_fwcfg_dma_trans(buf, len, (sel << 16) | 0x08 | 0x10);
}

Check warning on line 80 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L79-L80

Added lines #L79 - L80 were not covered by tests

static void qemu_fwcfg_dma_read(void *buf, int len)

Check warning on line 82 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L82

Added line #L82 was not covered by tests
{
qemu_fwcfg_dma_trans(buf, len, 0x02);
}

Check warning on line 85 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L84-L85

Added lines #L84 - L85 were not covered by tests

static int fdt_parse_fwcfg(void *fdt)

Check warning on line 87 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L87

Added line #L87 was not covered by tests
{
int node, rc;
u64 addr, size;
char compat[] = "qemu,fw-cfg-mmio";

Check warning on line 91 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L91

Added line #L91 was not covered by tests

node = fdt_node_offset_by_compatible(fdt, -1, compat);
if (node < 0)
return -EINVAL;

Check warning on line 95 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L93-L95

Added lines #L93 - L95 were not covered by tests

rc = fdt_get_node_addr_size(fdt, node, 0, &addr, &size);
if (rc)
return -EINVAL;

Check warning on line 99 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L97-L99

Added lines #L97 - L99 were not covered by tests

qemu_fwcfg_base = addr;
return 0;

Check warning on line 102 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L101-L102

Added lines #L101 - L102 were not covered by tests
}

static int fdt_parse_simplefb(void *fdt)

Check warning on line 105 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L105

Added line #L105 was not covered by tests
{
const fdt32_t *prop;
int node, len, rc;
u64 addr, size;
char compat[] = "simple-framebuffer";

Check warning on line 110 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L110

Added line #L110 was not covered by tests

node = fdt_node_offset_by_compatible(fdt, -1, compat);
if (node < 0)
return -EINVAL;

Check warning on line 114 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L112-L114

Added lines #L112 - L114 were not covered by tests

prop = fdt_getprop(fdt, node, "width", &len);
if (!prop)
return -EINVAL;

Check warning on line 118 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L116-L118

Added lines #L116 - L118 were not covered by tests

simplefb_width = fdt32_to_cpu(*prop);

Check warning on line 120 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L120

Added line #L120 was not covered by tests

prop = fdt_getprop(fdt, node, "height", &len);
if (!prop)
return -EINVAL;

Check warning on line 124 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L122-L124

Added lines #L122 - L124 were not covered by tests

simplefb_height = fdt32_to_cpu(*prop);

Check warning on line 126 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L126

Added line #L126 was not covered by tests

prop = fdt_getprop(fdt, node, "stride", &len);
if (!prop)
return -EINVAL;

Check warning on line 130 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L128-L130

Added lines #L128 - L130 were not covered by tests

simplefb_pitch = fdt32_to_cpu(*prop);

Check warning on line 132 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L132

Added line #L132 was not covered by tests

rc = fdt_get_node_addr_size(fdt, node, 0, &addr, &size);
if (rc)
return -EINVAL;

Check warning on line 136 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L134-L136

Added lines #L134 - L136 were not covered by tests

simplefb_paddr = addr;

Check warning on line 138 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L138

Added line #L138 was not covered by tests

prop = fdt_getprop(fdt, node, "format", &len);
if (!prop)
return -EINVAL;

Check warning on line 142 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L140-L142

Added lines #L140 - L142 were not covered by tests

if (!strcmp((void *)prop, "r8g8b8"))
simplefb_format = QEMU_RAMFB_RGB888;
else if (!strcmp((void *)prop, "x8r8g8b8"))
simplefb_format = QEMU_RAMFB_XRGB8888;
else if (!strcmp((void *)prop, "r5g6b5"))
simplefb_format = QEMU_RAMFB_RGB565;

Check warning on line 149 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L144-L149

Added lines #L144 - L149 were not covered by tests

return 0;

Check warning on line 151 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L151

Added line #L151 was not covered by tests
}

int init_ramfb(void *fdt)

Check warning on line 154 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L154

Added line #L154 was not covered by tests
{
int rc;
bool found = false;
u32 count = 0, select = 0;

Check warning on line 158 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L157-L158

Added lines #L157 - L158 were not covered by tests
struct qemu_fwcfg_file file;

rc = fdt_parse_fwcfg(fdt);
if (rc)
return -EINVAL;

Check warning on line 163 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L161-L163

Added lines #L161 - L163 were not covered by tests

rc = fdt_parse_simplefb(fdt);
if (rc)
return -EINVAL;

Check warning on line 167 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L165-L167

Added lines #L165 - L167 were not covered by tests

qemu_fwcfg_dma_sel_read(&count, 0x19, sizeof(count));
count = BE32(count);

Check warning on line 170 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L169-L170

Added lines #L169 - L170 were not covered by tests

for (u32 i = 0; i < count; i++) {
qemu_fwcfg_dma_read(&file, sizeof(file));
if (!strcmp(file.name, "etc/ramfb")) {
found = true;
select = BE16(file.select);
break;

Check warning on line 177 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L172-L177

Added lines #L172 - L177 were not covered by tests
}
}

if (!found)
return -ENODEV;

Check warning on line 182 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L181-L182

Added lines #L181 - L182 were not covered by tests

struct qemu_ramfb_cfg ramfb_cfg = {
.addr = BE64(simplefb_paddr),
.format = BE32(simplefb_format),

Check warning on line 186 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L184-L186

Added lines #L184 - L186 were not covered by tests
.flags = BE32(0),
.width = BE32(simplefb_width),
.height = BE32(simplefb_height),
.stride = BE32(simplefb_pitch)

Check warning on line 190 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L188-L190

Added lines #L188 - L190 were not covered by tests
};

qemu_fwcfg_dma_sel_write(&ramfb_cfg, select, sizeof(ramfb_cfg));
return 0;

Check warning on line 194 in modules/ramfb/riscv/ramfb.c

View check run for this annotation

Codecov / codecov/patch

modules/ramfb/riscv/ramfb.c#L193-L194

Added lines #L193 - L194 were not covered by tests
}

9 changes: 6 additions & 3 deletions other/bsp/riscv64/qemu-virt/uEnv.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This is the sample uEnv.txt file for qemu-virt U-boot

# kernel command line can be modified here
bootargs=tilck -sercon -panic_regs -panic_mmap
bootargs=tilck -panic_regs -panic_mmap

# When bootelf kernel, do not directly jump into kernel, bootelf is only used
# to properly load tilck in elf format.
Expand All @@ -24,11 +24,14 @@ fitfile=image.fit
kerneladdr=@KERNEL_LOAD@

# use FDT that came with uboot
setupfdt1=setexpr newfdt @KERNEL_LOAD@ + 0x800000;fdt move ${fdtaddr} ${newfdt}; fdt addr ${newfdt}; fdt resize
setupfdt1=setexpr newfdt @KERNEL_LOAD@ + 0x800000;fdt move ${fdtaddr} ${newfdt}; fdt addr ${newfdt}; fdt resize 4096

# set fdt initrd
setupird=fdt set /chosen linux,initrd-start <0x0 0x${initrd_start}>; fdt set /chosen linux,initrd-end <0x0 0x${initrd_end}>

# set fdt simple-framebuffer
setupfb=setexpr simplefb_addr @KERNEL_LOAD@ + 0x900000; fdt mknode / simplefb; fdt set /simplefb compatible "simple-framebuffer"; fdt set /simplefb width <0x190>; fdt set /simplefb height <0x12c>; fdt set /simplefb stride <0x4b0>; fdt set /simplefb format "r8g8b8"; fdt set /simplefb reg <0x0 0x${simplefb_addr} 0x0 0x0>

# set fdt bootargs
setupfdt2=fdt set /chosen bootargs "${bootargs}"

Expand All @@ -42,4 +45,4 @@ loadkernel=bootm start ${loadaddr} ${loadaddr} ${newfdt}; bootm loados ${loadadd
message=echo Booting kernel with ramdisk ${initrd_start}-${initrd_end}

# the real boot command be executed
boot2=run loadfit; run setupfdt1; run setupfdt2; run loadkernel; run setupird; run message; bootm go ${loadaddr} - ${newfdt};
boot2=run loadfit; run setupfdt1; run setupfdt2; run setupfb; run loadkernel; run setupird; run message; bootm go ${loadaddr} - ${newfdt};
7 changes: 6 additions & 1 deletion tests/runners/single_test_run
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,12 @@ def run_the_vm():
global g_gcda_buf
global g_gcda_file

arch_opts = "@QEMU_ARCH_OPTS@".split(' ')
arch_opts_str = "@QEMU_ARCH_OPTS@"
if ARCH in ['riscv64']:
arch_opts_str = arch_opts_str.replace("-serial stdio ", "")
arch_opts_str = arch_opts_str.replace("-device ramfb ", "")

arch_opts = arch_opts_str.split(' ')
args = [
'qemu-system-@ARCH@',
'-m', str(VM_MEMORY_SIZE_IN_MB),
Expand Down

0 comments on commit 66137b1

Please sign in to comment.