How to get U-Boot to Load and Run a Bare-Metal Binary on the Raspberry Pi 3 Model B+? [closed] - raspberry-pi

Closed. This question is not about programming or software development. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 8 days ago.
Improve this question
I have a Raspberry Pi Model 3B+. Currently, I can successfully load this exact kernel8.img file (which is just a raw binary) from this tutorial bare metal following the instructions outlined in the tutorial's README as shown below:
... you can download a raspbian image, dd it to the SD card, mount it and delete the unnecessary .img files. Whichever you prefer. What's important, you'll create kernel8.img with these tutorials which must be copied to the root directory on the SD card, and no other .img files should exists there.
The serial output after the above kernel8.img is running successfully looks something like this:
EMMC: GPIO set up
EMMC: reset OK
sd_clk divisor 00000068, shift 00000006
EMMC: Sending command 00000000 arg 00000000
EMMC: Sending command 08020000 arg 000001AA
EMMC: Sending command 37000000 arg 00000000
EMMC: Sending command 29020000 arg 51FF8000
EMMC: CMD_SEND_OP_COND returned VOLTAGE CCS 0000000040F98000
...
However, I would like to load that kernel8.img file via U-Boot and TFTP so that I don't have to keep plugging/unplugging microSD cards.
I have a functioning TFTP server and I have loaded U-Boot onto the Raspberry Pi successfully.
The physical address the kernel image gets loaded to bare metal is 0x80000 as explained by the tutorial:
Important note, for AArch64 the load address is 0x80000, and not 0x8000 as with AArch32.
The kernel8.img's file-type is also just a raw binary:
$ file kernel8.img
kernel8.img: data
As such, I've run the following two U-Boot commands:
tftp 0x80000 rpi3bp/kernel8.img
go 0x80000
However, as shown below, I'm getting some garbled mess once the binary is running: ��ogK�S��rK.
...
U-Boot> tftp 0x80000 rpi3bp/kernel8.img
lan78xx_eth Waiting for PHY auto negotiation to complete........ done
Using lan78xx_eth device
TFTP from server 192.168.0.198; our IP address is 192.168.0.111
Filename 'rpi3bp/kernel8.img'.
Load address: 0x80000
Loading: ################################################## 6.6 KiB
603.5 KiB/s
done
Bytes transferred = 6808 (1a98 hex)
U-Boot> go 0x80000
## Starting application at 0x00080000 ��ogK�S��rK
According to this SO post (as shown below), the go command is all that is required to get a bare-metal binary running on U-boot.
If you have issues executing your binary when using the go command,
then the problem lies with your program, e.g. taking control of the
processor and initializing its C environment.
However, I know for a fact that the kernel image runs fine bare-metal using the Raspberry Pi's default bootloader. So what could be the issue here and why can't I seem to get that kernel image running via U-Boot?
Edit 1:
Here's some context on how I set up U-Boot on the Raspberry Pi. Currently, the Raspberry Pi's bootloader is booting U-Boot in 64-bit mode. The Raspberry Pi's bootloader is configured via the config.txt file and below is my config.txt file:
enable_uart=1
arm_64bit=1
kernel=u-boot.bin
Documentation on the arm_64bit option is here:
arm_64bit
If set to non-zero, forces the kernel loading system to assume a
64-bit kernel, starts the processors up in 64-bit mode, and sets
kernel8.img to be the kernel image loaded, unless there is an explicit
kernel option defined in which case that is used instead. Defaults to
0 on all platforms.

The issue is related to the fact that U-Boot uses UART1 on the Raspberry Pi and the binary I'm trying to run uses UART0 as explained by #sawdust below:
Per U-Boot's DT, it appears that U-Boot uses UART1 on gpios 14&15. The
standalone uses UART0 on the same gpios. So that explains both (a)
getting output from two programs on same pin, and (b) why removing
uart_init() failed. Since U-Boot sets up UART0 for Bluetooth, perhaps
the standalone does not expect that; hence a goofy baudrate. An
oscilloscope could easily verify that.
I know this to be true because I modified the code in uart.c to use UART1 instead and I can now see sensible serial output now.
However, it is still unclear to me why despite the seemingly valid initialisation of UART0 in this part of the code, UART0 does not seem to output legible characters at the right baud rate.

Related

Boot process for Raspberry Pi Compute module 4 running Yocto image with u-boot

