[How-to guide] Installing OpenWrt on Qnap QHora-322

Hello everyone! :slight_smile:

I have successfully managed to install OpenWrt on my Qnap QHora-322 and would like to share a guide on how to do it with the community.

0. Prerequisites

  • PC with some Linux OS (I used a Laptop with Debian 12)
  • USB flash drive
  • USB to TTL adapter
  • JST PH 2.0 4-pin connector with wires
  • RJ45 ethernet cable
  • Phillips 2 screwdriver

1. Open the case

Remove all 7 Phillips 2 screws on the underside of the case. There are 4 screws hidden under each rubber foot and 1 under the “warranty void if removed”-sticker.

2. Establish a connection to the serial console

Find the serial console 4-pin socket, named “DBG_CONSOLE”. It is located next to the buzzer.

Plug the JST PH 2.0 4-pin connector into the socket and connect the other ends of the wires to the USB to TTL adapter as follows:

  • Pin 1 ----> RX
  • Pin 2 --/--> 3.3 V - Do not connect!
  • Pin 3 ----> TX
  • Pin 4 ----> Ground

Note: Pin 1 is the pin closest to the buzzer, pin 4 is the pin furthest away from the buzzer.

On your PC running Linux, open a terminal and enter the following command:

ls /dev/

Plug the USB to TTL adapter into your PC and execute the command above again to see if a new device appears. For me it was /dev/ttyUSB0.

Enter the following command as root to connect to the serial console:

screen -L /dev/ttyUSB0 115200

Power up the Qnap QHora-322. You should see some output on your screen, that looks something like this:

BootROM - 2.03

Starting CP-0 IOROM 1.07

Booting from SPI NOR flash 1 (0x32)

Found valid image at boot postion 0x000

lNOTICE:  Starting binary extension
NOTICE:  SVC: DEV ID: CN913x, FREQ Mode: 0x6
NOTICE:  SVC: AVS work point changed from 0x2da to 0x2da
mv_ddr: Marvell-devel (release) (Jun 08 2022 - 17:52:54)
SSCG_EN
Synopsys DDR43 PHY Firmware version: A-2017.11
SNPS DDR: 1D training passed
SNPS DDR: 2D training passed
SNPS DDR: training completed
dma memcmp pass
mv_ddr: completed successfully
NOTICE:  Cold boot
[...]

If your output is completely garbled, then try swapping the RX and TX pins. If your output is partially garbled, then verify the wires are firmly connected.

When you reach the line "Hit any key to stop autoboot:", then press the enter key on your keyboard a couple of times to prevent the OS from booting. You will know that it worked, when your prompt looks like this:

Marvell>> 

3. Install and prepare a TFTP server

On your PC, open a new terminal and execute the following commands as root, to install a tftp-server:

apt update

apt install tftpd-hpa

Go to https://downloads.openwrt.org/releases/22.03.5/targets/mvebu/cortexa72/ (Replace “22.03.5” with your desired OpenWrt version) and download the iei_puzzle-m902-initramfs-kernel.bin file. Move the file into your TFTP server directory by executing the following commands as root:

cd $your_download_directory

cp openwrt-*-mvebu-cortexa72-iei_puzzle-m902-initramfs-kernel.bin /srv/tftp/.

Connect your PC to RJ45 port number 2 of your Qnap QHora-322 and change the IP address of your PC’s ethernet interface to 192.168.1.2 (netmask 255.255.255.0).

In the serial console enter the following commands:

setenv ipaddr 192.168.1.1

setenv serverip 192.168.1.2

setenv ethact mvpp2-1

ping 192.168.1.2

The last command should give you the following output:

Using mvpp2-1 device
host 192.168.1.2 is alive

4. Boot OpenWrt via tftp

In the serial console enter the following command:

tftpboot 0x6500000 openwrt-22.03.5-mvebu-cortexa72-iei_puzzle-m902-initramfs-kernel.bin

(Replace 22.03.5 with the OpenWrt version you downloaded.)

This should give you the following output:

Using mvpp2-1 device
TFTP from server 192.168.1.2; our IP address is 192.168.1.1
Filename 'openwrt-22.03.5-mvebu-cortexa72-iei_puzzle-m902-initramfs-kernel.bin'.
Load address: 0x6500000
Loading: *#################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 ###############################################
	 3 MiB/s
