Designing OpenWrt device from the (nearly) ground up

Can you paste the U-Boot environment content and partition layout? It would reveal a lot about boot process.

I can see two approaches:

  • pick one partition and use it for OpenWrt, preserving triple boot
  • since you're basically dealing with old unmaintained OpenWrt, simply overwrite all three partitions and use them as one big rootfs

I'd go with the second option in this case. I did the same when porting OpenWrt to Fritzbox 7362.

OCTEON eMMC stage 1 bootloader

Partition: 1, start: 0x0000000000000800, size: 0x0000000000200001
Reading 470976 bytes.
................................................................................................................... Done.
Loaded OCTBOOT2BIN, size: 0x0000000000072FC0
Branching to stage 2 at: 0xFFFFFFFF81004000
Board TLV descriptor Read - RHino continues ... 2 board 0x4e26 major 1 minor 0, DDR HERTZ 0 hz
Rhino: early board init, mem_clk 0x29b ..

U-Boot 2013.07 (Development build, svnversion: u-boot:exported, exec:) (Build time: Mar 27 2015 - 10:49:38)

Initializing DRAM
U-Boot is not RAM-resident
Rhino: lookup_ddr_config_structure: cpu_id 890370 board_type 20006 ...
Rhino: cpu_id 0xd9602 board_type 0x4e26 major 0x1 minor 0x0  mask 1 ...
Initializing DDR, clock = 667000000hz, reference = 50000000hz
LMC0_DCLK_CNT: 0xffffffffffffffff
Measured DDR clock 666666652 Hz
Mem size in MBYTES: 1024
RHino: new Ram size 1024MiB (0x40000000)
Ram size 1024MiB (0x40000000)
Clearing memory from 0 to 1048576
Done clearing memory
CUST_PRIVATE_RHINO_ITUS7X board revision major:1, minor:0, serial #: 
OCTEON CN7020-AAP pass 1.2, Core clock: 1000 MHz, IO clock: 600 MHz, DDR clock: 667 MHz (1334 Mhz DDR)
Base DRAM address used by u-boot: 0x4f804000, size: 0x7fc000
DRAM: 1 GiB
Clearing DRAM.....Clearing base address: 0x100000, size: 0xff00000, ub_base: 0x4f804000, ub_size: 0x7fc000
Stack: 0xc03f5c60
Done clearing memory, ub_base: 0x4f804000
.Clearing base address: 0x20000000, size: 0x30000000, ub_base: 0x4f804000, ub_size: 0x7fc000
Stack: 0xc03f5c60
Done clearing memory, ub_base: 0x4f804000
 done
Using default environment

MMC:   Octeon MMC/SD0: 1
Hit any key to stop autoboot:  0 
reading u-boot-octeon_rhino_itus7x.bin
early_board_init: Early board init .................
Importing environment from RAM address 0x1000
RAM environment is 33 bytes

U-Boot 2013.07 (Development build, svnversion: u-boot:exported, exec:) (Build time: May 21 2015 - 11:11:49)

Initializing DRAM
U-Boot is RAM resident
Using DRAM size from environment: 1024 MBytes
DDR clock is 667 MHz
RHino: new Ram size 1024MiB (0x40000000)
Ram size 1024MiB (0x40000000)
Preserving environment in RAM
Done clearing memory
Configuring DLM0 for QSGMII
DLM1: mini-PCIe slots selected
CUST_PRIVATE_RHINO_ITUS7X board revision major:0, minor:1, serial #: 752011191521-36409
OCTEON CN7020-AAP pass 1.2, Core clock: 1000 MHz, IO clock: 600 MHz, DDR clock: 667 MHz (1334 Mhz DDR)
Base DRAM address used by u-boot: 0x4f000000, size: 0x1000000
DRAM: 1 GiB
Clearing DRAM.....Clearing base address: 0x100000, size: 0xff00000, ub_base: 0x4f000000, ub_size: 0x1000000
Stack: 0xc0f71c60
Done clearing memory, ub_base: 0x4f000000
.Clearing base address: 0x20000000, size: 0x30000000, ub_base: 0x4f000000, ub_size: 0x1000000
Stack: 0xc0f71c60
Done clearing memory, ub_base: 0x4f000000
 done
board_fixup_fdt: Found PCIe GPIO2 ..
MMC device not found, initializing
Octeon MMC/SD0: 1
*** Warning - bad CRC, using default environment

PCIe: Link timeout on port 0, probably the slot is empty
PCIe: Port 1 not in PCIe mode, skipping
PCIe: Port 2 not in PCIe mode, skipping
Net:   cvmx_helper_interface: interface 0
cvmx_helper_interface: interface 1
cvmx_helper_interface: interface 4
octeth0, octeth1, octeth2, octeth3
Type the command 'usb start' to scan for USB storage devices.