I am learning about u-boot and how this works in the Raspberry Pi system.
This is what I understood so far:
The first stage from the RPI cannot or should be modified. In this stage the BootROM simply loads the bootloader from the flash EEPROM.
In the second stage the EEPROM boot loader finds and loads start.elf, whose task is to load the kernel. It first reads "config.txt" which contains a kernel parameter. This is where u-boot is "injected".
kernel=u-boot.bin
U-boot can then in turn load the actual kernel. For a CM4 this would be "kernel7l.img".
I would be super satisfied with this knowledge, but in practice I have (possibly) seen other ways of integrating u-boot. I am here referring, for example, to Yocto recipes for the CM4 (meta-raspberrypi / u-boot). The boot directory of such an image contains: boot.scr, uboot.env, and uImage.
The readable part of boot.scr specifies that uImage will be loaded:
value bootargs /chosen bootargs
fatload mmc 0:1 ${kernel_addr_r} uImage
if test ! -e mmc 0:1 uboot.env; then saveenv; fi;
bootm ${kernel_addr_r} - ${fdt_addr}
config.txt does not contain a kernel parameter.
So here my questions for this boot process:
start.elf cannot be modified since it is proprietary. How can it load u-boot if there is no kernel parameter in config.txt pointing to a binary u-boot? boot.scr is supposed to run before u-boot.bin. Who reads and executes boot.scr?
is uImage just another name for u-boot.bin?
In this scheme how does u-boot know it must load "kernel7l.img"?
Are there other ways of integrating u-boot in a RaspberryPi? Is there any documentation which describes these different integration schemes?
Thank you very much for your help!
The boot.scr script is read by U-Boot.
fatload mmc 0:1 ${kernel_addr_r} uImage loads a kernel in deprecated U-Boot specific format which can be created with the mkimage command.
The bootm ${kernel_addr_r} - ${fdt_addr} command receives the addresses of uImage and the device tree. The address for the initrd is left out ('-'). bootm starts the kernel and passes the device tree address to it.
Adding kernel=u-boot.bin to config.txt is the correct way to invoke U-Boot on a Raspberry.
Distributions like Suse and Fedora prefer to boot Linux via GRUB on the Raspberry using U-Boot's bootefi command.
So here my questions for this boot process:
start.elf cannot be modified since it is proprietary. How can it load u-boot if there is no kernel parameter in config.txt pointing to a binary u-boot?
The kernel=... parameter in the config.txt is an optional parameter that specifies an alternate (kernel) filename to load by the EEPROM boot program.
The default filename to load from the boot partition depends on the RPI version.
According to RPi documentation, the default kernel filename on the Pi 1, Pi Zero, and Compute Module is kernel.img, on the Pi 2, Pi 3, and Compute Module 3 it is kernel7.img, and on the Pi4 it is kernel7l.img
If "there is no kernel parameter", then inspect the kernelx.img file; what are the contents?
boot.scr is supposed to run before u-boot.bin. Who reads and executes boot.scr?
Incorrect, boot.scr is not "run before u-boot.bin".
The file boot.scr contains script that can be interpreted by U-Boot.
(The executable image for U-Boot is the u-boot.bin file.)
is uImage just another name for u-boot.bin?
No, those are two distinct filenames with completely different uses.
The u-boot.bin file is the executable image for U-Boot.
A uImage file is a kernel image with the U-Boot wrapper for identification and verification. The U-Boot wrapper/header can be used for a variety of objects such a U-Boot script or a standalone executable besides a kernel image.
See Image vs zImage vs uImage
In this scheme how does u-boot know it must load "kernel7l.img"?
U-Boot does not have that directive (in this situation).
According to the boot.scr file that you posted, the booting sequence that U-Boot will perform is to load the uImage from the boot partition.
Are there other ways of integrating u-boot in a RaspberryPi? Is there any documentation which describes these different integration schemes?
As mentioned in your post and the other answer, an explicit kernel=u-boot.bin in the config.txt would be the obvious/preferred method to invoke U-Boot.
Otherwise, IDK. Today's alternative could be tomorrow's deprecated method.

CodeSys killing eth0 on Raspberry Pi 4?