done
Bytes transferred = 22626312 (1594008 hex)

Now enter the following commands to boot OpenWrt:

ext4load mmc 0:2 0x6000000 cn9132-db-A.dtb

booti 0x6500000 - 0x6000000

The output after the last command should look something like this:

## Flattened Device Tree blob at 06000000
   Booting using the fdt blob at 0x6000000
   Using Device Tree in place at 0000000006000000, end 000000000600db4e

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd083]
[    0.000000] Linux version 5.10.176 (builder@buildhost) (aarch64-openwrt-linux-musl-gcc (OpenWrt GCC 11.2.0 r20134-5f15225c1e) 11.2.0, GNU ld (GNU Binutils) 2.37) #0 SMP Thu Apr 27 20:28:15 2023
[    0.000000] Machine model: QHora-322
[    0.000000] Zone ranges:
[    0.000000]   DMA      [mem 0x0000000000000000-0x00000000ffffffff]
[    0.000000]   DMA32    empty
[    0.000000]   Normal   [mem 0x0000000100000000-0x000000013fffffff]
[    0.000000] Movable zone start for each node
[...]

When the boot process is finished, you need to press the enter key to activate the console. When you press the enter key, you should get the following output:

BusyBox v1.35.0 (2023-04-27 20:28:15 UTC) built-in shell (ash)

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 OpenWrt 22.03.5, r20134-5f15225c1e
 -----------------------------------------------------
=== WARNING! =====================================
There is no root password defined on this device!
Use the "passwd" command to set up a new password
in order to prevent unauthorized SSH logins.
--------------------------------------------------
root@OpenWrt:/# 

5. Download, extract and write OpenWrt to persistent storage

Go to https://downloads.openwrt.org/releases/22.03.5/targets/mvebu/cortexa72/ (Replace “22.03.5” with your desired OpenWrt version) and download the iei_puzzle-m902-squashfs-sdcard.img.gz file.

Extract the kernel and the root filesystem from the image by executing the following commands on your PC as root:

gzip -d openwrt-*-mvebu-cortexa72-iei_puzzle-m902-squashfs-sdcard.img.gz

newloop=$(losetup -f)

losetup -P $newloop openwrt-*-mvebu-cortexa72-iei_puzzle-m902-squashfs-sdcard.img

dd if=${newloop}p1 of=0.img

dd if=${newloop}p2 of=1.img

losetup -d $newloop

This should put two additional files in your download directory:

  • 0.img (This is the kernel)
  • 1.img (This is the root filesystem)

Format a USB flash drive with the F2FS file system and copy the two files (0.img and 1.img) onto it.

Unplug the USB flash drive from your PC and plug it into the Qnap QHora-322. On the serial console you should see that OpenWrt detected the USB flash drive:

[ 1428.007066] usb 2-1: new SuperSpeed Gen 1 USB device number 3 using xhci-hcd
[ 1428.037697] usb-storage 2-1:1.0: USB Mass Storage device detected
[ 1428.043944] scsi host0: usb-storage 2-1:1.0
[ 1429.127231] scsi 0:0:0:0: Direct-Access     Kingston DT HyperX 3.0    PMAP PQ: 0 ANSI: 6
[ 1429.135713] sd 0:0:0:0: [sda] 123600896 512-byte logical blocks: (63.3 GB/58.9 GiB)
[ 1429.143497] sd 0:0:0:0: [sda] Write Protect is off
[ 1429.148422] sd 0:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
[ 1429.365915]  sda: sda1
[ 1429.368773] sd 0:0:0:0: [sda] Attached SCSI removable disk

Mount the USB flash-drive’s F2FS partition by executing the following commands on the serial console:

mkdir /mnt/USB

mount /dev/sda1 /mnt/USB/

cd /mnt/USB/

Write the images to persistent storage by executing the following commands:

dd if=0.img of=/dev/mmcblk0p1

dd if=1.img of=/dev/mmcblk0p3

6. Adjust bootloader to autoboot OpenWrt

Reboot the router by executing the reboot command in the serial console.

When you reach the line "Hit any key to stop autoboot:", then press the enter key on your keyboard a couple of times to prevent the OS from booting. You will know that it worked, when your prompt looks like this:

Marvell>> 

Enter the following commands to change the behavior of the bootloader:

