Beginning Apache NuttX Actual-Time Working System
📝 12 Nov 2023
Final week we booted Linux on the Pine64 Ox64 64-bit RISC-V SBC (pic under), powered by Bouffalo Lab BL808 SoC…
And we questioned if a tiny 64-bit RTOS (Actual-Time Working System) like Apache NuttX RTOS would possibly run extra effectively on Ox64.
(With solely 64 MB of RAM)
Let’s make it occur! On this article we…
-
Start with NuttX for Star64 JH7110 RISC-V SBC
-
Boot it unmodified (!) on our Ox64 BL808 RISC-V SBC
-
Add Debug Logs in RISC-V Meeting
-
Tweak the NuttX UART Driver to print on Ox64
-
Repair the Platform-Degree Interrupt Controller
-
Monitor down why RISC-V Exceptions aren’t dumped appropriately
-
And plan for the upcoming Preliminary RAM Disk
We’re booting Star64 NuttX on Ox64? Unmodified?!
Yeah it appears like we’re Shredding a Toaster inside a Blender (with loads of Smoke and Noise)…
However we’re beginning with NuttX for Star64 JH7110 anyway! That’s as a result of we have now a really sturdy hunch (or simply plainly cussed) that NuttX will boot properly throughout RISC-V SoCs.
(We ported NuttX QEMU to Star64 in only a few weeks!)
However Star64 runs on SiFive Cores. Ox64 makes use of T-Head Cores!
If RISC-V ain’t RISC-V on SiFive vs T-Head: We’ll discover out!
That is how we obtain and construct NuttX for Star64 JH7110 RISC-V SBC…
## Obtain WIP NuttX Supply Code
git clone
--branch ox64
https://github.com/lupyuen2/wip-pinephone-nuttx
nuttx
git clone
--branch ox64
https://github.com/lupyuen2/wip-pinephone-nuttx-apps
apps
## Construct NuttX for Star64
cd nuttx
instruments/configure.sh star64:nsh
make
## Dump the RISC-V Disassembly for NuttX Kernel
riscv64-unknown-elf-objdump
-t -S --demangle --line-numbers --wide
nuttx
>nuttx.S
2>&1
(Remember to install the Build Prerequisites and Toolchain)
(And enable Scheduler Info Output)
Subsequent we put together a Linux microSD for Ox64 as described in the previous article.
(Remember to flash OpenSBI and U-Boot Bootloader)
Then we do the Linux-To-NuttX Switcheroo: Overwrite the microSD Linux Picture by the NuttX Kernel…
## Export the NuttX Binary Picture
## to `nuttx.bin`
riscv64-unknown-elf-objcopy
-O binary
nuttx
nuttx.bin
## Overwrite the Linux Picture
## on Ox64 microSD
cp nuttx.bin
"/Volumes/NO NAME/Picture"
diskutil unmountDisk /dev/disk2
Insert the microSD into Ox64 and energy up Ox64.
Ox64 boots OpenSBI, which begins U-Boot Bootloader, which begins NuttX Kernel.
And we see… Completely Nothing!
Retrieving file: /extlinux/../Picture
append: root=PARTLABEL=rootfs rootwait rw rootfstype=ext4 console=ttyS0,2000000 loglevel=8 earlycon=sbi
Retrieving file: /extlinux/../bl808-pine64-ox64.dtb
Flattened Machine Tree blob at 51ff8000
Booting utilizing the fdt blob at 0x51ff8000
Working FDT set to 51ff8000
Loading Machine Tree to 0000000053f22000, finish 0000000053f25fab ... OK
Working FDT set to 53f22000
Beginning kernel...
Shouldn’t we see a Crash Dump?
Yeah we’re hoping that NuttX would crash and OpenSBI (Supervisor Binary Interface) might dump a significant Stack Hint. However nope!
Is NuttX alive? We are able to examine…
Now we have a robust hunch that NuttX is definitely booting on Ox64… Learn how to show it?
We’ll print one thing within the NuttX Boot Code. Which is in RISC-V Meeting!
Ox64’s BL808 UART appears tremendous acquainted. After we examine these UARTs…
We uncover that BL808 UART works the identical means as BL602!
Thus we search steerage from the NuttX Driver for BL602 UART.
Thanks! However how can we print to BL808 UART?
BL602 UART Driver prints to the Serial Console like so: bl602_serial.c
// Output FIFO Offset is 0x88
#outline BL602_UART_FIFO_WDATA_OFFSET 0x000088
#outline BL602_UART_FIFO_WDATA(n) (BL602_UART_BASE(n) + BL602_UART_FIFO_WDATA_OFFSET)
// Write a personality to UART
void bl602_send(struct uart_dev_s *dev, int ch) {
...
// Look ahead to FIFO to be empty
whereas ((getreg32(BL602_UART_FIFO_CONFIG_1(uart_idx)) &
UART_FIFO_CONFIG_1_TX_CNT_MASK) == 0);
// Write character to Output FIFO
putreg32(ch, BL602_UART_FIFO_WDATA(uart_idx));
}
For BL808: We do the identical. We merely write the character to…
Based mostly on our Star64 Debug Code, we write this in RISC-V Meeting to print “123
”…
/* Load UART3 Base Handle to Register t0 */
li t0, 0x30002000
/* Load `1` to Register t1 */
li t1, 0x31
/* Retailer byte from Register t1 to UART3 Base Handle, Offset 0x88 */
sb t1, 0x88(t0)
/* Load `2` to Register t1 */
li t1, 0x32
/* Retailer byte from Register t1 to UART3 Base Handle, Offset 0x88 */
sb t1, 0x88(t0)
/* Load `3` to Register t1 */
li t1, 0x33
/* Retailer byte from Register t1 to UART3 Base Handle, Offset 0x88 */
sb t1, 0x88(t0)
(li
loads a Value into a Register)
(sb
stores a byte from a Register into an Address Offset)
We insert the code above into our NuttX Boot Code: jh7110_head.S
And we see (pic above)…
Our hunch is 100% right, NuttX is ALIVE on Ox64 yay!
The rest we modified within the NuttX Boot Code?
OpenSBI boots on Ox64 with Hart ID 0 (as an alternative of 1). Which suggests we take away this adjustment for Hart ID: jh7110_head.S
/* We assume that OpenSBI has handed Hart ID (worth 1) in Register a0.
* However NuttX expects Hart ID to start out at 0, so we subtract 1.
* Beforehand: addi a0, a0, -1 */
Certainly Ox64 boots at a distinct RAM Handle from Star64?
Yep! Subsequent we repair the NuttX Boot Handle for Ox64.
From the U-Boot Bootloader we see that Ox64 boots Linux at this deal with…
$ printenv
kernel_addr_r=0x50200000
Based mostly on the Boot Handle, we outline these Reminiscence Areas for NuttX…
(Web page Pool will probably be utilized by NuttX Apps)
(RAM Disk will comprise the NuttX Shell and Apps)
We replace the Reminiscence Areas within the NuttX Linker Script: ld.script
MEMORY
{
kflash (rx) : ORIGIN = 0x50200000, LENGTH = 2048K /* w/ cache */
ksram (rwx) : ORIGIN = 0x50400000, LENGTH = 2048K /* w/ cache */
pgram (rwx) : ORIGIN = 0x50600000, LENGTH = 4096K /* w/ cache */
ramdisk (rwx) : ORIGIN = 0x50A00000, LENGTH = 16M /* w/ cache */
} /* TODO: Expend the whole 64 MB RAM */
We make the identical adjustments to the NuttX Construct Configuration: nsh/defconfig
CONFIG_RAM_START=0x50200000
CONFIG_RAM_SIZE=1048576
CONFIG_ARCH_PGPOOL_PBASE=0x50600000
CONFIG_ARCH_PGPOOL_VBASE=0x50600000
CONFIG_ARCH_PGPOOL_SIZE=4194304
And we replace the NuttX Reminiscence Map: jh7110_mm_init.c
// Map the entire I/O Reminiscence
// with Digital Handle = Bodily Handle
#outline MMU_IO_BASE (0x00000000)
#outline MMU_IO_SIZE (0x50000000)
What’s this Reminiscence Map?
Contained in the BL808 SoC is the Sv39 Memory Management Unit (MMU). (Identical for Star64 JH7110)
The MMU maps Digital Reminiscence Addresses to Bodily Reminiscence Addresses. And stops the NuttX Kernel from accessing Invalid Addresses.
At startup, NuttX configures the MMU with the Reminiscence Map, the Vary of Reminiscence Addresses that the NuttX Kernel is allowed to entry.
The code above says that NuttX is allowed to entry any deal with from 0x0000
0000
to 0x5000
0000
. (Due to Reminiscence-Mapped I/O)
Time to make NuttX discuss…
NuttX on Ox64 has been awfully quiet…
Learn how to repair the UART Driver in order that NuttX can print issues?
NuttX continues to be operating the JH7110 UART Driver (16550).
To print to the Ox64 Serial Console, we make a fast patch to the NuttX UART Driver.
For now, we hardcode the UART3 Base Handle (from above) and Output FIFO Offset: uart_16550.c
// Write one character to the UART
void u16550_putc(FAR struct u16550_s *priv, int ch) {
// Hardcode the UART3 Base Handle and Output FIFO Offset
*(unstable uint8_t *) 0x30002088 = ch;
// Beforehand:
// whereas ((u16550_serialin(priv, UART_LSR_OFFSET) & UART_LSR_THRE) == 0);
// u16550_serialout(priv, UART_THR_OFFSET, (uart_datawidth_t)ch);
}
(Yeah the UART Buffer would possibly overflow, we’ll repair later)
For Different UART Registers: We skip the studying and writing of the registers, as a result of we’ll patch them later: uart_16550.c
// Learn from UART Register
uart_datawidth_t u16550_serialin(FAR struct u16550_s *priv, int offset) {
return 0;
// Commented out the remaining
}
// Write to UART Register
void u16550_serialout(FAR struct u16550_s *priv, int offset, uart_datawidth_t worth) {
// Commented out the remaining
}
And we received’t await UART Prepared, since we don’t entry the Line Management Register: uart_16550.c
// Wait till UART isn't busy. That is wanted earlier than writing to Line Management Register.
// In any other case we are going to get spurious interrupts on Synopsys DesignWare 8250.
int u16550_wait(FAR struct u16550_s *priv) {
// Nopez! No ready for now
return OK;
}
After these fixes, NuttX prints our very first Crash Dump on Ox64 yay! (Pic above)
Beginning kernel...
123ABC
riscv_exception:
EXCEPTION: Load entry fault
MCAUSE: 5
EPC: 50208086
MTVAL: 0c002104
riscv_exception: PANIC!!! Exception = 0000000000000005
_assert: Present Model: NuttX 12.0.3 93a92a7-dirty Nov 5 2023 11:27:46 risc-v
_assert: Assertion failed panic: at file: widespread/riscv_exception.c:85 process: Idle_Task course of: Kernel 0x50200e28
up_dump_register: EPC: 0000000050208086
up_dump_register: A0: 000000000c002104 A1: ffffffffffffffff A2: 0000000000000001 A3: 0000000000000003
MTVAL (Machine Trap Value) says that NuttX has crashed whereas studying the Invalid Information Handle 0x0C00
2104
. (Therefore the “Load Entry Fault”)
Why is Information Handle 0x0C00
2104
inflicting unhappiness? First we find out about RISC-V Interrupts…
Platform-Level Interrupt Controller for Star64 JH7110
What’s this Platform-Degree Interrupt Controller?
Inside our BL808 SoC, the Platform-Level Interrupt Controller (PLIC) is the {hardware} that receives Exterior Interrupts and forwards them to our RISC-V CPU.
(Like for UART Interrupts, pic above)
Earlier we noticed NuttX crashing with this RISC-V Exception…
EXCEPTION: Load entry fault
MCAUSE: 5
EPC: 50208086
MTVAL: 0c002104
This says that NuttX crashed when it tried to entry Invalid Information Handle 0x0C00
2104
from Code Handle 0x5020
8086
.
We glance up Code Handle 0x5020
8086
in our RISC-V Disassembly for NuttX Kernel…
nuttx/arch/risc-v/src/widespread/riscv_modifyreg32.c:52
regval = getreg32(addr);
50208086: 2701 sext.w a4,a4
Which factors to this: riscv_modifyreg32.c
// Atomically modify the required bits
// in a Reminiscence-Mapped Register
void modifyreg32(uintptr_t addr, uint32_t clearbits, uint32_t setbits) = setbits;
putreg32(regval, addr);
spin_unlock_irqrestore(NULL, flags);
Therefore NuttX tried to change a Reminiscence-Mapped Register that doesn’t exist, and crashed.
However what Reminiscence-Mapped Register?
The offending Information Handle 0x0C00
2104
really comes from the Star64 PLIC! (Platform-Degree Interrupt Controller)
// Star64 PLIC Base Handle
// From https://github.com/apache/nuttx/blob/grasp/arch/risc-v/src/jh7110/{hardware}/jh7110_memorymap.h#L30
#outline JH7110_PLIC_BASE 0x0c000000
// Star64 S-Mode Interrupt Allow
// From https://github.com/apache/nuttx/blob/grasp/arch/risc-v/src/jh7110/{hardware}/jh7110_plic.h#L34-L49
#outline JH7110_PLIC_ENABLE2 (JH7110_PLIC_BASE + 0x002104)
PLIC for Ox64 is in a distinct place, let’s change it.
What’s the PLIC Base Handle for Ox64?
For Ox64, PLIC Base Handle is 0xE000
0000
, in response to the Linux Machine Tree: bl808-pine64-ox64.dts
interrupt-controller@e0000000 {
suitable = "thead,c900-plic";
reg = <0xe0000000 0x4000000>;
interrupts-extended = <0x06 0xffffffff 0x06 0x09>;
interrupt-controller;
#address-cells = <0x00>;
#interrupt-cells = <0x02>;
riscv,ndev = <0x40>;
phandle = <0x01>;
};
Based mostly on the above, we modify the PLIC Base Handle for Ox64: jh7110_memorymap.h
#outline JH7110_PLIC_BASE 0xe0000000
(PLIC Offsets are in XuanTie OpenC906 User Manual, Page 77)
NuttX now crashes at a distinct place, with IRQ 15 (pic under)…
123ABC
nx_start: Entry
up_irqinitialize: a, b, c
riscv_dispatch_irq: irq=15
irq_unexpected_isr: ERROR irq: 15
_assert: Present Model: NuttX 12.0.3 910bfca-dirty Nov 6 2023 15:23:11 risc-v
_assert: Assertion failed panic: at file: irq/irq_unexpectedisr.c:54 process: Idle_Task course of: Kernel 0x50200e50
However there’s one thing distinctive about IRQ 15…
What’s IRQ 15? Who’s inflicting it? (Pic above)
From the XuanTie OpenC906 User Manual (Web page 21)…
“Exception Vector ID 15: A Retailer / Atomic Instruction web page error exception”
This says that NuttX tried to put in writing to an Invalid Information Handle.
And it failed attributable to an “Surprising Interrupt”.
One thing particular about IRQ 15?
IRQ 15 is definitely a RISC-V Exception!
Rightfully, NuttX ought to print a useful RISC-V Exception Crash Dump with the offending Information Handle. (Like this)
However NuttX wasn’t terribly useful for this RISC-V Exception. Very odd!
The place did it crash?
Based mostly on our Debug Log, NuttX crashes simply earlier than setting the PLIC: jh7110_irq.c
// Init the Interrupts
void up_irqinitialize(void) {
...
// Disable S-Mode Interrupts
_info("bn");
up_irq_save();
// Disable all World Interrupts
_info("cn");
// Crashes right here!
putreg32(0x0, JH7110_PLIC_ENABLE1);
putreg32(0x0, JH7110_PLIC_ENABLE2);
...
// Connect the RISC-V Exception Handlers
_info("fn");
riscv_exception_attach();
One thing doesn’t look proper…
Yeah within the code above, we connect the RISC-V Exception Handlers (riscv_exception_attach)…
After the code has crashed! (putreg32)
Therefore we connect the Exception Handlers earlier: jh7110_irq.c
// Init the Interrupts
void up_irqinitialize(void) {
...
// Disable S-Mode Interrupts
_info("bn");
up_irq_save();
// Moved Right here: Connect the RISC-V Exception Handlers
_info("fn");
riscv_exception_attach();
// Disable all World Interrupts
_info("cn");
// Crashes right here!
putreg32(0x0, JH7110_PLIC_ENABLE1);
putreg32(0x0, JH7110_PLIC_ENABLE2);
Then riscv_exception_attach will deal with all RISC-V Exceptions appropriately, together with IRQ 15: riscv_exception.c
// Connect the RISC-V Exception Handlers
void riscv_exception_attach(void) {
...
// IRQ 15: Retailer / AMO Web page Fault
irq_attach(RISCV_IRQ_STOREPF, riscv_exception, NULL);
Does it work?
Yep we see the Retailer / AMO Web page Fault Exception! (Pic under)
up_irqinitialize: c
riscv_dispatch_irq: irq=15
riscv_exception:
EXCEPTION: Retailer/AMO web page fault
MCAUSE: f
EPC: 50207e6a
MTVAL: e0002100
After we search for the NuttX Kernel Disassembly, the Exception Code Handle 0x5020
7E6A
(EPC) comes from our PLIC Code…
nuttx/arch/risc-v/src/chip/jh7110_irq.c:62
putreg32(0x0, JH7110_PLIC_ENABLE1);
50207e64: 700017b7 lui a5,0x70001
50207e68: 0786 slli a5,a5,0x1
50207e6a: 1007a023 sw zero,256(a5) # 70001100 <__ramdisk_end+0x1e601100>
The offending Information Handle (MTVAL) is 0xE000
2100
.
Which is our Ox64 PLIC! We scrutinise PLIC once more…
However is 0xE000 2100 accessible?
Ah we forgot so as to add the Platform-Degree Interrupt Controller (PLIC) to the Reminiscence Map. That is how we repair it: jh7110_mm_init.c
// Map the entire I/O Reminiscence
// with Digital Handle = Bodily Handle
// (Contains PLIC)
#outline MMU_IO_BASE (0x00000000)
#outline MMU_IO_SIZE (0xf0000000)
(Memory Map doesn’t look right)
NuttX boots even additional. And tries to register IRQ 57 for the Star64 UART Interrupt…
up_irqinitialize: c, d, e, g
uart_register: Registering /dev/console
uart_register: Registering /dev/ttyS0
irq_attach: irq=57
up_enable_irq: irq=57
riscv_exception:
EXCEPTION: Load entry fault
MCAUSE: 5
EPC: 50208342
MTVAL: e0002104
Nevertheless it crashes whereas accessing the PLIC at one other Invalid Information Handle: 0xE000
2104
. (Sigh)
Ack! Sufficient with the PLIC already…
Yeah we’ll repair PLIC later. All the UART Driver will be revamped anyway, together with the UART Interrupt.
For now, we disable the UART Interrupt: uart_16550.c
// Connect the UART Interrupt for Star64
int u16550_attach(struct uart_dev_s *dev) {
// Do not connect the interrupt
// Beforehand:
// ret = irq_attach(priv->irq, u16550_interrupt, dev);
// Do not allow the interrupt
// Beforehand:
// up_enable_irq(priv->irq);
NuttX hits one other roadblock…
Initial RAM Disk for Star64 JH7110
We disabled the UART Interrupts. What occurs now?
NuttX boots a lot additional, however crashes within the NuttX Bringup…
up_irqinitialize: c, d, e, g
uart_register: Registering /dev/console
uart_register: Registering /dev/ttyS0
work_start_lowpri: Beginning low-priority kernel employee thread(s)
_assert: Present Model: NuttX 12.0.3 b244f85-dirty Nov 6 2023 17:35:34 risc-v
_assert: Assertion failed ret >= 0: at file: init/nx_bringup.c:283 process: AppBringUp course of: Kernel 0x5020107e
That’s as a result of NuttX couldn’t mount the Preliminary RAM Disk: nx_bringup.c
// Mount the File System containing
// the NuttX Shell (NSH)
ret = nx_mount(CONFIG_INIT_MOUNT_SOURCE, CONFIG_INIT_MOUNT_TARGET,
CONFIG_INIT_MOUNT_FSTYPE, CONFIG_INIT_MOUNT_FLAGS,
CONFIG_INIT_MOUNT_DATA);
// Fails right here
DEBUGASSERT(ret >= 0);
That comprises the Executable Binaries for NuttX Shell (NSH) and the NuttX Apps.
Why is the Preliminary RAM Disk lacking?
That’s as a result of we haven’t loaded the Preliminary RAM Disk into RAM!
We’ll modify the NuttX Kernel Picture (or U-Boot Script) on the microSD Card, in order that U-Boot Bootloader will load our Preliminary RAM Disk earlier than beginning NuttX.
(Upcoming work for Initial RAM Disk)
Are we carried out but?
That’s all for right now! NuttX has booted a lot code on Ox64. Right here’s the circulate of the NuttX Code that boots on Ox64 (pic under)…
Clickable Version of NuttX Boot Flow
This week we made loads of progress beginning Apache NuttX RTOS on the tiny Ox64 BL808 RISC-V SBC…
-
We took NuttX for Star64 JH7110 RISC-V SBC
-
And booted it (semi-successfully) on Ox64 BL808 RISC-V SBC
(Via sheer tenacity or desperation or a lot of luck)
-
Due to the Debug Logs we added in RISC-V Meeting
-
And our modified NuttX UART Driver that prints on Ox64
-
We mounted the Platform-Degree Interrupt Controller
-
Found why RISC-V Exceptions weren’t dumped appropriately
-
As we deliberate for the upcoming Preliminary RAM Disk
We’ll do rather more for NuttX on Ox64 BL808, keep tuned for updates!
Many Due to my GitHub Sponsors (and the superior NuttX Group) for supporting my work! This text wouldn’t have been potential with out your assist.
Received a query, remark or suggestion? Create an Problem or submit a Pull Request right here…
My soldering of Ox64 BL808 appears horrigible… Nevertheless it boots NuttX!
What occurs precisely when NuttX boots on Ox64?
On this article, NuttX has booted loads of code on Ox64. Right here’s the circulate of the NuttX Code that boots on Ox64…
Clickable Version of NuttX Boot Flow
NuttX Boot Code: jh7110_head prints “123” and calls…
Early Serial Init: riscv_earlyserialinit calls…
Start NuttX: nx_start does many things and calls…
IRQ Init: up_irqinitialize calls…
Init NuttX: up_initialize calls…
Bringup NuttX: nx_bringup calls…
Due to this fact we anticipate NuttX to boot fully on Ox64 after we’ve carried out…
What’s this Reminiscence Map?
// Map the entire I/O Reminiscence
// with Digital Handle = Bodily Handle
#outline MMU_IO_BASE (0x00000000)
#outline MMU_IO_SIZE (0x50000000)
Contained in the BL808 SoC is the Sv39 Memory Management Unit (MMU) with 128 / 256 / 512 TLB desk entries. (Identical for Star64 JH7110)
The MMU maps Digital Reminiscence Addresses to Bodily Reminiscence Addresses. And stops the NuttX Kernel from accessing Invalid Addresses.
At startup, NuttX configures the MMU with the Reminiscence Map, the Vary of Reminiscence Addresses that the NuttX Kernel is allowed to entry.
The code above says that NuttX is allowed to entry any deal with from 0x0000
0000
to 0x5000
0000
. (Due to Reminiscence-Mapped I/O)
(MMU appears in OpenC906 User Manual, Page 50)
However we forgot so as to add the PLIC to the Reminiscence Map!
The Platform-Level Interrupt Controller (PLIC) is at 0xE000
0000
.
Let’s add the PLIC to the Reminiscence Map: jh7110_mm_init.c
// Map the entire I/O Reminiscence
// with Digital Handle = Bodily Handle
// (Contains PLIC)
#outline MMU_IO_BASE (0x00000000)
#outline MMU_IO_SIZE (0xf0000000)
This doesn’t look proper…
Yeah after we substitute the above MMU_IO_BASE and MMU_IO_SIZE into the Reminiscence Map: jh7110_mm_init.c
// Arrange the Kernel MMU Reminiscence Map
void jh7110_kernel_mappings(void) {
...
// Map I/O Area, use sufficient massive web page tables for the I/O area
// MMU_IO_BASE is 0x00000000
// MMU_IO_SIZE is 0xf0000000
mmu_ln_map_region(1, PGT_L1_VBASE, MMU_IO_BASE, MMU_IO_BASE, MMU_IO_SIZE, MMU_IO_FLAGS);
// Map the Kernel Code for L2/L3
// From https://github.com/lupyuen2/wip-pinephone-nuttx/blob/ox64/boards/risc-v/jh7110/star64/scripts/ld.script#L20-L27
// KFLASH_START is 0x50200000
// KFLASH_SIZE is 2 MB
map_region(KFLASH_START, KFLASH_START, KFLASH_SIZE, MMU_KTEXT_FLAGS);
// Map the Kernel Information for L2/L3
// From https://github.com/lupyuen2/wip-pinephone-nuttx/blob/ox64/boards/risc-v/jh7110/star64/scripts/ld.script#L20-L27
// KSRAM_START is 0x50400000
// KSRAM_SIZE is 2 MB
map_region(KSRAM_START, KSRAM_START, KSRAM_SIZE, MMU_KDATA_FLAGS);
// Join the L1 and L2 web page tables for the kernel textual content and knowledge
mmu_ln_setentry(1, PGT_L1_VBASE, PGT_L2_PBASE, KFLASH_START, PTE_G);
// Map the Web page Pool for NuttX Apps
// From https://github.com/lupyuen2/wip-pinephone-nuttx/blob/ox64/boards/risc-v/jh7110/star64/scripts/ld.script#L20-L27
// PGPOOL_START is 0x50600000
// PGPOOL_SIZE is 4 MB + 16 MB (together with RAM Disk)
mmu_ln_map_region(2, PGT_L2_VBASE, PGPOOL_START, PGPOOL_START, PGPOOL_SIZE, MMU_KDATA_FLAGS);
}
We see an issue with the Reminiscence Map…
(Web page Pool consists of RAM Disk)
The I/O Area overlaps with the Kernel Code, Information and Web page Pool!
This occurs as a result of the PLIC is positioned at 0xE000
0000
. Which is AFTER the RAM Area…
Reminiscence Area | Begin Handle | Measurement |
---|---|---|
I/O Area | 0x0000 0000 |
0x5000 0000 |
RAM | 0x5000 0000 |
64 MB |
Apps | 0xC000 0000 |
(See under) |
PLIC | 0xE000 0000 |
??? |
Additionally NuttX Apps will fail as a result of they run within the (Digital) Person Handle House at 0xC000
0000
: nsh/defconfig
CONFIG_ARCH_TEXT_VBASE=0xC0000000
CONFIG_ARCH_TEXT_NPAGES=128
CONFIG_ARCH_DATA_VBASE=0xC0100000
CONFIG_ARCH_DATA_NPAGES=128
CONFIG_ARCH_HEAP_VBASE=0xC0200000
CONFIG_ARCH_HEAP_NPAGES=128
However our Kernel Reminiscence House already extends to 0xF000
0000
!
Thus we would introduce one other Reminiscence Area, simply to map the PLIC.
(Or ought to we transfer the Person Handle House to 0xF000
0000
? Which supplies us max 256 MB for NuttX Apps?)
The OpenSBI Log would possibly supply some hints on the Reminiscence Map…
Firmware Base : 0x3ef80000
Firmware Measurement : 200 KB
Domain0 Region00 : 0xe4008000-0xe400bfff (I)
Domain0 Region01 : 0xe4000000-0xe4007fff (I)
Domain0 Region02 : 0x3ef80000-0x3efbffff ()
Domain0 Region03 : 0x00000000-0xffffffffffffffff (R,W,X)
Domain0 Subsequent Handle: 0x50000000
Domain0 Subsequent Arg1 : 0x51ff8000
(0x3EF8
0000
might be protected as a result of it comprises the OpenSBI Firmware. What’s “(I)
”?)
Try our progress right here…
How will we create the NuttX UART Driver for Ox64 BL808?
At this time NuttX helps the 32-bit predecessor of BL808: Bouffalo Lab BL602.
After we examine these UARTs…
We uncover that BL808 UART works the identical means as BL602!
Thus we’ll merely copy the NuttX Driver for BL602 UART to Ox64.
UART Interrupts are necessary: If UART Interrupts aren’t carried out, NuttX Shell (NSH) and NuttX Apps won’t print anything.
BL602 UART Driver has simply been ported to Ox64! (Minus the UART Interrupts) Test our progress right here…
What about different drivers: BL808 vs BL602?
The controllers under look extremely comparable on BL808 vs BL602. Which suggests we have now loads of NuttX Drivers to copy from BL602 to BL808!
Our earlier experiments with BL602 NuttX proved that the drivers above work properly. So we’re all set for BL808!
(BL602 NuttX is tested on Real Hardware every day)
What concerning the drivers lacking from BL602 NuttX?
We’ll port the lacking BL808 Drivers from Bouffalo Lab’s BouffaloSDK to NuttX.
(BouffaloSDK is Apache 2.0 Licensed)
Initial RAM Disk for Star64 JH7110
What’s this Preliminary RAM Disk?
The Preliminary RAM Disk comprises the Executable Binaries for NuttX Shell (NSH) and NuttX Apps.
At startup, NuttX masses the Preliminary RAM Disk into RAM and mounts the File System, in order that the NuttX Shell (and NuttX Apps) might be began later.
Why is the Preliminary RAM Disk lacking from Ox64?
That’s as a result of we haven’t loaded the Preliminary RAM Disk into RAM!
Two methods we will load the Preliminary RAM Disk…
-
Load the Preliminary RAM Disk from a Separate File: initrd (just like Star64)
This implies we have to modify the U-Boot Script: boot-pine64.scr
And make it load the initrd file into RAM.
(Which is sweet for separating the NuttX Kernel and NuttX Apps)
OR…
-
Append the Preliminary RAM Disk to the NuttX Kernel Picture
So the U-Boot Bootloader will load (one-shot into RAM) the NuttX Kernel + Preliminary RAM Disk.
And we reuse the prevailing U-Boot Config on the microSD Card: extlinux/extlinux.conf
(Which could be extra environment friendly for our Restricted RAM)
TODO: Can we mount the File System straight from the NuttX Kernel Picture in RAM? With out copying to the RAM Disk Memory Region?
We’ll most likely undertake the Second Technique, since we’re low on RAM. Like this…
## Export the NuttX Binary Picture to `nuttx.bin`
riscv64-unknown-elf-objcopy
-O binary
nuttx
nuttx.bin
## Insert 32 KB of zeroes after NuttX Binary Picture for Kernel Stack
head -c 32768 /dev/zero >/tmp/nuttx.zero
## Append the Preliminary RAM Disk to the NuttX Binary Picture
cat nuttx.bin /tmp/nuttx.zero initrd
>Picture
## Overwrite the Linux Picture on Ox64 microSD
cp Picture "/Volumes/NO NAME/"
Try our progress right here…