I'm running into a very strange issue attempting to run CodeSys on a 4GB RasPi-4. Long story short, the Pi works fine right up until I start running the CodeSys project. When I do, within 60sec, eth0 goes down and cannot be brought back up. Even rebooting the Pi has no effect. The only way I've found to recover eth0 is to re-burn RasPiOS from the source image from Raspberrypi.org (which I've done about 30 times over the past few days, trying to trial-and-error my way out of this).
Linux raspberrypi 5.4.79-v7l+ #1373 SMP Mon Nov 23 13:27:40 GMT 2020 armv7l GNU/Linux
I have eth0 set to a static IP using /etc/dhcpcd.conf. Whatever is causing this issue is not altering my settings there. Attempts to use ifconfig eth0 up/down have no effect -- no errors, no feedback, just nothing. Checking eth0's state shows "waiting for carrier," despite being connected to an active switch (I've also swapped out all the cables and the switch to eliminate them as the source of the problem).
When I re-burn the Pi and install CodeSys, eth0 stays up indefinitely (24hrs+ in my longest test). It's starting the CodeSys project that kills eth0. A reboot after etho "dies" gives a series of bcmgenet messages that appear to be related:
pi#raspberrypi:~ $ dmesg | grep bcmg
[ 1.033665] bcmgenet fd580000.ethernet: failed to get enet clock
[ 1.033685] bcmgenet fd580000.ethernet: GENET 5.0 EPHY: 0x0000
[ 1.033709] bcmgenet fd580000.ethernet: failed to get enet-wol clock
[ 1.033730] bcmgenet fd580000.ethernet: failed to get enet-eee clock
[ 1.044648] libphy: bcmgenet MII bus: probed
[ 9.528502] bcmgenet fd580000.ethernet: configuring instance for external RGMII
[ 9.535175] bcmgenet fd580000.ethernet eth0: Link is Down
I also tried creating a new CodeSys project from scratch that had no eth0 drivers (ModBus, Ethernet/IP) installed, only the GPIO driver. That didn't help either -- eth0 dies within 60sec.
The strangest part is, only eth0 seems to be affected. The GPIO pins keep cycling as controlled by the CodeSys project (I have a simple LED-blinking program running), and I can still SSH into the Pi using wifi. But since my main reason for setting this Pi up is to use Ethernet/IP and ModBus....
This thread: at GitHub is the only place I've found anyone describing anything similar to what I'm experiencing, but in that case CodeSys is not installed. I did try adding genet.skip_umac_reset=n to my cmdline.txt as suggested in the thread, but it had no effect.
So, it turned out this was an issue configuring the GPIO pins.
CodeSys has two difference "device" files for adding the GPIO pins to the project device tree. The default selection is for older Pi models, and the alternate choice (labelled only for B+ and Pi2) is the correct one for the Pi4.
As it turns out, the outdated GPIO device file will work on a Pi4, mostly. But using the wrong device file allows CodeSys to try configuring GPIO pins that shouldn't be tampered with. In this case, GPIO 28 and 29. Setting either of them to Output mode killed eth0.
Using the correct device file removes 28&29 from the list of configurable GPIO pins. It also gives the correct list of available GPIO pins for the newer Pi models, hopefully avoiding other potential config issues that I didn't trip over.
In CodeSys, right-clicking on the GPIOs element in the device tree offers the option to "Update the Device." Select this option to get the list of available device files, and select the correct one before using the "Update Device" button in the bottom of the window.

Is there a library for MSR605X that works with Raspberry Pi?