setenv bootcmd 'ext4load mmc 0:1 0x6500000 Image; ext4load mmc 0:1 0x6000000 cn9132-puzzle-m902.dtb; setenv bootargs $console cpuidle.off=1 root=/dev/mmcblk0p3; booti 0x6500000 - 0x6000000'

setenv current_entry 0

saveenv

The last command should give you the following output:

Saving Environment to SPI Flash... SF: Detected mx25l3205d with page size 256 Bytes, erase size 4 KiB, total 4 MiB
Erasing SPI flash...Writing to SPI flash...done
OK

Unplug the Qnap QHora-322 from the power source and plug it back in to check, if OpenWrt is booting automatically.

Done!

If you have any questions, suggestions or corrections, please let me know.

Have a great day! :slight_smile:

2 Likes

Is this your device's firmware, or is this for some other device and you managed to get it working successfully?

The Qnap QHora-322 is a re-branded IEI Puzzle-M902. The only difference is that the IEI Puzzle-M902 already comes with OpenWrt pre-installed, but the Qnap QHora-322 comes with QuRouter-OS. So if one wants to install OpenWrt on it, the files from the IEI Puzzle-M902 can be used. :slight_smile:

Edit: The firmware-upgrade functionality of QuRouter-OS does not allow the installation of OpenWrt, so the installation needs to be done "manually".

1 Like

Overall, the specs of this device are (compared to most other devices on the TOH) really impressive in my opinion:

  • quad-core ARM CPU with 2.2 GHz
  • 4 GB RAM
  • 4 GB Storage
  • 3x 10 Gbit/s and 6x 2.5 Gbit/s interfaces

I have yet to benchmark it though, to see if the CPU is powerful enough to actually route these bandwidths. (Need to buy a 10 Gbit/s network card first lol :smiley:)

I will post updates here as soon as I have done so.

Giving this a try in the near future. Could you please write up the reverse procedure for returning to stock firmware? Thank you in advance!

I personally do not intend to revert back to the stock OS, but if you want to do it, you can follow this guide here: Reinstall stock firmware on qhora-322 - Installing and Using OpenWrt - OpenWrt Forum. Looks pretty good to me. :slight_smile:

If you want to save yourself some hassle though (Edit: So you do not have to decrypt the stock firmware file), you can backup the two partitions to your USB flash drive, before executing the last two commands in section 5 of my guide. After mounting the USB flash drive, do this:

dd if=/dev/mmcblk0p1 of=/mnt/USB/mmcblk0p1_stock.img

dd if=/dev/mmcblk0p3 of=/mnt/USB/mmcblk0p3_stock.img

Once the backup is finished, proceed with writing OpenWrt:

dd if=0.img of=/dev/mmcblk0p1

dd if=1.img of=/dev/mmcblk0p3

Have a nice day! :slight_smile:

What's the price of this device?

Thank you JuliusZet! Not planning to return to routeros either. But having the option is nice incase something goes wrong.

1 Like

I bought mine for ~ 560 €, but I would recommend you look up the price yourself as it will most likely vary from region to region.


Success!


Speeds are looking decent after bumping the MTU to 9000

Question:

  • A while ago I remember reading something about this unit running hot and requiring the fan speed to be tuned. Is that still the case?

Thanks again to JuliusZet! Specifically bought this router with OpenWRT in mind. I was just waiting for this guide and others to take the leap.

1 Like

I was not able to test it yet, but just in case I have added this to my /etc/rc.local file:

echo "255" > /sys/class/hwmon/hwmon6/pwm1

It will set the fan speed to 100 % on startup, which is quite loud, but I do not care since my QHora-322 is in a 19" rack in another room. :wink:

Could it be that the fan is generally very loud?
I can already hear it very clearly at 127-159 and it seems to be rattling a bit

Ok can someone please explain the upgrade procedure to me?

Assuming I want to upgrade to the snapshot version or to the upcoming release 23.05.3 - how exactly do I do this with which file?

It seems that some people have already bricked their router with the wrong file:

Hi @loaNga0m,

I can confirm the fan becomes audible when the speed is increased to higher than ~ 50 %, but I do not hear any rattling noises. My fan speed is set to 100 % for almost 6 months now.

If you followed my guide in the very first post in this tread, it should be as easy as just using OpenWRT's built-in firmware-upgrade-functionality to upgrade. Just be sure to use the EXT4 version from the firmware selector: https://firmware-selector.openwrt.org/?target=mvebu%2Fcortexa72&id=iei_puzzle-m902
I have upgraded from 22.03.5 to 23.05.0 and from 23.05.0 to 23.05.2 like this and it worked flawlessly. :slight_smile:

