@@ -153,32 +153,54 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile
153153 endif
154154
155155 # Export for build.rs
156- @@ -74,13 +76,14 @@
156+ @@ -68,19 +70,22 @@
157+ DOCKER_ARG_DEV = --privileged -v /dev:/dev
158+
159+ DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE)
160+ + DOCKER_TEST = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DIR_UTILS) $(DOCKER_IMAGE)
161+ DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE)
162+
163+ # Dockerize commands that require USB device passthrough only on Linux
157164 ifeq ($(UNAME_S),Linux)
158165 DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV)
159166
160167- DOCKER_MINITERM = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_UTILS) $(DOCKER_IMAGE)
161168+ DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_UTILS) $(DOCKER_IMAGE)
162169 endif
163170
164- EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE)
171+ - EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE)
165172- EXEC_MINITERM = ruby ../utils/miniterm.rb
166- + EXEC_MINIPUSH = ruby ../utils/minipush.rb
173+ + EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE)
174+ + EXEC_MINIPUSH = ruby ../utils/minipush.rb
175+ + EXEC_QEMU_MINIPUSH = ruby tests/qemu_minipush.rb
167176
168177- .PHONY: all $(KERNEL_ELF) $(KERNEL_BIN) doc qemu miniterm clippy clean readelf objdump nm check
169178+ .PHONY: all $(KERNEL_ELF) $(KERNEL_BIN) doc qemu qemuasm chainboot clippy clean readelf objdump nm \
170179+ check
171180
172181 all: $(KERNEL_BIN)
173182
174- @@ -102,10 +105,14 @@
183+ @@ -96,16 +101,26 @@
184+ @$(DOC_CMD) --document-private-items --open
185+
186+ ifeq ($(QEMU_MACHINE_TYPE),)
187+ - qemu:
188+ + qemu test:
189+ $(call colorecho, "\n$(QEMU_MISSING_STRING)")
190+ else
175191 qemu: $(KERNEL_BIN)
176192 $(call colorecho, "\nLaunching QEMU")
177193 @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN)
178194+
179195+ qemuasm: $(KERNEL_BIN)
180196+ $(call colorecho, "\nLaunching QEMU with ASM output")
181197+ @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) -d in_asm
198+ +
199+ + test: $(KERNEL_BIN)
200+ + $(call colorecho, "\nTesting chainloading - $(BSP)")
201+ + @$(DOCKER_TEST) $(EXEC_QEMU_MINIPUSH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) \
202+ + -kernel $(KERNEL_BIN) $(CHAINBOOT_DEMO_PAYLOAD)
203+ +
182204 endif
183205
184206- miniterm:
@@ -470,6 +492,93 @@ diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs
470492+ kernel()
471493 }
472494
495+ diff -uNr 05_drivers_gpio_uart/tests/qemu_minipush.rb 06_uart_chainloader/tests/qemu_minipush.rb
496+ --- 05_drivers_gpio_uart/tests/qemu_minipush.rb
497+ +++ 06_uart_chainloader/tests/qemu_minipush.rb
498+ @@ -0,0 +1,82 @@
499+ + # frozen_string_literal: true
500+ +
501+ + # SPDX-License-Identifier: MIT OR Apache-2.0
502+ + #
503+ + # Copyright (c) 2020-2021 Andre Richter <andre.o.richter@gmail.com>
504+ +
505+ + require_relative '../../utils/minipush'
506+ + require 'expect'
507+ + require 'timeout'
508+ +
509+ + # Match for the last print that 'demo_payload_rpiX.img' produces.
510+ + EXPECTED_PRINT = 'Echoing input now'
511+ +
512+ + # The main class
513+ + class QEMUMiniPush < MiniPush
514+ + TIMEOUT_SECS = 3
515+ +
516+ + # override
517+ + def initialize(qemu_cmd, binary_image_path)
518+ + super(nil, binary_image_path)
519+ +
520+ + @qemu_cmd = qemu_cmd
521+ + end
522+ +
523+ + private
524+ +
525+ + def quit_qemu_graceful
526+ + Timeout.timeout(5) do
527+ + pid = @target_serial.pid
528+ + Process.kill('TERM', pid)
529+ + Process.wait(pid)
530+ + end
531+ + end
532+ +
533+ + # override
534+ + def open_serial
535+ + @target_serial = IO.popen(@qemu_cmd, 'r+', err: '/dev/null')
536+ +
537+ + # Ensure all output is immediately flushed to the device.
538+ + @target_serial.sync = true
539+ +
540+ + puts "[#{@name_short}] ✅ Serial connected"
541+ + end
542+ +
543+ + # override
544+ + def terminal
545+ + result = @target_serial.expect(EXPECTED_PRINT, TIMEOUT_SECS)
546+ + exit(1) if result.nil?
547+ +
548+ + puts result
549+ +
550+ + quit_qemu_graceful
551+ + end
552+ +
553+ + public
554+ +
555+ + # override
556+ + def connetion_reset; end
557+ +
558+ + # override
559+ + def handle_reconnect(error)
560+ + handle_unexpected(error)
561+ + end
562+ + end
563+ +
564+ + ##--------------------------------------------------------------------------------------------------
565+ + ## Execution starts here
566+ + ##--------------------------------------------------------------------------------------------------
567+ + puts
568+ + puts 'QEMUMiniPush 1.0'.cyan
569+ + puts
570+ +
571+ + # CTRL + C handler. Only here to suppress Ruby's default exception print.
572+ + trap('INT') do
573+ + # The `ensure` block from `QEMUMiniPush::run` will run after exit, restoring console state.
574+ + exit
575+ + end
576+ +
577+ + binary_image_path = ARGV.pop
578+ + qemu_cmd = ARGV.join(' ')
579+ +
580+ + QEMUMiniPush.new(qemu_cmd, binary_image_path).run
581+
473582diff -uNr 05_drivers_gpio_uart/update.sh 06_uart_chainloader/update.sh
474583--- 05_drivers_gpio_uart/update.sh
475584+++ 06_uart_chainloader/update.sh
0 commit comments