Running TCP/IP Stack in Linux

With uClinux running on the STM32H7, you get the full Linux TCP/IP stack. Userspace POSIX APIs are provided by the uClibc library. Key user-space networking tools and utilities are available from the multi-call busybox. Additional tools and packages, such as for instance the SSH dropbear server, can be built specifically for uClinux. All in all, you have the powerful Linux TCP/IP stack at your disposal.

There is a full-functioning Ethernet device driver available in the kernel tree for the STM32H7 SOM. The device driver is linux/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c configured in the kernel using the CONFIG_DWMAC_STM32 build time option in Device Drivers -> Network device support -> Ethernet driver support -> STMicroelectronics devices -> STM32 DWMAC support.

image-20240524-124303.png

For the run-time configuration of the kernel, Ethernet is enabled in rootfs.dts.STM32H7 in projects/rootfs as follows:

&mac { status = "okay"; pinctrl-0 = <&ethernet_rmii>; pinctrl-names = "default"; phy-mode = "rmii"; phy-handle = <&phy0>; mdio0 { #address-cells = <1>; #size-cells = <0>; compatible = "snps,dwmac-mdio"; phy0: ethernet-phy@0 { reg = <1>; }; }; };

This will register a platform device for the STM32H7 SOM Ethernet controller with the Ethernet driver.

The Linux project provided by Emcraft in the distribution (refer to projects/rootfs) and installed on each shipping module and kit includes the TCP/IP stack and various network related capabilities. The following snapshot shows the full Linux bootstrap sequence from power-on to the Linux shell:

U-Boot SPL 2019.04- (Jul 07 2023 - 11:10:24 +0000) Hit 's' key to enter spl shell: Trying to boot from SPI U-Boot 2019.04- (Jul 07 2023 - 11:10:24 +0000) Model: STMicroelectronics STM32H7 SOM DRAM: 64 MiB SF: Detected n25q512ax3 with page size 256 Bytes, erase size 4 KiB, total 64 MiB Flash: 128 KiB MMC: STM32 SDMMC2: 0 Loading Environment from UBI... ubi0: default fastmap pool size: 256 ubi0: default fastmap WL pool size: 128 ubi0: attaching mtd2 ubi0: scanning is finished ubi0: attached mtd2 (name "system", size 23 MiB) ubi0: PEB size: 4096 bytes (4 KiB), LEB size: 3968 bytes ubi0: min./max. I/O unit sizes: 1/256, sub-page size 1 ubi0: VID header offset: 64 (aligned 64), data offset: 128 ubi0: good PEBs: 5888, bad PEBs: 0, corrupted PEBs: 0 ubi0: user volume: 5, internal volumes: 1, max. volumes count: 23 ubi0: max/mean erase counter: 2/1, WL threshold: 4096, image sequence number: 0 ubi0: available PEBs: 1067, total reserved PEBs: 4821, PEBs reserved for bad PEB handling: 0 Read 16384 bytes from volume env1 to d396f620 Read 16384 bytes from volume env2 to d3973640 OK In: serial Out: serial Err: serial No size specified -> Using max size (2099072) Read 2099072 bytes from volume splash to d0c00000 Net: eth0: ethernet@40028000 Hit any key to stop autoboot: 0 Booting Image #1 No size specified -> Using max size (8392320) Read 8392320 bytes from volume rtos1 to d0c00000 ## Booting kernel from Legacy Image at d0c00000 ... Image Name: Linux-5.15.67 Image Type: ARM Linux Multi-File Image (uncompressed) Data Size: 6447130 Bytes = 6.1 MiB Load Address: d0008000 Entry Point: d0008001 Contents: Image 0: 6432192 Bytes = 6.1 MiB Image 1: 14926 Bytes = 14.6 KiB Verifying Checksum ... OK ## Loading init Ramdisk from multi component Legacy Image at d0c00000 ... ## Flattened Device Tree from multi component Image at D0C00000 Booting using the fdt at 0xd122260c Loading Multi-File Image ... OK Loading Ramdisk to d3972000, end d3975a4e ... OK Loading Device Tree to d396b000, end d3971a4d ... OK Starting kernel ... [ 0.000000] Booting Linux on physical CPU 0x0 [ 0.000000] Linux version 5.15.67 (sasha@workbench.emcraft.com) (arm-none-eabi-gcc (GNU Arm Embedded Toolchain 10.3-2021.10) 10.3.1 20210824 (release), GNU ld (GNU Arm Embedded Toolchain 10.3-2021.10) 2.36.1.20210621) #2 PREEMPT Fri Jul 7 11:02:11 UTC 2023 [ 0.000000] CPU: ARMv7-M [411fc271] revision 1 (ARMv7M), cr=00000000 [ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, PIPT instruction cache [ 0.000000] OF: fdt: Machine model: STM32H7 SOM Starter Kit [ 0.000000] printk: bootconsole [earlycon0] enabled [ 0.000000] printk: debug: ignoring loglevel setting. [ 0.000000] Reserved memory: created DMA memory pool at 0xd3f00000, size 1 MiB [ 0.000000] OF: reserved mem: initialized node dmapool, compatible id shared-dma-pool [ 0.000000] Zone ranges: [ 0.000000] Normal [mem 0x00000000d0000000-0x00000000d3ffffff] [ 0.000000] Movable zone start for each node [ 0.000000] Early memory node ranges [ 0.000000] node 0: [mem 0x00000000d0000000-0x00000000d3bfffff] [ 0.000000] node 0: [mem 0x00000000d3c00000-0x00000000d3ffffff] [ 0.000000] Initmem setup node 0 [mem 0x00000000d0000000-0x00000000d3ffffff] [ 0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768 [ 0.000000] pcpu-alloc: [0] 0 [ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 16256 [ 0.000000] Kernel command line: console=ttySTM0,115200 earlyprintk consoleblank=0 panic=3 ignore_loglevel ip=172.17.0.66:172.17.0.1::::eth0:off [ 0.000000] Unknown kernel command line parameters "consoleblank=0 ip=172.17.0.66:172.17.0.1::::eth0:off", will be passed to user space. [ 0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes, linear) [ 0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes, linear) [ 0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off [ 0.000000] Memory: 54356K/65536K available (2472K kernel code, 313K rwdata, 1100K rodata, 2240K init, 122K bss, 11180K reserved, 0K cma-reserved) [ 0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1 [ 0.000000] rcu: Preemptible hierarchical RCU implementation. [ 0.000000] rcu: RCU event tracing is enabled. [ 0.000000] Trampoline variant of Tasks RCU enabled. [ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies. [ 0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16 [ 0.000000] /soc/interrupt-controller@58000000: bank0 [ 0.000000] /soc/interrupt-controller@58000000: bank1 [ 0.000000] /soc/interrupt-controller@58000000: bank2 [ 0.000000] clocksource: arm_system_timer: mask: 0xffffff max_cycles: 0xffffff, max_idle_ns: 29863442 ns [ 0.000000] ARM System timer initialized as clocksource [ 0.000012] sched_clock: 32 bits at 200MHz, resolution 5ns, wraps every 10737418237ns [ 0.007939] timer@40000c00: STM32 sched_clock registered [ 0.013294] Switching to timer-based delay loop, resolution 5ns [ 0.019243] timer@40000c00: STM32 delay timer registered [ 0.024598] clocksource: timer@40000c00: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 9556302233 ns [ 0.034508] /soc/timer@40000c00: STM32 clockevent driver initialized (32 bits) [ 0.042665] Calibrating delay loop (skipped), value calculated using timer frequency.. 400.00 BogoMIPS (lpj=2000000) [ 0.053397] pid_max: default: 4096 minimum: 301 [ 0.058758] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear) [ 0.066352] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear) [ 0.082295] rcu: Hierarchical SRCU implementation. [ 0.089681] devtmpfs: initialized [ 0.118466] DMA: default coherent area is set [ 0.122921] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns [ 0.133076] pinctrl core: initialized pinctrl subsystem [ 0.143231] NET: Registered PF_NETLINK/PF_ROUTE protocol family [ 0.180330] stm32h743-pinctrl soc:pin-controller@58020000: GPIOA bank added [ 0.189425] stm32h743-pinctrl soc:pin-controller@58020000: GPIOB bank added [ 0.198466] stm32h743-pinctrl soc:pin-controller@58020000: GPIOC bank added [ 0.207591] stm32h743-pinctrl soc:pin-controller@58020000: GPIOD bank added [ 0.216689] stm32h743-pinctrl soc:pin-controller@58020000: GPIOE bank added [ 0.225964] stm32h743-pinctrl soc:pin-controller@58020000: GPIOF bank added [ 0.235219] stm32h743-pinctrl soc:pin-controller@58020000: GPIOG bank added [ 0.244763] stm32h743-pinctrl soc:pin-controller@58020000: GPIOH bank added [ 0.254189] stm32h743-pinctrl soc:pin-controller@58020000: GPIOI bank added [ 0.263413] stm32h743-pinctrl soc:pin-controller@58020000: GPIOJ bank added [ 0.272836] stm32h743-pinctrl soc:pin-controller@58020000: GPIOK bank added [ 0.279930] stm32h743-pinctrl soc:pin-controller@58020000: Pinctrl STM32 initialized [ 0.322332] stm32-mdma 52000000.dma-controller: STM32 MDMA driver registered [ 0.332046] pps_core: LinuxPPS API ver. 1 registered [ 0.337097] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti < giometti@linux.it> [ 0.346595] PTP clock support registered [ 0.355718] clocksource: Switched to clocksource timer@40000c00 [ 0.370121] NET: Registered PF_INET protocol family [ 0.375946] IP idents hash table entries: 2048 (order: 2, 16384 bytes, linear) [ 0.386209] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 4096 bytes, linear) [ 0.394752] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear) [ 0.403085] TCP established hash table entries: 1024 (order: 0, 4096 bytes, linear) [ 0.411156] TCP bind hash table entries: 1024 (order: 0, 4096 bytes, linear) [ 0.418582] TCP: Hash tables configured (established 1024 bind 1024) [ 0.425522] UDP hash table entries: 256 (order: 0, 4096 bytes, linear) [ 0.432493] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes, linear) [ 0.440671] NET: Registered PF_UNIX/PF_LOCAL protocol family [ 0.456203] workingset: timestamp_bits=30 max_order=14 bucket_order=0 [ 0.523138] io scheduler mq-deadline registered [ 0.535965] io scheduler kyber registered [ 0.557198] STM32 USART driver initialized [ 0.562753] stm32-usart 40011000.serial: interrupt mode for rx (no dma) [ 0.576839] stm32-usart 40011000.serial: interrupt mode for tx (no dma) [ 0.583632] 40011000.serial: ttySTM0 at MMIO 0x40011000 (irq = 30, base_baud = 12500000) is a stm32-usart [ 0.609685] printk: console [ttySTM0] enabled [ 0.609685] printk: console [ttySTM0] enabled [ 0.638237] printk: bootconsole [earlycon0] disabled [ 0.638237] printk: bootconsole [earlycon0] disabled [ 0.667402] stm32-dwmac 40028000.ethernet: IRQ eth_wake_irq not found [ 0.672549] stm32-dwmac 40028000.ethernet: IRQ eth_lpi not found [ 0.696974] stm32-dwmac 40028000.ethernet: PTP uses main clock [ 0.706411] stm32-dwmac 40028000.ethernet: User ID: 0x31, Synopsys ID: 0x42 [ 0.712088] stm32-dwmac 40028000.ethernet: DWMAC4/5 [ 0.737006] stm32-dwmac 40028000.ethernet: DMA HW capability register supported [ 0.742966] stm32-dwmac 40028000.ethernet: RX Checksum Offload Engine supported [ 0.766116] stm32-dwmac 40028000.ethernet: TX Checksum insertion supported [ 0.771656] stm32-dwmac 40028000.ethernet: Wake-Up On Lan supported [ 0.786546] stm32-dwmac 40028000.ethernet: TSO supported [ 0.790569] stm32-dwmac 40028000.ethernet: Enable RX Mitigation via HW Watchdog Timer [ 0.818708] stm32-dwmac 40028000.ethernet: device MAC address b6:9c:51:c9:a2: 3f [ 0.824692] stm32-dwmac 40028000.ethernet: Enabled L3L4 Flow TC (entries=2) [ 0.846095] stm32-dwmac 40028000.ethernet: Enabled RFS Flow TC (entries=8) [ 0.851667] stm32-dwmac 40028000.ethernet: Using 32 bits DMA width [ 1.153156] Unpacking initramfs... [ 1.155275] Initramfs unpacking failed: invalid magic at start of compressed archive [ 1.163609] Freeing initrd memory: 16K [ 1.176665] i2c_dev: i2c /dev entries driver [ 1.182850] mmci-pl18x 52007000.mmc: failed to get pinctrl [ 2.207936] NET: Registered PF_INET6 protocol family [ 2.217643] Segment Routing with IPv6 [ 2.220347] In-situ OAM (IOAM) with IPv6 [ 2.224219] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver [ 2.233229] NET: Registered PF_PACKET protocol family [ 2.251070] Freeing unused kernel image (initmem) memory: 2240K [ 2.255676] This architecture does not have kernel memory protection. [ 2.262220] Run /init as init process [ 2.265995] with arguments: [ 2.268703] /init [ 2.270976] with environment: [ 2.274056] HOME=/ [ 2.276533] TERM=linux [ 2.279125] consoleblank=0 [ 2.282109] ip=172.17.0.66:172.17.0.1::::eth0:off init started: BusyBox v1.24.2 (2023-07-07 11:01:57 UTC) [38] Jan 01 00:00:02 Running in background / # [ 2.527312] stm32-dwmac 40028000.ethernet eth0: PHY [stmmac-0:01] driver [SMSC LAN8710/LAN8720] (irq=POLL) [ 2.536356] stm32-dwmac 40028000.ethernet eth0: Register MEM_TYPE_PAGE_POOL RxQ-0 [ 2.545894] stm32-dwmac 40028000.ethernet eth0: No Safety Features support found [ 2.551950] stm32-dwmac 40028000.ethernet eth0: IEEE 1588-2008 Advanced Timestamp supported [ 2.561350] stm32-dwmac 40028000.ethernet eth0: registered PTP clock [ 2.568913] stm32-dwmac 40028000.ethernet eth0: configuring for phy/rmii link mode [ 4.649596] stm32-dwmac 40028000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx [ 4.657026] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready / #

Let's test the TCP/IP stack on the STM32H7-SOM.

From the development host validate that the STM32H7-SOM is visible using ping:

$ ping -c 5 172.17.0.66 PING 172.17.0.66 (172.17.0.66) 56(84) bytes of data. 64 bytes from 172.17.0.66: icmp_seq=1 ttl=64 time=1.37 ms 64 bytes from 172.17.0.66: icmp_seq=2 ttl=64 time=0.750 ms 64 bytes from 172.17.0.66: icmp_seq=3 ttl=64 time=0.747 ms 64 bytes from 172.17.0.66: icmp_seq=4 ttl=64 time=0.734 ms 64 bytes from 172.17.0.66: icmp_seq=5 ttl=64 time=0.734 ms --- 172.17.0.66 ping statistics --- 5 packets transmitted, 5 received, 0% packet loss, time 4054ms rtt min/avg/max/mdev = 0.734/0.866/1.369/0.251 ms$

ping the development host from the STM32H7 SOM:

On the target, start the telnetd daemon to allow connections to the STM32H7:

Connect to the target from the development host using telnet. The target is configured to accept the 123 password for root:

The dropbear SSH daemon starts automatically on the target. Verify that dropbear allows secure connections to the target:

Connect to the target from the development host using ssh. The first connection takes several seconds to establish as the STM32H7 runs computation-extensive key calculations. Again, enter 123 on the password prompt:

On the target, enable access to the Internet by configuring a default gateway. Note also that the system makes use of the public name server provided by Google:

Use ntpd to synchronize the time on the target with the time provided by a public server:

Use wget to download a file from a remote server:

Mount a directory exported by a development host over NFS:

Start the HTTP daemon:

From a local host, open a Web browser to the STM32H7-SOM and watch the demo web page provided by the target. The STM32H7-SOM shows the current time and date as well as the list of the currently running processes:

image-20240524-124514.png