Does this answer your question?

1 Like

Thank you very much!

I have already replaced the fan, the original one seems to have had a small bearing damage.
The new one doesn't rattle!

Thank you very much.
For the upgrade information.
So can I simply flash the ext4-sdcard.img.gz via LuCI?

I was a bit confused because you use the squashfs-sdcard.img.gz in the instructions and I now have this on the router.

[3.625081] VFS: Mounted root (squashfs filesystem) readonly on device 179:3.

Therefore I would have assumed that I have to use the squashfs-sdcard.img.
But some people seem to have already broken the router with this one.

So i just flash ext4-sdcard.img.gz and the bootcmd in uboot doesn't need to be changed?

Sorry for all the questions but I'd rather ask before I turn the rather expensive router into a paperweight.

Thanks again for the instructions!

In fact it does not really matter if you use the ext4 or the squashfs one. Just do not use the kernel.bin file. :smiley:

You can also flash an ext4 image over a squashfs installation no problem. I did the same after learning that ext4 is better. Just be aware that ext4 uses up a bit more space than squashfs (--> it does not matter for us :smiley:). I also did not need to change the bootcmd in uboot.

If something breaks, keep in mind that, as long as the bootloader is still in tact, you can always re-flash the device via serial. :slight_smile:

Have a great day! :slight_smile:

1 Like

Hello there

I have finally found some time (and spent way too much money :stuck_out_tongue_winking_eye:) to upgrade the rest of my networking equipment to 10G and configure the Qnap QHora-322 as my new main router. I am extremely happy with it.

Here some tips, that I think might be useful for (future) owners of the device.

1. Interface names

The physical ethernet interfaces of the device do not show up in chronological order in OpenWrt. (You might recognize a pattern though.)

  • eth0 = 10G port 1
  • eth1 = 2.5G port 2
  • eth2 = 2.5G port 1
  • eth3 = 10G port 2
  • eth4 = 2.5G port 4
  • eth5 = 2.5G port 3
  • eth6 = 10G port 3
  • eth7 = 2.5G port 6
  • eth8 = 2.5G port 5

2. Enable jumbo frames

In order to utilize the full bandwidth of 10 Gbit/s, you should think about enabling jumbo-frames. At least for the 10G interfaces.

According to my tests, with the default MTU size of 1500 the maximum routable bandwidth is between 5 and 6 Gbit/s and is being limited by the performance of a single core. (One core was always at 100 % during file transfer.)

But with an MTU size of 9000 the device is able to route traffic at 10 Gbit/s whilst the CPU usage of one core is only around 50 %.

To enable jumbo frames on the 10G ports, add these options to your /etc/config/network:

config globals 'globals'
        option packet_steering '1'

config device
        option name 'eth0'
        option mtu '9000'
        option mtu6 '9000'

config device
        option name 'eth3'
        option mtu '9000'
        option mtu6 '9000'

config device
        option name 'eth6'
        option mtu '9000'
        option mtu6 '9000'

You need to ensure though, that all devices, that are on the same data-link-layer as this interface, are able to handle jumbo-frames. Otherwise, you will run into all kinds of funny issues.

3. Partition layout (if someone is interested)

Device            Start      End  Sectors  Size  Name
/dev/mmcblk0p1       34   131105   131072   64M  kernel_1
/dev/mmcblk0p2   131106   262177   131072   64M  kernel_2
/dev/mmcblk0p3   262178  1310753  1048576  512M  rootfs_1
/dev/mmcblk0p4  1310754  2359329  1048576  512M  rootfs_2
/dev/mmcblk0p5  2359330  3407905  1048576  512M  sys_log
/dev/mmcblk0p6  3407906  3538977   131072   64M  reserved
/dev/mmcblk0p7  3538978  7372833  3833856  1.8G  rootfs_data

And that's it for now. :smiley:

If you have any questions, please let me know.

Have a nice day! :slight_smile:

I have activated "packet steering", which has a positive effect on benchmarks with multiple streams.

Oh yeah I should have mentioned that I was testing with

network.globals.packet_steering='1'

That was one of the first settings I have changed :smiley: and I have never tested with this setting disabled.