From a77b6614a3799aa899509161db911a2c20ad20a2 Mon Sep 17 00:00:00 2001 From: mohamed-mokhtar-elkomy Date: Sat, 25 Apr 2026 13:31:34 +0200 Subject: [PATCH 1/4] feat: add OpenSBI platform for IKR Cyclone 10 GX --- platform/ikr/Kconfig | 16 +++ platform/ikr/configs/defconfig | 0 platform/ikr/objects.mk | 102 +++++++++++++++++++ platform/ikr/platform.c | 177 +++++++++++++++++++++++++++++++++ 4 files changed, 295 insertions(+) create mode 100644 platform/ikr/Kconfig create mode 100644 platform/ikr/configs/defconfig create mode 100644 platform/ikr/objects.mk create mode 100644 platform/ikr/platform.c diff --git a/platform/ikr/Kconfig b/platform/ikr/Kconfig new file mode 100644 index 00000000000..d73825da99f --- /dev/null +++ b/platform/ikr/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: BSD-2-Clause + +# +# All mandatory drivers or libraries for this platform should +# be directly selected by the PLATFORM_xyz kconfig symbol. +# +# All optional drivers or libraries for this platform should +# be enabled via configs/defconfig of this platform. +# +config PLATFORM_TEMPLATE + bool + select IPI_MSWI + select IRQCHIP_PLIC + select SERIAL_UART8250 + select TIMER_MTIMER + default y diff --git a/platform/ikr/configs/defconfig b/platform/ikr/configs/defconfig new file mode 100644 index 00000000000..e69de29bb2d diff --git a/platform/ikr/objects.mk b/platform/ikr/objects.mk new file mode 100644 index 00000000000..4ecff913c11 --- /dev/null +++ b/platform/ikr/objects.mk @@ -0,0 +1,102 @@ +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2019 Western Digital Corporation or its affiliates. +# + +# IKR config: cyclone 10GX starting address +FW_TEXT_START=0x40000000 + +# Compiler pre-processor flags +platform-cppflags-y = + +# C Compiler and assembler flags. +platform-cflags-y = +platform-asflags-y = + +# Linker flags: additional libraries and object files that the platform +# code needs can be added here +platform-ldflags-y = + +# +# Command for platform specific "make run" +# Useful for development and debugging on plaftform simulator (such as QEMU) +# +# platform-runcmd = your_platform_run.sh + +# +# Platform RISC-V XLEN, ABI, ISA and Code Model configuration. +# These are optional parameters but platforms can optionaly provide it. +# Some of these are guessed based on GCC compiler capabilities +# +# PLATFORM_RISCV_XLEN = 64 +# PLATFORM_RISCV_ABI = lp64 +# PLATFORM_RISCV_ISA = rv64imafdc +# PLATFORM_RISCV_CODE_MODEL = medany + +# Space separated list of object file names to be compiled for the platform +platform-objs-y += platform.o + +# +# If the platform support requires a builtin device tree file, the name of +# the device tree compiled file should be specified here. The device tree +# source file be in the form
.dts +# +# platform-objs-y +=
.o + +# Optional parameter for path to external FDT +# FW_FDT_PATH="path to platform flattened device tree file" + +# +# Dynamic firmware configuration. +# Optional parameters are commented out. Uncomment and define these parameters +# as needed. +# +FW_DYNAMIC=n + +# +# Jump firmware configuration. +# Optional parameters are commented out. Uncomment and define these parameters +# as needed. +# +FW_JUMP=n +# This needs to be 4MB aligned for 32-bit support +# This needs to be 2MB aligned for 64-bit support +# ifeq ($(PLATFORM_RISCV_XLEN), 32) +# FW_JUMP_OFFSET=0x400000 +# else +# FW_JUMP_OFFSET=0x200000 +# endif +# FW_JUMP_FDT_OFFSET=0x2200000 +# +# You can use fixed address for jump firmware as an alternative option. +# SBI will prefer "_ADDR" if both "_ADDR" and "_OFFSET" are +# defined +# ifeq ($(PLATFORM_RISCV_XLEN), 32) +# FW_JUMP_ADDR=0x80400000 +# else +# FW_JUMP_ADDR=0x80200000 +# endif +# FW_JUMP_FDT_ADDR=0x82200000 + +# +# Firmware with payload configuration. +# Optional parameters are commented out. Uncomment and define these parameters +# as needed. +# +FW_PAYLOAD=y +# This needs to be 4MB aligned for 32-bit support +# This needs to be 2MB aligned for 64-bit support +ifeq ($(PLATFORM_RISCV_XLEN), 32) +FW_PAYLOAD_OFFSET=0x400000 +else +FW_PAYLOAD_OFFSET=0x200000 +endif +# FW_PAYLOAD_ALIGN=0x1000 +# FW_PAYLOAD_PATH="path to next boot stage binary image file" +FW_PAYLOAD_FDT_OFFSET=0x2200000 +# +# You can use fixed address for payload firmware as an alternative option. +# SBI will prefer "FW_PAYLOAD_FDT_ADDR" if both "FW_PAYLOAD_FDT_OFFSET" +# and "FW_PAYLOAD_FDT_ADDR" are defined. +# FW_PAYLOAD_FDT_ADDR=0x82200000 diff --git a/platform/ikr/platform.c b/platform/ikr/platform.c new file mode 100644 index 00000000000..eb4dd4263e1 --- /dev/null +++ b/platform/ikr/platform.c @@ -0,0 +1,177 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Include these files as needed. + * See objects.mk PLATFORM_xxx configuration parameters. + */ +#include +#include + +#define PLATFORM_PLIC_ADDR 0x00200100 +#define PLATFORM_PLIC_SIZE (0x200000 + \ + (PLATFORM_HART_COUNT * 0x1000)) +#define PLATFORM_PLIC_NUM_SOURCES 128 +#define PLATFORM_HART_COUNT 1 +// #define PLATFORM_CLINT_ADDR 0x2000000 +#define PLATFORM_ACLINT_MTIMER_FREQ 10000000 +#define PLATFORM_ACLINT_MSWI_ADDR 0x00000096 +#define PLATFORM_ACLINT_MTIMER_ADDR 0x00000080 +#define PLATFORM_UART_ADDR 0x1 +// #define PLATFORM_UART_INPUT_FREQ 10000000 +// #define PLATFORM_UART_BAUDRATE 115200 +#define PLATFORM_UART_DATA_OFFSET 0 +#define PLATFORM_UART_RXSTS_OFFSET 1 +#define PLATFORM_UART_TXSTS_OFFSET 2 +#define PLATFORM_UART_RX_AVAIL 0x1 + +static void ikr_uart_putc(char ch) +{ + while (readb((volatile void *)(PLATFORM_UART_ADDR + + PLATFORM_UART_TXSTS_OFFSET)) != 0) + ; + + writeb((u8)ch, (volatile void *)(PLATFORM_UART_ADDR + + PLATFORM_UART_DATA_OFFSET)); +} + +static void ikr_uart_puts(const char *s) +{ + while (*s) { + if (*s == '\n') + ikr_uart_putc('\r'); + ikr_uart_putc(*s++); + } +} + +static int ikr_uart_getc(void) +{ + if (readb((volatile void *)(PLATFORM_UART_ADDR + + PLATFORM_UART_RXSTS_OFFSET)) & + PLATFORM_UART_RX_AVAIL) { + u8 ch = readb((volatile void *)(PLATFORM_UART_ADDR + + PLATFORM_UART_DATA_OFFSET)); + writeb(0, (volatile void *)(PLATFORM_UART_ADDR + + PLATFORM_UART_RXSTS_OFFSET)); + return ch; + } + + return -1; +} + +static struct sbi_console_device ikr_uart_console = { + .name = "ikr-uart", + .console_putc = ikr_uart_putc, + .console_getc = ikr_uart_getc, +}; + +static struct plic_data plic = { + .unique_id = 0, + .addr = PLATFORM_PLIC_ADDR, + .size = PLATFORM_PLIC_SIZE, + .num_src = PLATFORM_PLIC_NUM_SOURCES, + .context_map = { + [0] = { 0, 1 }, + }, +}; + +// With 1 hart this is usually fine. With multi-hart kernels you must add MSWI/IPI support. +// static struct aclint_mswi_data mswi = { +// .addr = PLATFORM_ACLINT_MSWI_ADDR, +// .size = ACLINT_MSWI_SIZE, +// .first_hartid = 0, +// .hart_count = PLATFORM_HART_COUNT, +// }; + +static struct aclint_mtimer_data mtimer = { + .mtime_freq = PLATFORM_ACLINT_MTIMER_FREQ, + .mtime_addr = PLATFORM_ACLINT_MTIMER_ADDR, + .mtime_size = 0x8, + .mtimecmp_addr = PLATFORM_ACLINT_MTIMER_ADDR + 0x8, + .mtimecmp_size = 0x8, + .first_hartid = 0, + .hart_count = PLATFORM_HART_COUNT, + .has_64bit_mmio = true, +}; + +/* + * Platform early initialization. + */ +static int platform_early_init(bool cold_boot) +{ + + if (!cold_boot) + return 0; + + /* Raw UART banner before console registration. */ + ikr_uart_puts("Loading OpenSBI now...\n"); + + sbi_console_set_device(&ikr_uart_console); + + /* UART and other low MMIO lives in the first page in rvemu. */ + sbi_domain_root_add_memrange(0x0, PAGE_SIZE, PAGE_SIZE, + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)); + + /* rvemu does not provide a page-aligned MSWI window; with one hart we can + * skip MSWI initialization and still boot OpenSBI. + */ + return 0; +} + +/* + * Platform final initialization. + */ +static int platform_final_init(bool cold_boot) +{ + return 0; +} + +/* + * Initialize the platform interrupt controller during cold boot. + */ +static int platform_irqchip_init(void) +{ + /* Example if the generic PLIC driver is used */ + return plic_cold_irqchip_init(&plic); +} + +/* + * Initialize platform timer during cold boot. + */ +static int platform_timer_init(void) +{ + /* Example if the generic ACLINT driver is used */ + return aclint_mtimer_cold_init(&mtimer, NULL); +} + +/* + * Platform descriptor. + */ +const struct sbi_platform_operations platform_ops = { + .early_init = platform_early_init, + .final_init = platform_final_init, + .irqchip_init = platform_irqchip_init, + .timer_init = platform_timer_init +}; +const struct sbi_platform platform = { + .opensbi_version = OPENSBI_VERSION, + .platform_version = SBI_PLATFORM_VERSION(0x0, 0x00), + .name = "ikr-linux", + .features = SBI_PLATFORM_DEFAULT_FEATURES, + .hart_count = PLATFORM_HART_COUNT, + .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, + .heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(1), + .platform_ops_addr = (unsigned long)&platform_ops +}; From 6275b8cdaccc6684e5971f368fdc1a00d963822c Mon Sep 17 00:00:00 2001 From: mohamed-mokhtar-elkomy Date: Sat, 25 Apr 2026 14:19:33 +0200 Subject: [PATCH 2/4] fix: prevent OpenSBI hang in stack_chk_guard initialization (#1) --- firmware/fw_base.S | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index 63bb4473b20..4317935da73 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -110,21 +110,7 @@ _bss_zero: /* Trying to initialize the stack guard via the Zkr extension */ lla t0, __stack_chk_guard_done csrw CSR_MTVEC, t0 - li t0, 0 - li t3, SEED_OPTS_ES16 - li t4, SEED_ENTROPY_MASK - li t5, __SIZEOF_POINTER__ -__stack_chk_guard_loop: - csrrw t1, CSR_SEED, x0 - li t2, SEED_OPTS_MASK - and t2, t2, t1 - bgtu t2, t3, __stack_chk_guard_done - bltu t2, t3, __stack_chk_guard_loop - and t1, t1, t4 - slli t0, t0, 16 - or t0, t0, t1 - addi t5, t5, -2 - bgtz t5, __stack_chk_guard_loop + li t0, 0xdeadbeefdeadbeef lla t1, __stack_chk_guard REG_S t0, 0(t1) j __stack_chk_guard_done From a7791d988c09a0ac3de3d49601491f17640dfa58 Mon Sep 17 00:00:00 2001 From: mohamed-mokhtar-elkomy Date: Fri, 1 May 2026 16:13:12 +0200 Subject: [PATCH 3/4] feat(platform): update IKR platform configuration --- platform/ikr/platform.c | 101 +++++++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 32 deletions(-) diff --git a/platform/ikr/platform.c b/platform/ikr/platform.c index eb4dd4263e1..a4d3f4bbf5c 100644 --- a/platform/ikr/platform.c +++ b/platform/ikr/platform.c @@ -20,56 +20,92 @@ #include #define PLATFORM_PLIC_ADDR 0x00200100 -#define PLATFORM_PLIC_SIZE (0x200000 + \ - (PLATFORM_HART_COUNT * 0x1000)) +#define PLATFORM_PLIC_SIZE (0x200000 + (2 * PLATFORM_HART_COUNT * 0x1000)) #define PLATFORM_PLIC_NUM_SOURCES 128 #define PLATFORM_HART_COUNT 1 -// #define PLATFORM_CLINT_ADDR 0x2000000 + #define PLATFORM_ACLINT_MTIMER_FREQ 10000000 #define PLATFORM_ACLINT_MSWI_ADDR 0x00000096 #define PLATFORM_ACLINT_MTIMER_ADDR 0x00000080 + #define PLATFORM_UART_ADDR 0x1 -// #define PLATFORM_UART_INPUT_FREQ 10000000 -// #define PLATFORM_UART_BAUDRATE 115200 -#define PLATFORM_UART_DATA_OFFSET 0 +#define PLATFORM_UART_INPUT_FREQ 10000000 #define PLATFORM_UART_RXSTS_OFFSET 1 -#define PLATFORM_UART_TXSTS_OFFSET 2 -#define PLATFORM_UART_RX_AVAIL 0x1 +#define PLATFORM_UART_TXSTS_OFFSET 2 +#define PLATFORM_UART_DATA_OFFSET 0x00 +#define PLATFORM_UART_IER_OFFSET 0x01 +#define PLATFORM_UART_FCR_OFFSET 0x02 +#define PLATFORM_UART_LCR_OFFSET 0x03 +#define PLATFORM_UART_MCR_OFFSET 0x04 +#define PLATFORM_UART_LSR_OFFSET 0x05 +#define PLATFORM_UART_RX_AVAIL 0x01 // DR bit in LSR +/* Bit masks for the LSR (Offset 5) */ +#define PLATFORM_UART_LSR_RX_READY 0x01 // Bit 0: Data Ready +#define PLATFORM_UART_LSR_TX_EMPTY 0x20 // Bit 5: Transmit Holding Register Empty + +//For Qemu +// static void ikr_uart_putc(char ch) +// { +// // Wait until THR is empty (Bit 5 of LSR becomes 1) +// while ((readb((volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_LSR_OFFSET)) & +// PLATFORM_UART_LSR_TX_EMPTY) == 0) +// ; + +// writeb((u8)ch, (volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_DATA_OFFSET)); +// } + +// //For Qemu +// static int ikr_uart_getc(void) +// { +// // Check LSR Bit 0 (Data Ready) +// u8 status = readb((volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_LSR_OFFSET)); +// // +// if (status & PLATFORM_UART_LSR_RX_READY) { +// // Read the data; this hardware-clears the Ready bit +// return (int)readb((volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_DATA_OFFSET)); +// } +// return -1; +// } + static void ikr_uart_putc(char ch) { while (readb((volatile void *)(PLATFORM_UART_ADDR + - PLATFORM_UART_TXSTS_OFFSET)) != 0) - ; + PLATFORM_UART_TXSTS_OFFSET)) != 0); writeb((u8)ch, (volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_DATA_OFFSET)); } -static void ikr_uart_puts(const char *s) -{ - while (*s) { - if (*s == '\n') - ikr_uart_putc('\r'); - ikr_uart_putc(*s++); - } -} - static int ikr_uart_getc(void) { + /* + * Check RX_STATE bit 0 (data available). Reading UART_DATA + * automatically clears the RX_AVAIL bit in hardware, so no + * explicit status-register write is needed here. Writing 0 + * to RXSTS after the DATA read would race with rvemu's input + * thread (which sets RX_AVAIL for the next queued character + * between the DATA read and such a write), silently dropping + * characters when multiple bytes arrive before a poll cycle. + */ if (readb((volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_RXSTS_OFFSET)) & PLATFORM_UART_RX_AVAIL) { - u8 ch = readb((volatile void *)(PLATFORM_UART_ADDR + + return (int)(u8)readb((volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_DATA_OFFSET)); - writeb(0, (volatile void *)(PLATFORM_UART_ADDR + - PLATFORM_UART_RXSTS_OFFSET)); - return ch; } - return -1; } +static void ikr_uart_puts(const char *s) +{ + while (*s) { + if (*s == '\n') + ikr_uart_putc('\r'); + ikr_uart_putc(*s++); + } +} + static struct sbi_console_device ikr_uart_console = { .name = "ikr-uart", .console_putc = ikr_uart_putc, @@ -86,14 +122,6 @@ static struct plic_data plic = { }, }; -// With 1 hart this is usually fine. With multi-hart kernels you must add MSWI/IPI support. -// static struct aclint_mswi_data mswi = { -// .addr = PLATFORM_ACLINT_MSWI_ADDR, -// .size = ACLINT_MSWI_SIZE, -// .first_hartid = 0, -// .hart_count = PLATFORM_HART_COUNT, -// }; - static struct aclint_mtimer_data mtimer = { .mtime_freq = PLATFORM_ACLINT_MTIMER_FREQ, .mtime_addr = PLATFORM_ACLINT_MTIMER_ADDR, @@ -123,6 +151,15 @@ static int platform_early_init(bool cold_boot) sbi_domain_root_add_memrange(0x0, PAGE_SIZE, PAGE_SIZE, (SBI_DOMAIN_MEMREGION_MMIO | SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)); + /* Allow access to the new UART location */ + sbi_domain_root_add_memrange(PLATFORM_UART_ADDR, PAGE_SIZE, PAGE_SIZE, + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)); + + /* Keep access to the PLIC/Timer area (assuming they are near 0x0c000000 or 0x02000000) */ + sbi_domain_root_add_memrange(PLATFORM_PLIC_ADDR, 0x400000, PAGE_SIZE, + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)); /* rvemu does not provide a page-aligned MSWI window; with one hart we can * skip MSWI initialization and still boot OpenSBI. From edcc6a69ff709d096b07f20c95d023bfc82e3752 Mon Sep 17 00:00:00 2001 From: mohamed-mokhtar-elkomy Date: Fri, 8 May 2026 21:53:08 +0200 Subject: [PATCH 4/4] feat(platform): update ikr OpenSBI platform and object file --- platform/ikr/objects.mk | 5 +- platform/ikr/platform.c | 161 ++++++++++++++++++++-------------------- 2 files changed, 85 insertions(+), 81 deletions(-) diff --git a/platform/ikr/objects.mk b/platform/ikr/objects.mk index 4ecff913c11..1386bc9e126 100644 --- a/platform/ikr/objects.mk +++ b/platform/ikr/objects.mk @@ -31,7 +31,7 @@ platform-ldflags-y = # # PLATFORM_RISCV_XLEN = 64 # PLATFORM_RISCV_ABI = lp64 -# PLATFORM_RISCV_ISA = rv64imafdc +PLATFORM_RISCV_ISA = rv64ima_zicsr_zifencei # PLATFORM_RISCV_CODE_MODEL = medany # Space separated list of object file names to be compiled for the platform @@ -46,6 +46,9 @@ platform-objs-y += platform.o # Optional parameter for path to external FDT # FW_FDT_PATH="path to platform flattened device tree file" +# FW_PAYLOAD_PATH=/home/elkomy/rp-workspace/linux/arch/riscv/boot/Image +# FW_PAYLOAD_PATH=/home/elkomy/rp-workspace/u-boot/u-boot.bin +# FW_FDT_PATH=/home/elkomy/rp-workspace/output/ikr.dtb # # Dynamic firmware configuration. diff --git a/platform/ikr/platform.c b/platform/ikr/platform.c index a4d3f4bbf5c..17df9aa059e 100644 --- a/platform/ikr/platform.c +++ b/platform/ikr/platform.c @@ -11,67 +11,69 @@ #include #include #include - -/* - * Include these files as needed. - * See objects.mk PLATFORM_xxx configuration parameters. - */ #include #include -#define PLATFORM_PLIC_ADDR 0x00200100 -#define PLATFORM_PLIC_SIZE (0x200000 + (2 * PLATFORM_HART_COUNT * 0x1000)) -#define PLATFORM_PLIC_NUM_SOURCES 128 -#define PLATFORM_HART_COUNT 1 +#define PLATFORM_PLIC_ADDR 0x00200100 +#define PLATFORM_PLIC_SIZE (0x200000 + (2 * PLATFORM_HART_COUNT * 0x1000)) +#define PLATFORM_PLIC_NUM_SOURCES 128 +#define PLATFORM_HART_COUNT 1 -#define PLATFORM_ACLINT_MTIMER_FREQ 10000000 +#define PLATFORM_ACLINT_MTIMER_FREQ 10000000 #define PLATFORM_ACLINT_MSWI_ADDR 0x00000096 -#define PLATFORM_ACLINT_MTIMER_ADDR 0x00000080 - -#define PLATFORM_UART_ADDR 0x1 -#define PLATFORM_UART_INPUT_FREQ 10000000 -#define PLATFORM_UART_RXSTS_OFFSET 1 -#define PLATFORM_UART_TXSTS_OFFSET 2 -#define PLATFORM_UART_DATA_OFFSET 0x00 -#define PLATFORM_UART_IER_OFFSET 0x01 -#define PLATFORM_UART_FCR_OFFSET 0x02 -#define PLATFORM_UART_LCR_OFFSET 0x03 -#define PLATFORM_UART_MCR_OFFSET 0x04 -#define PLATFORM_UART_LSR_OFFSET 0x05 -#define PLATFORM_UART_RX_AVAIL 0x01 // DR bit in LSR +#define PLATFORM_ACLINT_MTIMER_ADDR 0x00000080 + +#define PLATFORM_UART_ADDR 0x01 +#define PLATFORM_UART_INPUT_FREQ 10000000 +#define PLATFORM_UART_RXSTS_OFFSET 1 +#define PLATFORM_UART_TXSTS_OFFSET 2 +#define PLATFORM_UART_DATA_OFFSET 0x00 +#define PLATFORM_UART_IER_OFFSET 0x01 +#define PLATFORM_UART_FCR_OFFSET 0x02 +#define PLATFORM_UART_LCR_OFFSET 0x03 +#define PLATFORM_UART_MCR_OFFSET 0x04 +#define PLATFORM_UART_LSR_OFFSET 0x05 +#define PLATFORM_UART_RX_AVAIL 0x01 // DR bit in LSR /* Bit masks for the LSR (Offset 5) */ -#define PLATFORM_UART_LSR_RX_READY 0x01 // Bit 0: Data Ready -#define PLATFORM_UART_LSR_TX_EMPTY 0x20 // Bit 5: Transmit Holding Register Empty - -//For Qemu -// static void ikr_uart_putc(char ch) -// { -// // Wait until THR is empty (Bit 5 of LSR becomes 1) -// while ((readb((volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_LSR_OFFSET)) & -// PLATFORM_UART_LSR_TX_EMPTY) == 0) -// ; - -// writeb((u8)ch, (volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_DATA_OFFSET)); -// } - -// //For Qemu -// static int ikr_uart_getc(void) -// { -// // Check LSR Bit 0 (Data Ready) -// u8 status = readb((volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_LSR_OFFSET)); -// // -// if (status & PLATFORM_UART_LSR_RX_READY) { -// // Read the data; this hardware-clears the Ready bit -// return (int)readb((volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_DATA_OFFSET)); -// } -// return -1; -// } +#define PLATFORM_UART_LSR_RX_READY 0x01 // Bit 0: Data Ready +#define PLATFORM_UART_LSR_TX_EMPTY 0x20 // Bit 5: Transmit Holding Register Empty + +// #define USE_UART_QEMU 1 // Set to 1 to use the QEMU-specific UART implementation + +// For Qemu +#ifdef USE_UART_QEMU +static void ikr_uart_putc(char ch) +{ + // Wait until THR is empty (Bit 5 of LSR becomes 1) + while ((readb((volatile void *)(PLATFORM_UART_ADDR + + PLATFORM_UART_LSR_OFFSET)) & + PLATFORM_UART_LSR_TX_EMPTY) == 0) + ; + + writeb((u8)ch, (volatile void *)(PLATFORM_UART_ADDR + + PLATFORM_UART_DATA_OFFSET)); +} +static int ikr_uart_getc(void) +{ + // Check LSR Bit 0 (Data Ready) + u8 status = readb((volatile void *)(PLATFORM_UART_ADDR + + PLATFORM_UART_LSR_OFFSET)); + // + if (status & PLATFORM_UART_LSR_RX_READY) { + // Read the data; this hardware-clears the Ready bit + return (int)readb((volatile void *)(PLATFORM_UART_ADDR + + PLATFORM_UART_DATA_OFFSET)); + } + return -1; +} +#else static void ikr_uart_putc(char ch) { while (readb((volatile void *)(PLATFORM_UART_ADDR + - PLATFORM_UART_TXSTS_OFFSET)) != 0); + PLATFORM_UART_TXSTS_OFFSET)) != 0) + ; writeb((u8)ch, (volatile void *)(PLATFORM_UART_ADDR + PLATFORM_UART_DATA_OFFSET)); @@ -89,14 +91,17 @@ static int ikr_uart_getc(void) * characters when multiple bytes arrive before a poll cycle. */ if (readb((volatile void *)(PLATFORM_UART_ADDR + - PLATFORM_UART_RXSTS_OFFSET)) & + PLATFORM_UART_RXSTS_OFFSET)) & PLATFORM_UART_RX_AVAIL) { - return (int)(u8)readb((volatile void *)(PLATFORM_UART_ADDR + - PLATFORM_UART_DATA_OFFSET)); + return (int)(u8)readb( + (volatile void *)(PLATFORM_UART_ADDR + + PLATFORM_UART_DATA_OFFSET)); } return -1; } +#endif + static void ikr_uart_puts(const char *s) { while (*s) { @@ -107,7 +112,7 @@ static void ikr_uart_puts(const char *s) } static struct sbi_console_device ikr_uart_console = { - .name = "ikr-uart", + .name = "ikr-uart", .console_putc = ikr_uart_putc, .console_getc = ikr_uart_getc, }; @@ -123,13 +128,13 @@ static struct plic_data plic = { }; static struct aclint_mtimer_data mtimer = { - .mtime_freq = PLATFORM_ACLINT_MTIMER_FREQ, - .mtime_addr = PLATFORM_ACLINT_MTIMER_ADDR, - .mtime_size = 0x8, - .mtimecmp_addr = PLATFORM_ACLINT_MTIMER_ADDR + 0x8, - .mtimecmp_size = 0x8, - .first_hartid = 0, - .hart_count = PLATFORM_HART_COUNT, + .mtime_freq = PLATFORM_ACLINT_MTIMER_FREQ, + .mtime_addr = PLATFORM_ACLINT_MTIMER_ADDR, + .mtime_size = 0x8, + .mtimecmp_addr = PLATFORM_ACLINT_MTIMER_ADDR + 0x8, + .mtimecmp_size = 0x8, + .first_hartid = 0, + .hart_count = PLATFORM_HART_COUNT, .has_64bit_mmio = true, }; @@ -151,15 +156,11 @@ static int platform_early_init(bool cold_boot) sbi_domain_root_add_memrange(0x0, PAGE_SIZE, PAGE_SIZE, (SBI_DOMAIN_MEMREGION_MMIO | SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)); - /* Allow access to the new UART location */ - sbi_domain_root_add_memrange(PLATFORM_UART_ADDR, PAGE_SIZE, PAGE_SIZE, - (SBI_DOMAIN_MEMREGION_MMIO | - SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)); - + /* Allow access to the IKR UART MMIO region (0x11000). */ /* Keep access to the PLIC/Timer area (assuming they are near 0x0c000000 or 0x02000000) */ sbi_domain_root_add_memrange(PLATFORM_PLIC_ADDR, 0x400000, PAGE_SIZE, - (SBI_DOMAIN_MEMREGION_MMIO | - SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)); + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)); /* rvemu does not provide a page-aligned MSWI window; with one hart we can * skip MSWI initialization and still boot OpenSBI. @@ -197,18 +198,18 @@ static int platform_timer_init(void) * Platform descriptor. */ const struct sbi_platform_operations platform_ops = { - .early_init = platform_early_init, - .final_init = platform_final_init, - .irqchip_init = platform_irqchip_init, - .timer_init = platform_timer_init + .early_init = platform_early_init, + .final_init = platform_final_init, + .irqchip_init = platform_irqchip_init, + .timer_init = platform_timer_init }; const struct sbi_platform platform = { - .opensbi_version = OPENSBI_VERSION, - .platform_version = SBI_PLATFORM_VERSION(0x0, 0x00), - .name = "ikr-linux", - .features = SBI_PLATFORM_DEFAULT_FEATURES, - .hart_count = PLATFORM_HART_COUNT, - .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, - .heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(1), - .platform_ops_addr = (unsigned long)&platform_ops + .opensbi_version = OPENSBI_VERSION, + .platform_version = SBI_PLATFORM_VERSION(0x0, 0x00), + .name = "ikr-linux", + .features = SBI_PLATFORM_DEFAULT_FEATURES, + .hart_count = PLATFORM_HART_COUNT, + .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, + .heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(1), + .platform_ops_addr = (unsigned long)&platform_ops };