Start documenting process

This commit is contained in:
Blizzard Finnegan 2025-03-12 15:03:17 -04:00
parent 89f433be07
commit b112b9bcc0
Signed by: blizzardfinnegan
GPG key ID: 61C1E13067E0018E
3 changed files with 210 additions and 2 deletions

View file

@ -1,3 +1,50 @@
# nvidia-riscv
This is where I plan to store all of my notes and documentation regarding my RISC-V computer build. Each section of this will have a boiled-down script-like version available in this repository as well, although this file will be the main source of information until the scripts have been built.
Documentation of my journey building a RISC-V computer with an NVidia GPU
# Configuration
- Mainboard: [Milk-V Jupiter](https://milkv.io/jupiter) with SpacemiT M1-x processor (Original retail price) [^1]
- RAM: 16GB of LPDDR4X (Soldered)
- GPU: [Gigabyte GTX 1050Ti](https://www.techpowerup.com/gpu-specs/gigabyte-gtx-1050-ti-oc.b3909) (Use, ~$50 off eBay)
- Power Supply: 750W SFX PSU (model number to come; something cheap off amazon)
- Case: [SGPC K49 Case](https://www.sgpcdesign.com/products/sgpc-itx-mini-case-k49steel) (Something cheap off amazon)
- CPU Cooler: Cheap generic heatsink off amazon; not strictly necessary
I would recommend having a >16GB SD card available, a >16GB NVMe drive, and a USB-to-UART serial adapter for early boot observation and interruption when/if necessary.
# Basics: Booting the Board
So, let's start with the basics. This board ships with 2 manufacturer-supported compatible linux distributions; Bianbu OS (based on Ubuntu), and Ubuntu Linux 23.10. Ubuntu 23.10 is EOL, so that's no good. Bianbu OS is a Chinese-first distribution, developed by SpacemiT. Firstly, I personally don't trust the longevity and security of board-manufacturer linux distributions, and secondly, I can't read hanzi (chinese characters). So, already at square one, we're stuck.
Luckily, Milk-V is not the only manufacturer of devices containing the SpacemiT K1/M1 family of processors. Other implementations include the BananaPi BPI-F3 single-board computer, the SpacemiT MuseBook laptop, and the DC ROMA II laptop. The DC ROMA II, which I also have, natively supports Ubuntu 23.10, Ubuntu 24.04, and Debian sid/trixie. Debian [officially supports the RISC-V architecture](https://riscv.org/ecosystem-news/2023/07/debian-gnu-linux-is-now-officially-supported-on-the-risc-v-architecture/), so for the remainder of this discussion I will be using Debian.
So, all that needs doing now is to flash the ISO to an NVMe drive, install it, and boot the device right? Well, not quite so fast. You can just flash the ISO to an *SD* card, but not an NVMe. For how I've done this, you'll actually need both. For reasons that [are documented by Bianbu](https://git.blizzard.systems/bianbu-repo-mirror/bianbu-linux-docs/src/branch/main/en/device/boot.md) but not well understood by me, the partition structure the board wants is... not as you'd expect. For more information, see the aforementioned link, but the short version is, we need to flash the board with either `fastboot`, or their distributed tool [Titanflasher](https://github.com/milkv-jupiter/jupiter-tools/releases/tag/titanflasher). The fastboot commands are documented, and will be added to this repository, but I couldn't get it to play nicely, so I would recommend using the Titanflasher tool. Titanflasher has an auto-updater, and I'd also recommend that since the released version in the Github doesn't make it nearly as easy to change the language, and again defaults to Chinese.
So the first real step is downloading the Ubuntu 23.10 release from [Milk-V's github page](https://github.com/milkv-jupiter/jupiter-ubuntu-build/releases). We'll use this to flash the onboard NOR storage with the appropriate uboot version and configuration. You will also need the [DC ROMA II Debian image](https://drive.google.com/file/d/14QySBh36lR1JhwN1AoZgiBQrxX6HsKGA/view?usp=drive_link). Yes, it's a Google Drive link, it's what DC Roma distributes at time of writing. Flash the Debian image to an SD card using your tool of choice (BalenaEtcher is nice if `dd` makes you nervous), and use Titanflasher to burn to the board storage (this will be documented in a separate document).
Because the Jupiter board puts SD card as higher priority than NVMe, it should just boot to SD card if both devices are installed. The board boots as soon as power is given, so no need to press the power button. The board should boot properly to Debian Trixie, although this will take some time. The GUI will also show a complaint about not having much space left for storage; you can fix this if you want be resizing the partition, but it'll make the next step faster if you don't. We don't really care what's going on here, we just want to copy everything out onto the NVMe. The default login for this image is `roma` for both the user and password. Open a terminal, either in the GUI or over the serial connection, and run the following to transfer the Debian install over to the NVMe.
```bash
sudo dd if=/dev/mmcblk0p5 of=/dev/nvme0n1p5 status=progress
sudo dd if=/dev/mmcblk0p6 of=/dev/nvme0n1p6 status=progress
```
This will copy Debian over to the NVMe drive, along with the boot partition and it's appropriate configuration. Once both of these commands finish, you can resize the partitions on the NVMe drive using something like `cfdisk` and `resize2fs`. For some reason, `fdisk` doesn't seem to play nicely with this, and resizing doesn't always work, so keep the SD card handy in case it refuses to boot later. turn off the device, remove the SD card, and boot the device again. If all goes according to plan, you should end up with the same setup as before, but now it's on an NVMe drive.
# New Kernel
Now that we're booted and into linux, we need to get an updated version of the kernel. Make sure you have network access (wifi won't work right now, we'll get to that in a bit), then download the [SpacemiT kernel](https://gitee.com/bianbu-linux/linux-6.6). I doubt that SpacemiT will upstream their changes, which is a bit unfortunate, but we work with what we can. As documented [here by Bianbu](https://bianbu-linux.spacemit.com/en/faqs/), you will also need to download the [Real-Time CPU firmware](https://gitee.com/bianbu-linux/buildroot-ext/tree/bl-v2.0.y/board/spacemit/k1/target_overlay/lib/firmware) (you're looking for `esos.elf`), and it will need to be added into either the linux kernel build, `/lib/firmware`, or both.
While you are waiting for that to download, you should also install `linux-firmware` from the package manager. You can also use the `linux-firmware` git repository hosted [on the kernel git page](https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware) if you'd prefer. You will also need to install the dependencies required for kernel development, as documented by Milk-V:
```bash
sudo apt-get install flex bison libncurses-dev debhelper libssl-dev u-boot-tools libpfm4-dev libpfm4-dev libtraceevent-dev asciidoc
```
# Acknowledgements
This was developed with the help of many various forum posts, along with the discussion and documentation from these specific people:
- `opvolger`, for documenting the custom kernel process on his blog and [on GitHub](https://github.com/Opvolger/Opvolger/blob/master/milkVjupiter/OpenSUSEATIRadeonHD5850.md)
- Ard Biesheuvel and Alexander Graf, for their work documenting, developing, and publicly discussing [u-Boot, UEFI, Grub](https://www.youtube.com/watch?v=qJAkJ3nmWgM), and [emulation in UEFI](https://www.youtube.com/watch?v=uxvAH1Q4Mx0)
- Jeff Geerling, and the many contributors to the Raspberry Pi forums for their discussions of defining manually modifying DeviceTree for [expanding BAR space](https://forums.raspberrypi.com/viewtopic.php?t=288902)
[^1]: The Milk-V Jupiter For context, the K1 and M1 are functionally identical silicon design; the K1 uses a plastic housing and is clocked slightly lower than the M1, which has a metal case for better thermal conductivity. They're also collectively referred to as the Stone series or Key Stone series, depending on which page of the SpacemiT website you read (this is likely a machine translation inconsistency, at a guess).

28
fastboot.sh Normal file
View file

@ -0,0 +1,28 @@
# According to the Milk-V documentation:
# "The following flashing commands are for developers' reference only"
# The commands also show up in the Titanflasher command window, for transparency
#
# This flashes based on images posted on the Milk-V docs page: https://milkv.io/docs/jupiter/getting-started/resources
# Note that this uses the ZIP file, rather than the zipped image file. Titanflasher unzips the zip file.
fastboot stage factory/FSBL.bin
fastboot continue
sleep 2
fastboot stage u-boot.itb
fastboot continue
sleep 3
#adb reboot bootloader
#sleep 3
fastboot flash gpt partition_universal.json
fastboot flash bootinfo factory/bootinfo_sd.bin
fastboot flash fsbl factory/FSBL.bin
fastboot flash env env.bin
fastboot flash opensbi fw_dynamic.itb
fastboot flash uboot u-boot.itb
fastboot flash bootfs bootfs.ext4
fastboot flash rootfs rootfs.ext4
sleep 2
fastboot reboot

133
ubootTalkNotes.md Normal file
View file

@ -0,0 +1,133 @@
Direct notes from talks on uBoot, UEFI, and new board spinup on uboot
---
# UEFI in U-boot
efi_loader: UEFI interface translation layer for uboot
How do we call it though?
`bootefi` requires a kernel and devicetree loaded into memory.
call `bootefi $kernel_addr_r $fdt_addr_r`
This runs an EFI stub, and boots as normal.
You also need a `setenv bootargs console=tty earlycon` for boot debugging so you can watch it boot properly.
`fdt chosen` updates current devicetree
Seems like it might not require an initramfs?
Enables bidi interface for UEFI, which is increasingly more important.
# distroboot
`boot_targets=mmc0 usb0 pxe dhcp` defines which targets to look for.
Search for `extlinux` file, boot script, or an `EFI` executable.
`EFI` assumes first partition is EFI System Partition
uboot knows your wanted devicetree, so it searches under:
- `/`
- `/dtb/`
- `/dtb/current/`
- `/boot/`
- `/boot/dtb/`
- `/boot/dtb/current/`
##SD
Also looks for `efi/boot/boot(arch).efi`
"Is that signed?" - we'll come back to it. Doable, not implemented at 2017
Loads grub, plays like normal.
Grub can load a kernel, an initrd, an initramfs, whatever grub normally does.
## ISO
We have SD cards implemented, which is all we need, right?
Well, not really. We need ISO and Network support too.
Some PowerPC forks hacked in a solution.
There's a module for uboot that exposes an ISO as a partition table. Then we can just play like normal.
Stable code since 2016ish.
## networkboot
2 kinds, PXE boot and DHCP boot. PXE is extlinux specific.
DHCP is what you would call PXE.
Sends a DHCP request, with a hint token saying "I'm an EFI system on this architecture" in the "Vendor [something] specific interface". REturns a filename property in its ACK, which is then downloaded from a TFTP server.
Works the same as tianocore or AMI.
# EFI Tables
Pointers to binary blobs with a UUID prepended.
DeviceTree is in there, ACPI is in there, etc.
U-Boot doesn't implement ACPI. "If anybody wants to implement that in a uboot environment, be my guest! But I don't know why you would want to do that"
This is where DeviceTree is stored and used after initial boot! And since you can only have one at a time, this makes DeviceTree compatible.
# What doesn't work?
- NVRAM runtime services
No generic RTC interface, no configurable boot order (which.... we need that???)
- Editable object bucket
Loading stuff into Uboot gets thrown out in the next use; can't boot from BTRFS
- Libraries in object bucket
... which means you don't have an EFI shell either. But we're in embedded land, so its not that useful anyways.
# Why?
Complete separation between hardware and software
Removes generic implementation value add from firmware, takes it back to software
Current situation is tweaking uboot until it doesn't behave normally, or it becomes a maintenance mess
EFI is a generic value add, and it means you can switch to a different architecture
"One day when I get around to it I'll write a mainframe port"
removes dependency on Linux as well
uboot as OS
"Don't reinvent the wheel"
"How do we get from a firmware that goes away to a firmware that stays resident?"
Specially marked points in functions so they don't get overwritten
Linux can also move those runtimes around, so we need to know about that
Optional implementation, but no real overhead
PSCI vs EFI
PSCI lives in EO3, EO2 is hypervisor, EO1 is system mode, EO0 is userspace. PSCI and EFI live in EO3, so it can't get messed with by the kernel
-------
New board running uboot:
1. RAM
2. Serial
There's an internal printlog for the kernel and uboot; you can listen to this by JTAG
3. Networking
Netboot means you're no longer the problem
Ethernet driver and PHY are needed here.
If you're lucky, you have a driver from a similar SOC
1. Or just get PCI working, then use an existing PCI-driven network driver.
This isn't necessarily easier though
But I don't have network, or no TFTP allowed, or ethernet is not working in A0
Option 1: SPI programmable via JTAG
Option 2: Removable SPI chip (very very tedious)
Uboot needs drivers for SPI or NAND to boot
4. Other peripherals
5. Diagnostics (uboot has a POST option)o
Make sure your uboot partition is generous, and/or check for that size beforehand
Upstreaming?
1. Mailing list
Push early, push often.
Each patch needs to be a singular logical change
Follow the model inhouse so you can just push direct from internal
Run checkpatch!
2. Upstreaming is good for your project, try to push for it early.
You might need to upstream until after release.
1. Start with a rebase to latest version.
This might just magically work! ....... or maybe not. In which case start from scratch.
2. Squash
No one cares externally
3. Carve into submittable chunks
1. Basic enablement
2. DeviceTree
3. Individual driver in a separate patch
4. diags and anything else (might need company permissions)
If you've released this thing, it's GPLv2, it's no longer proprietary.