I have been trying to locate a working library for the MSR605X magnetic card reader/writer. At time of writing, I have tried five separate libraries. Only two of these were explicitly for the 605X the other three were for the older 605. All the libraries I have tried either did nothing at all or errored before completing a command (can't figure out the errors either).
I am running Raspberry Pi OS 32 bit on a Raspberry Pi 3 B+ the MSR605X communicates via a USB connection.
So far the library that seems to be most complete is: https://pypi.org/project/msrx/
However, I can not get this library to read or write (either nothing happens or I get a Serial exception "cannot reconfig port).
Any help or links to documentation for this reader is welcome.
EDIT: Adding the commands ran with the above library
msrx -D /dev/input/event4 read
msrx -D /dev/input/jso0 read
The -D is to specify the device path (default is /dev/ttyUSB0 which doesn't exist on my system). I obtained the above two paths by searching for USB serial devices then matching the search result to the device ID which I obtained from lsusb.
Running these commands results in a serial exception (could not reconfig port) which I assume means that I have the wrong device path. I have also checked for any tty* device paths that are changed when I plug in the reader. I consistently get a permission denied error whenever trying to run the above commands with a tty* device path (I am root on this system).
msrx author here — MSR605 requires an external 9V power injected into its cable (via the barrel jack port), otherwise it won't power up properly.

Bare metal Raspberry Pi 2: Generating an SD card image for QEMU emulation

I've recently been getting into bare metal development for the Raspberry Pi 2, and having some success. Admittedly I've hesitated to buy an actual physical device until I feel I can do something useful with it, for the time being I've been emulating the device using qemu 2.11.0.
So far I've developed multicore capabilities for my kernel, as well as simple Serial I/O, but I feel I'd like to get much further before working with a physical device.
My issue right now is that I'm trying to learn how to place my kernel onto an SD card image and boot qemu-system-arm from that SD card image, so I can properly emulate a kernel loaded from the raspberry pi 2 bootloader.
I've gotten as far as grabbing the SD card contents from https://github.com/raspberrypi/firmware ... aster/boot, and using the following script to create the image and load my kernel into it. I've seen that people have figured out how to load Raspbian from an emulated SD card, so I figure I can do the same.
#!/bin/bash
OUTPUT_IMG=os.img
OUTPUT_IMG_SIZE=40
TEMP_MOUNT_DIR="$(mktemp -d)"
# the SD card boot partition contents are in this folder...
OUTPUT_IMG_CONTENTS_DIR="./sd"
OS_DIR="${HOME}/os"
OS_BINARY="${OS_DIR}/kernel.bin"
dd if=/dev/null of=${OUTPUT_IMG} bs=1M seek=${OUTPUT_IMG_SIZE}
mkfs.fat -F 32 ${OUTPUT_IMG}
sudo mount -t vfat -o loop ${OUTPUT_IMG} ${TEMP_MOUNT_DIR}
make -C ${OS_DIR} clean
make -C ${OS_DIR}
sudo cp -r ${OUTPUT_IMG_CONTENTS_DIR} ${TEMP_MOUNT_DIR}
sudo cp ${OS_BINARY} "${TEMP_MOUNT_DIR}/kernel.img"
The only issue is that qemu doesn't seem to boot from this image using the following command:
qemu-system-arm -machine raspi2 -serial file:serial.log -sd ./dev/os.img
I've tried a few different combinations, but to no avail.
I can see from hooking GDB that the kernel is simply not booting from this card image. Loading the kernel directly into qemu with the -kernel argument works otherwise perfectly.
I was wondering if anyone here had any insight on how to accomplish this!
Any help here would be greatly appreciated!
Your command won't work because you haven't passed QEMU either a guest BIOS or a guest kernel to run. The QEMU arm boards aren't like the x86 PC machine, which always automatically runs a guest BIOS image. If you want to run a BIOS (probably UEFI?) you need to find a suitable BIOS blob and pass it to QEMU with the -bios argument. Then QEMU will run the BIOS code, which will hopefully include SD card drivers to load the kernel and so on off the SD card.
Just using -kernel is much simpler...
After doing a bit of reading and searching online, as well as a bit of help from other contributors such as Peter Maydell with his answer above, I think I've answered my own question. Unless I'm mistaken qemu-system-arm does not fully emulate the Raspberry Pi boot process, and instead just loads the kernel specified with the -kernel argument by loading the binary into the guest system's memory and jumping to the entry point. It doesn't look like any additional hardware bootloading is emualted for -M raspi2 unfortunately.
Can ARM qemu system emulator boot from card image without kernel param?
This question is similar and contains some more useful details on this issue, relating to qemu-system-arm as a whole..

iMX6: MSI-X not working in Linux PCIe device driver

I'm trying to get MSI-X working on an iMX6 (Freescale/NXP/Qualcomm) CPU in Linux v4.1 for a PCIe character device driver. Whenever I call either pci_enable_msix() or pci_enable_msix_range() or pci_enable_msix_exact() I get an EINVAL value returned. I do have the CONFIG_PCI_MSI option selected in the kernel configuration and I am also able to get single MSI working with pci_enable_msi(), but I cannot get multiple MSI working either.
I have tested my driver code on an Intel i7 running kernel v3 with the same PCIe hardware attached and I was able to get MSI-X working without any problems so I know my code is correctly written and the hardware is correctly functioning.
When running on the iMX6 I can use lspci -v to view that the hardware has MSI-X capabilities and see the number of IRQs it allows. I can even get the same correct number in my driver when calling pci_msix_vec_count().Questions
Are there any other kernel configuration flags I need to set?
Is there anything specific to the iMX6 CPU I need to consider?
Does anyone have any experience with the iMX6 and either MSI-X or
multiple MSI?