late_board_init ..
ITUS: SW1 1 Bridge (INNER) 
Hit any key to stop autoboot:  0 
mmc1(part 0) is current device
reading ItusbridgeImage
35862152 bytes read in 3450 ms (9.9 MiB/s)
argv[2]: mem=0
argv[3]: numcores=2
Allocating memory for ELF segment: addr: 0xffffffff80100000 (adjusted to: 0x100000), size 0x23b1e90
## Loading big-endian Linux kernel with entry point: 0xffffffff80696500 ...
Bootloader: Done loading app on coremask: 0x3
Starting cores:
 0x3

At this point, you can see it loads the ItusxxxxxxImage based on the Switch position, into RAM

Is there a way to let the .BIN image just live as a LiveCD RAM image and store the packages on the /dev/mmcblk1px so that when the BIN gets updated, it'll not kernel-panic because the libraries/files kept on the /dev/mmcblk1px are older than the kernel (in RAM) and blow up..

Can you type printenv in U-Boot console and paste the output?

1 Like

Stage 1

Octeon cust_private_rhino_itus7x# printenv
do_env_print ......
baudrate=115200
boardname=cust_private_rhino_itus7x
bootcmd=bootstage3
bootdelay=3
loadaddr=0x20000000
numcores=2
octeon_failsafe_mode=0
octeon_ram_mode=0
octeon_stage3_bootloader=u-boot-octeon_rhino_itus7x.bin
stderr=serial
stdin=serial
stdout=serial
ver=U-Boot 2013.07 (Development build, svnversion: u-boot:exported, exec:) (Build time: Mar 27 2015 - 10:49:38)

Environment size: 391/8188 bytes

Stage 2

Octeon cust_private_rhino_itus7x(ram)# printenv
do_env_print ......
autoload=n
baudrate=115200
bf=bootoct $(flash_unused_addr) forceboot numcores=$(numcores)
boardname=cust_private_rhino_itus7x
bootcmd=run image_run
bootdelay=2
bridge=mmc dev 1;fatload mmc 1 $(loadaddr) brigdeImage;bootoctlinux $(loadaddr) mem=0 numcores=2
burn_app=erase $(flash_unused_addr) +$(filesize);cp.b $(fileaddr) $(flash_unused_addr) $(filesize)
dram_size_mbytes=1024
eth1addr=2c:26:5f:80:04:a5
eth2addr=2c:26:5f:80:04:a6
eth3addr=2c:26:5f:80:04:a7
ethact=octeth0
ethaddr=2c:26:5f:80:04:a4
gateway=mmc dev 1;fatload mmc 1 $(loadaddr) gatewayImage;bootoctlinux $(loadaddr) mem=0 numcores=2
image_run=mmc dev 1;fatload mmc 1 $(loadaddr) ItusgatewayImage;bootoctlinux $(loadaddr) mem=0 numcores=2 serial#=$(serial#)
linux_mmc=fatload mmc 1 $(loadaddr) vmlinux.64;bootoctlinux $(loadaddr) mem=0 numcores=2
loadaddr=0x20000000
ls=fatls mmc 1
numcores=2
octeon_failsafe_mode=0
octeon_ram_mode=1
router=mmc dev 1; fatload mmc 1 $(loadaddr) routerImage;bootoctlinux $(loadaddr) mem=0 numcores=2
serial#=752011191521-36409
stderr=serial
stdin=serial
stdout=serial
ver=U-Boot 2013.07 (Development build, svnversion: u-boot:exported, exec:) (Build time: May 21 2015 - 11:11:49)

Environment size: 1234/8188 bytes

OK, what about: run ls, help bootoct, help bootoctlinux?

Also, is there source for U-Boot bootloaders in both stages?

1 Like

