Best of Both Worlds
Turning the clock back to 2010, the Risc PC (available from 1994 to 2002) and the Iyonix (available from 2002 to 2008) were still doing sterling service but were no longer current machines. Virtual Risc PC was providing an emulation solution on current hardware. The Beagleboard-XM, running at 1GHz and having a much better memory bandwidth than the Iyonix offered promise.
The RISC OS port for the Beagleboard was in its infancy and development work required a serial terminal to observe what was happening. Various tinkering with the UBoot commands was part of this. At one stage I had an SD card image that would boot into either Linux or RISC OS depending whether the user push button on the circuit board was pressed during start up.
A rather complicated start up script provided three different options depending whether the user button (provided on the circuit board and readable by uBoot) was pressed after a few seconds, see below.
Contents of Boot/scr: led all off ; sleep 1 ; led 0 on ; sleep 1 ; led 1 on ; led 0 off echo Press USER button to enter Angstrom GUI sleep 3 ; mmc init if userbutton; then echo Entering Angstrom GUI; setenv bootargs 'console=ttyS2,115200n8 console=tty0 root=/dev/mmcblk0p2 rw roofstype=ext3 rootwait omapfb.mode=dvi:1280x1024MR-16@60'; setenv bootcmd 'fatload mmc 0 0x80300000 uImage; bootm 0x80300000'; boot; fi echo Entering RISC OS fatload mmc 0 0x4020F000 cmos;fatload mmc 0 0x80100000 riscos go 0x80100000
The Beagleboard ran the script 'boot.scr'. (If the user button was already pressed when it booted, then the script 'user.scr' ran instead and had similar instructions but started Linux command line.) After flashing the LEDs it looked again at the user button: if pressed it entered the Linux GUI, otherwise it started RISC OS.
That, of course, is all water under the bridge but it illustrates the complexity of start up scripts for non-RISC OS systems. It would not be until 2012 that the Raspberry Pi would appear and the focus of development work moved from the Beagleboard to the more affordable Raspberry Pi.
The solution for a dual boot option on the ARMBook is to put a Linux SD card in the slot if you want to boot into Linux and to remove it if you want to boot into RISC OS (which is flashed into eMMC).
On the Titanium RISC OS itself boots from NOR flash memory and does not use the SD card. If you do put an SD card in the slot containing Linux, then there is an application !GoLinux which will start Linux from RISC OS.
A solution for the Raspberry Pi is more complicated but a little more elegant. If you take the standard SD card image for RISC OS 5.28 then you have a card partitioned in a special way, see illustration immediately below.
This shows how the standard RISC OS SD card image for the Raspberry Pi appears. The card itself happens to be a 32GB card of which only 1875MB are used. The partition table shows a 48MB FAT partition and a filecore partition just below 1827MB in size. The contents of the FAT partition are displayed but Linux does not understand filecore so knows only that the space for it has been reserved.
This shows an SD card with a filecore partition and a FAT partition - so far as the partition data are concerned the FAT partition is 48MB and the filecore partition is 1827MB but RISC OS ignores the partition table (it knows it is the only show in town) and determines the size of its filecore image from the disc map itself. It knows therefore that it is 1875MB in size, encompassing the FAT partition which is carefully aligned so that the DOS image file $.!Boot.Loader in the filecore partition exactly corresponds to the FAT partition.
Let us look at the Raspian distribution (see illustration on next page) - this is also a two-partition SD card image which includes a 256MB fat partition and a 3384MB Linux partition which is seen (by Linux) as /dev/sdb2. Note that the contents of both partitions are displayed.
In order to create an SD card that will work on both operating systems then we will need a FAT partition of 256MB and a Linux partition of 4GB so let's make the filecore partition 2GB so that the whole image fits easily on an 8GB SD card.
Going down a cul-de-sac
This looked as if it would work. The first step is to use !SystemDisc to produce an SD card with a 256MB FAT partition and a 2GB filecore partition.
The second step is to create an ext4 partition of 4GB on the same card (big enough to accept a 3.7GB partition image).
We now have a card partitoned correctly and just need to populate it.
The third step is to use the 'dd' command in Linux to capture an image of the Linux partition on the Raspian distro and save it to disc. Then dismount the SD card and place the one prepared by !SystemDisc into the card reader and copy the partition image into the newly created ext4 partition.
The command line which copies the Linux partition from one SD card to another. Care is needed here!
We now have an SD card with three partitions and a lot of empty space. The filecore partition contains only a file $.!Boot.Loader and the FAT partition is empty. The FAT and filecore partitions can be populated with the RISC OS 5.28 hard disc contents, including the firmware and RISC OS ROM, making sure NOT to copy the DOS image file Loader, just its contents.
Let's also make sure that the RISC OS ROM is one that will work on the Pi 400 while we are about it. To do this, a few source files need editing to produce a rom but by 15 November the development roms will work on the Pi 400 as well as the Pi 4. Perhaps also the various versions of the Compute Module 4.
We will also copy over the contents of the FAT partition from the Raspian distro, making sure that we keep both versions of CONFIG.TXT and CMDLINE/TXT so that we can combine them.
I shall add a switch on the 40 pin header between pins 29 (GPIO5) and 30 (GND) to enable a decision to be taken at boot time whether to boot into Linux or RISC OS. This will require changes to the file CONFIG.TXT. These changes will cause a boot into Linux if the switch is closed and into RISC OS if it is left open.
Complications on Pi 4
If you move an SD card between a Pi 4 and another model, you need to delete the directory $.!Boot.Choices.Boot so that it is repopulated on start up to ensure the correct network drivers are loaded.
Changes to CONFIG/TXT
Now we have a switch on the header to pull GPIO5 to LOW if the switch is pressed, we can change CONFIG/TXT to take different action on booting. There is an option to examine a GPIO pin and make execution conditional.
The first line of the file jumps over the RISC OS bits if GPIO 5 is pulled low. Linux has done its stuff in the CMDLINE/TXT file and needs little in this file. RISC OS does not seem put out by it.
Now we can backup the SD card image (Win32DiskImager will create an image file the whole length of the SD card but this file can be truncated to a shorter length so that it will fit various different makes of 8GB SD card.
disable_gamma console=serial0,115200 console=tty1 root=PARTUUID=3a324232-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet init=/usr/lib/raspi-config/init_resize.sh splash plymouth.ignore-serial-consoles
The contents of CMDLINE/TXT - the location of the root file system is specified by a partition UUID, highlighted above. For a particular SD card image this magic number is known. If you specify the correct partition UUID for an ext4 partition on a USB pen drive then Linux will boot from that pen drive. When it resizes the ext4 partition the UUID changes but it updates the CMDLINE.TXT on the pen drive.
The purpose of this backup is so that a fresh card can be created and retested if things go wrong! Also the first boot does some complicated things to the SD card image that has taken so long to create and it is wise to be able to do the testing on a known SD card image.
F%=OPENUP"C:\Data\30G_armini.img" PTR#F%=0 L%=1392508928 H%=7 SYS "SetFilePointer",@hfile%(F%),L%,^H%,0 SYS "SetEndOfFile",@hfile%(F%) SYS "CloseHandle",@hfile%(F%) END
This programme truncates the file to a length of 1328MB plus 7*4096MB = 30000MB. To truncate to 7000MB then L%=3045064704 and H%=1 and to truncate to 4GB plus 1875MB we need L%=1875*1024*1024 and H%=1. This image is 5971MB and so should comfortably fit onto an 8GB SD card.
A short programme in BBC BASIC for Windows will do this - RISC OS struggles to handle files which are so large. See inset below for details.
The SD card can be recreated (by writing the image to the card again) between each attempt so that the fresh install is preserved until we get it right.
The CMDLINE/TXT file is used extensively by Linux (not all of which I understand) and it refers explicitly to the ext4 partition by means of a magic number which is only known after the SD card partition has been created.
Whereas RISC OS requires very few, if any, commands in the CMDLINE/TXT file (disable_gamma and disable_mode_changes for example), Linux requires lots of stuff, which RISC OS can happily ignore. The partition UUID on our three partition SD card is currently unkown. The method above looked plausible to discover it but failed miserably. A later version of Linux would have allowed the more specific command ls -l /dev/disk/by-partuuid and I would have obtained the information I needed.
Going back to the 1875MB RISC OS SD card image with a 256MB FAT partition I took another approach. I downloaded the Raspian distro and flashed it to a USB pen drive. Now the CMDLINE.TXT file in the FAT partition of the pen drive had the correct partition UUID for the ext4 partition on the pen drive.
I therefore copied the contents of the FAT partition on the pen drive onto the SD card. I then added the CMOS and RISCOS/IMG files. At this stage the SD card would boot into Linux on the pen drive and then ignore the SD card.
Now let's look at the changes to CONFIG.TXT to enter RISC OS by default (highlighted) and Linux if the button on GPIO 5 is pressed.
[gpio5=1] fake_vsync_isr=1 framebuffer_swap=0 gpu_mem=64 init_emmc_clock=100000000 ramfsfile=CMOS ramfsaddr=0x508000 kernel=RISCOS.IMG device_tree= hdmi_drive=2 hdmi_blanking=1 disable_overscan=1 [pi4] enable_gic=1 [all][gpio5=0] # Additional overlays and parameters are documented /boot/overlays/README # Enable audio (loads snd_bcm2835) dtparam=audio=on [pi4] # Enable DRM VC4 V3D driver on top of the dispmanx display stack dtoverlay=vc4-fkms-v3d max_framebuffers=2 [all] #dtoverlay=vc4-fkms-v3d
The edited CONFIG/TXT file - the conditional statements are in square brackets with the RISC OS bit highlighted.
Did this work?
Almost. Hold the button down and the Raspberry Pi booted into the Linux distribution on the USB pen drive. It then displayed a message to say that it was extending the ext4 partition to fill the drive to use the whole of the capacity available. It then said ... rebooting in 5 seconds.
When it rebooted I had let go of the button by then and so it booted into RISC OS. No problem, I thought, I'll reboot and hold the button down this time. It then just kept rebooting until I let go of the button and then booted into RISC OS.
disable_gamma console=serial0,115200 console=tty1 root=PARTUUID=12345678-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles
The CMDLINE/TXT file on the USB pen drive has been silently changed to have the new partition UUID for the ext4 partition on that drive. The 'init' command to resize the partition on first boot has also been removed.
I then had a moment of inspiration and looked at the CMDLINE/TXT file on the pen drive. This was now different - the newly resized ext4 partition had a different UUID. So all I had to do was to copy the edited CMDLINE/TXT file from the FAT partition on the pen drive to the FAT partition on the SD card and it all worked.
What about the Pi 400?
The standard RISC OS 5.28 SD card image with a daily development rom on or after 125 November 2020 is a good way to check that things will be OK on the Pi 400. RISC OS started up fine on the Pi 400 at this stage.
Adding the huge number of extra files in the FAT partition of the RasPiOS distribution and the much larger CMDLINE/TXT and retesting on a Pi 4 showed that these extra files made no difference to RISC OS. They would be needed to start up RasPiOS although it would then run from the USB drive.
Testing the same SD card on the Pi 400 gave some problems - after a lot of trouble-shooting I found by trial and error that one particular file bcm-2711-rpi-4-b/dtb was needed for Raspian but, if present, prevented RISC OS from starting up on the Pi 400.
So the dual boot worked perfectly on the Pi 4 - press the button and booting was to RasPiOS, release it and booting was to RISC OS. Shutdown either system and the restart would be selected by the button - RISC OS or RasPiOS.
When the Raspberry Pi starts, two files are passed to the GPU - start4.elf (which specifies the VideoCore firmware in use) and fixup4.dat (which specifies memory locations). There are two methods, mutually exclusive, for the GPU to pass information to the kernel: the start.elf file will either load a device tree blob (if present) appropriate to the hardware or will put such information (called ATAG) into memory at 0x100.
Adding a command device_tree= to CONFIG.TXT forces the latter method for RISC OS and it all worked.
With an updated daily build rom, RISC OS works fine on the Pi 400 as part of the standard distribution.
The dual boot method, with RasPiOS on a USB pen drive and RISC OS on the SD card (with some extra files) works perfectly on the Pi 4 and the Pi 400 - choose your operating system with a push button.