Marvell/Cavium has a uboot source tree on their Github (https://github.com/MarvellEmbeddedProcessors/u-boot-marvell), but that's as far as I've looked into it.

Octeon cust_private_rhino_itus7x(ram)# run ls
            restore/
 35862152   itusbridgeimage 
 17675032   itusgatewayimage 
 23543944   itusrestoreimage 
 102217544   itusrouterimage 
   470976   octboot2.bin 
  1138416   u-boot-octeon_rhino_itus7x.bin 
            updates/
 17810200   itusgatewayimage-working 
 102217544   itusrouter-rescue 

8 file(s), 2 dir(s)

Octeon cust_private_rhino_itus7x(ram)# help bootoct
bootoct - Boot from an Octeon Executive ELF image in memory

Usage:
bootoct  [elf_address [stack=stack_size] [heap=heap_size] [coremask=mask_to_run | numcores=core_cnt_to_run] [forceboot] [debug] [break.
elf_address - address of ELF image to load. defaults to $(loadaddr). If 0, default load address used.
stack       - size of stack in bytes.  Defaults to 1 megabyte
heap        - size of heap in bytes.  Defaults to 3 megabytes
coremask    - mask of cores to run on.  Anded with coremask_override environment
              variable to ensure only working cores are used
numcores    - number of cores to run on.  Runs on specified number of cores, taking into
              account the coremask_override.
skipcores   - only meaningful with numcores.  Skips this many cores (starting from 0) when
              loading the numcores cores. For example, setting skipcores to 1 will skip core 0
              and load the application starting at the next available core.
debug       - if present, bootloader passes debug flag to application which will cause
              the application to stop at a breakpoint on startup
break       - if present, exit program when control-c is received on the console
forceboot   - if set, boots application even if core 0 is not in mask
endbootargs - if set, bootloader does not process any further arguments and only passes
              the arguments that follow to the application.  If not set, the application
              gets the entire commnad line as arguments.
app name    - U-boot has no way of knowing the name of the application so this must be the first argument.


Octeon cust_private_rhino_itus7x(ram)# help bootoctlinux
bootoctlinux - Boot from a linux ELF image in memory

Usage:
bootoctlinux elf_address [coremask=mask_to_run | numcores=core_cnt_to_run] [forceboot] [skipcores=core_cnt_to_skip] [namedblock=name] ]
elf_address - address of ELF image to load. If 0, default load address
              is  used.
coremask    - mask of cores to run on.  Anded with coremask_override
              environment variable to ensure only working cores are used
numcores    - number of cores to run on.  Runs on specified number of cores,
              taking into account the coremask_override.
skipcores   - only meaningful with numcores.  Skips this many cores
              (starting from 0) when loading the numcores cores.
              For example, setting skipcores to 1 will skip core 0
              and load the application starting at the next available core.
forceboot   - if set, boots application even if core 0 is not in mask
namedblock      - specifies a named block to load the kernel
endbootargs - if set, bootloader does not process any further arguments and
              only passes the arguments that follow to the kernel.
              If not set, the kernel gets the entire commnad line as
              arguments.


Octeon cust_private_rhino_itus7x(ram)#
   470976   octboot2.bin 
  1138416   u-boot-octeon_rhino_itus7x.bin 

These the bootloaders..
the ItusxxxxxImage are the ELF-BIN self-contained images.

bin/targets/octeon/generic/openwrt-octeon-itusrouter-initramfs-kernel.bin gets SCP'd/TFTP'd to /dev/mmc1blk1 (which is what the run ls command showed) as one of the three filenames you see: ItusrouterImage ItusgatewayImage ItusbridgeImage, which is then selected depending on the front-panel GPIO switch

Thanks, I have the full picture of the boot process now.

If I understood correctly from the first post, you can build vanilla OpenWrt and it works fine? You just have a problem with fitting the boot process and sysupgrade into OpenWrt?

Yes, I think so. I can build out an master branch build and I've pieced together whatever Itus Networks did originally without really knowing exactly what I'm doing. I had to hack apart the target/linux/generic/other-files/init for a custom init to issue the switch_root. This is how Itus did it, so I copied it and cleaned it up some, but it's only there because that's how they did it back originally. If there is a better way, please show me how.

This device has less than 500 units ever made, I would suspect, so going for "Official" status isn't a priority. I do, however, want to get it working as best I can. I've just recently been able to get opkg working by building out with CONFIG_ALL and then putting the resulting bin/ tree on Github (https://github.com/Grommish/shield_opkgs) so I can pull it.

I'm hoping this makes sense to someone who is outside the chaos I've been swirling around with this build. But, again, please let me re-iterate: Whatever is going on with the build happened because something Itus did put it that way. I do not know if its correct, proper, or the best way to do it, so I came here with this rather ludicrous of trying to prep a device for OpenWrt rather than the other way around :rofl:

I appreciate all everyone has been able to do to help me, and by extension, the users who are going to be using it!

OK, here the thing: with the environment and the commands executed I can see that it's structured similar to RPi (its bootloader also needs kernel on first FAT partition on mmc).
I can explain what you can do to boot new OpenWrt, but I need to know what exactly is the "mmc" on this board? Is it embedded eMMC flash or a removable SD card with standard MBR partition table?

It is embedded eMMC, although it does have an SD Card slot for external loads I suppose, and a Console port (rollover RJ45) so I have kermit, and of course TFTP built into the U-Boot itself. Althought with the three mode slots, I can boot the device enough to get SCP abilities pretty much no matter what.

Here is the form-factor:

Can you try following: remove that patch, write kernel to the first (FAT32) partition with the same name as one of the stock kernels and write rootfs image to partition 2. Then add root=/dev/mmcblk0p2 to the kernel command line and try booting it from flash that way. Create ext4 image and dd it to partition 2, it will be easier that way for now.

I'm not sure what you are asking me to do :flushed:

This is what I get in my bin/target/octeon/generic directory:

total 29580
drwxr-xr-x 3 grommish grommish     4096 Jun 21 12:33 .
drwxr-xr-x 3 grommish grommish     4096 Jun 21 08:40 ..
-rw-r--r-- 1 grommish grommish     2197 Jun 21 15:13 config.buildinfo
-rw-r--r-- 1 grommish grommish      263 Jun 21 15:13 feeds.buildinfo
-rwxr-xr-x 1 grommish grommish 18281240 Jun 21 15:36 openwrt-octeon-itusrouter-initramfs-kernel.bin
-rw-r--r-- 1 grommish grommish     3814 Jun 21 15:36 openwrt-octeon-itusrouter.manifest
-rw-r--r-- 1 grommish grommish 11898880 Jun 21 15:36 openwrt-octeon-itusrouter-squashfs-sysupgrade.tar
drwxr-xr-x 2 grommish grommish    73728 Jun 21 15:35 packages
-rw-r--r-- 1 grommish grommish      579 Jun 21 15:38 sha256sums
-rw-r--r-- 1 grommish grommish       20 Jun 21 15:13 version.buildinfo

The openwrt-octeon-itusrouter-initramfs-kernel.bin file is what gets renamed to ItusxxxxxxImage and loaded onto the FAT partition /dev/mmcblk1p1. There is no separate kernel images, unless you are talking about what is inside the openwrt-octeon-itusrouter-squashfs-sysupgrade.tar

As far as the command line change, I currently have in my target/linux/octeon/image/Makefile:

ITUS_CMDLINE:=console=ttyS0,115200, rootfstype=squashfs,ext4 rootwait

So, I should change it to

ITUS_CMDLINE:=console=ttyS0,115200, rootfstype=squashfs,ext4 rootwait root=/dev/mmcblk1p2

Is this right?

  • Go to menuconfig and in Target Images enable ext4.
  • In target/linux/octeon/image/Makefile set rootfstype to ext4 only.
  • Build new image with make.
  • Extract sysupgrade.tar, there should be two files: non-initramfs kernel and rootfs image.
  • Replace one of ItusxxxxxxImage files with this kernel. Then scp rootfs image to the device and from the console on the device execute this: dd if=/path/to/rootfs.image of=/dev/mmcblk1p2; sync and reboot, don't forget to set the appropriate boot mode.

You should now have a working OpenWrt image on the device.

P.S. Replace the kernel image that actually uses p2 for the rootfs (so you can still use factory images which use other partitions), it should be the "Router" mode according to your first post, and write the rootfs from another boot mode (gateway or switch).

Fantastic! It works. Now I just need to figure out the upgrade system.

It seems instead of passing the root=/dev/mmcblk1px, they were delaying the init until the mmcblk1 came online and then did the switch_root.

This is certainly a much cleaner solution, especially from an upgrade stand point. With a "self-contained" kernel image, I don't have to worry about kmod/lib version mismatches.

What they did, I assume, is that they used kernel with initramfs and then they switch_root into the one on separate partition. This is not very OpenWrt-ish for production image, undo that patch in your tree if you haven't already, take a look at how the RPi is configured and do the same for your board (because RPi also uses MMC, FAT32 partition 1 for kernel and ext4 partition 2 for rootfs).

There might also be someone here who already worked on RPi or another MMC target who could give you more clues, I have worked only with "classical" flash-based OpenWrt boards.

Already done :slight_smile:

Now, I'll have to look at the platform.sh and try and follow the path it takes. I am finally learning how to make subtargets and trying to re-org the octeon tree.

The way this is setup now, upgrading just means replacing the kernel BIN only? Since I created an opkg repo, if an existing user just copies the kernel over to /dev/mmcblk1p1/ItusxxxxxImage, I shouldn't need to do anyting with the root image, correct? Any updates can/should be done via the opkg repo for packages?

No, you must implement writing both writing kernel to FAT32 partition and rootfs to partition 2. Upgrading packages via opkg is not officially supported nor recommended: https://openwrt.org/docs/guide-user/additional-software/opkg

Mass upgrade of all “upgradable” packages is not a good idea, as opkg only indicates that there is a newer version of the package, but does not do any further evaluation. Exceeding the flash space or failing to download all needed upgrades might brick the router.

And here: Updating packages on LEDE with OPKG

Gotcha, but then how do Upgrades work, if I'm dd'ing the root to the /dev and the kernel.bin goes in the FAT partition, where are things saved to - or is this something I'll have to figure out?

Thank you for all the assistance @danijeltudek and the rest of you! I'll close this thread out and work through the rest of the issues/questions in new ones (so they can be easily found).

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.