From patchwork Tue Jan 24 19:18:58 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 6380 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 326A923E0E for ; Tue, 24 Jan 2012 19:19:04 +0000 (UTC) Received: from mail-bk0-f52.google.com (mail-bk0-f52.google.com [209.85.214.52]) by fiordland.canonical.com (Postfix) with ESMTP id 1BDAAA1802E for ; Tue, 24 Jan 2012 19:19:04 +0000 (UTC) Received: by mail-bk0-f52.google.com with SMTP id r19so4464979bka.11 for ; Tue, 24 Jan 2012 11:19:04 -0800 (PST) MIME-Version: 1.0 Received: by 10.205.120.17 with SMTP id fw17mr5495953bkc.74.1327432743876; Tue, 24 Jan 2012 11:19:03 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.204.130.220 with SMTP id u28cs112895bks; Tue, 24 Jan 2012 11:19:03 -0800 (PST) Received: by 10.112.40.200 with SMTP id z8mr3754073lbk.93.1327432742273; Tue, 24 Jan 2012 11:19:02 -0800 (PST) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [81.2.115.146]) by mx.google.com with ESMTPS id nf3si7065694lab.12.2012.01.24.11.19.00 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 24 Jan 2012 11:19:02 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) client-ip=81.2.115.146; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) smtp.mail=pm215@archaic.org.uk Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.72) (envelope-from ) id 1RpltS-00013R-SF; Tue, 24 Jan 2012 19:18:58 +0000 From: Peter Maydell To: android-virt@lists.cs.columbia.edu Cc: patches@linaro.org, Zygmunt Krynicki Subject: [PATCH 2/2] boot-wrapper: Support reading kernel/initrd via semihosting Date: Tue, 24 Jan 2012 19:18:58 +0000 Message-Id: <1327432738-4026-3-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1327432738-4026-1-git-send-email-peter.maydell@linaro.org> References: <1327432738-4026-1-git-send-email-peter.maydell@linaro.org> X-Gm-Message-State: ALoCoQm/spwHrP5g69GfgxH0DyAlsTx8eCcSiC3ULW22uGHkUsbgHvhGqufO9aMeq5fFC4wEQ7iN Implement support in the boot-wrapper for reading our kernel, initrd and command line arguments using the semihosting ABI provided by a Fast Model. We build a second AXF file linux-system-semi.axf which does not depend on or bake in a kernel binary. Instead when you start the model with it you pass the model a parameter like: -C cluster.cpu0.semihosting-cmd_line="--kernel /path/to/uImage --initrd /path/to/initrd -- console=ttyAMA0 mem=512M ..." The boot wrapper will interpret the --kernel and --initrd arguments as taking an option which is a (host system) path, and pass the tail of the string following '--' to the kernel as its command line. Signed-off-by: Peter Maydell --- Makefile | 12 ++- boot.S | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ model.lds.S | 12 ++- 3 files changed, 376 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 54cdbf5..ebcbce5 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ BOOTLOADER = boot.S KERNEL = uImage IMAGE = linux-system.axf +SEMIIMG = linux-system-semi.axf LD_SCRIPT = model.lds.S @@ -27,7 +28,7 @@ LD = $(CROSS_COMPILE)ld # These are needed by the underlying kernel make export CROSS_COMPILE ARCH -all: $(IMAGE) +all: $(IMAGE) $(SEMIIMG) clean: rm -f $(IMAGE) boot.o model.lds monitor.o uImage @@ -38,15 +39,24 @@ $(KERNEL): $(KERNEL_SRC)/arch/arm/boot/uImage $(IMAGE): boot.o monitor.o model.lds $(KERNEL) $(FILESYSTEM) Makefile $(LD) -o $@ --script=model.lds +$(SEMIIMG): bootsemi.o monitor.o modelsemi.lds + $(LD) -o $@ --script=modelsemi.lds + boot.o: $(BOOTLOADER) $(CC) $(CPPFLAGS) -DKCMD='$(KCMD)' -c -o $@ $< +bootsemi.o: $(BOOTLOADER) + $(CC) $(CPPFLAGS) -DSEMIHOSTING=1 -c -o $@ $< + monitor.o: $(MONITOR) $(CC) $(CPPFLAGS) -c -o $@ $< model.lds: $(LD_SCRIPT) Makefile $(CC) $(CPPFLAGS) -E -P -C -o $@ $< +modelsemi.lds: $(LD_SCRIPT) Makefile + $(CC) $(CPPFLAGS) -DSEMIHOSTING=1 -E -P -C -o $@ $< + $(KERNEL_SRC)/arch/arm/boot/uImage: force $(MAKE) -C $(KERNEL_SRC) -j4 uImage diff --git a/boot.S b/boot.S index 4629734..cf8bdb0 100644 --- a/boot.S +++ b/boot.S @@ -11,6 +11,49 @@ .arch_extension sec .text +#ifdef SEMIHOSTING +@ Helper definitions and macros for semihosting +SYS_OPEN = 0x01 +SYS_CLOSE = 0x02 +SYS_WRITE0 = 0x04 +SYS_READ = 0x06 +SYS_FLEN = 0x0C +SYS_GET_CMDLINE = 0x15 +SYS_REPORTEXC = 0x18 + +.macro semihost what + @ Make a semihosting call. Note that on return r0 is always + @ either the return value or is trashed. + mov r0, \what +#if defined(MACH_MPS) + @ M profile semihosting is via bpkt + bkpt 0xab +#elif defined(__thumb__) + @ Otherwise, different SVC numbers for ARM or Thumb mode + svc 0xab +#else + svc 0x123456 +#endif +.endm + +.macro exit + @ Exit via semihosting call + @ REASON_APP_EXIT = 0x20026 + mov r1, 0x20000 + orr r1, r1, 0x26 + semihost SYS_REPORTEXC + @ This point is never reached. +.endm + +.macro fail string + @ Print the message pointed to by string out via semihosting, + @ and then exit. + ldr r1, =\string + semihost SYS_WRITE0 + exit +.endm +#endif + .globl _start _start: #ifdef SMP @@ -114,6 +157,225 @@ _start: orr r1, #0x0001 @ cr str r1, [r0, #0x30] +#ifdef SEMIHOSTING + @ + @ Get kernel, initrd, command line via semihosting + @ + + mov r0, SYS_GET_CMDLINE + ldr r1, =semiblk + ldr r2, =sh_cmdline + str r2, [r1] + @ We have huge amounts of space between us and where we're + @ going to put the kernel, so we can allow for an enormous + @ command line length. + mov r3, 0x2000 + str r3, [r1, #4] + semihost SYS_GET_CMDLINE + cmp r0, 0 + bne 1f + ldr r3, [r1, #4] + cmp r3, 0x2000 + blt 2f +1: + @ Failed to get command line, or truncated + fail get_cmd_failed + +2: + @ That gives us one big NUL terminated string. + @ We expect: + @ --kernel kernelfilename + @ --initrd initrdfilename + @ -- + @ and the remainder of the string is kernel args + + @ r2 is still the command line here +1: + @ Skip any leading whitespace, stop if we hit the end + ldrb r0, [r2] + cmp r0, 32 + bne 2f + add r2, r2, 1 + b 1b +2: + cmp r0, 0 + bne 3f + @ If we hit the end of the string before '--' it's invalid + fail bad_cmd_line +3: + ldr r1, =dashdashkernel + bl matchword + cmp r0, 0 + beq 2f + @ found --kernel, r2 points at next word + @ load at offset -0x40 to allow for uImage header + ldr r1, =kernel + sub r1, r1, 0x40 + bl loadfile + b 1b + +2: + adr r1, dashdashinitrd + bl matchword + cmp r0, 0 + beq 2f + @ found --initrd, r2 points at next word + ldr r1, =filesystem + bl loadfile + @ now r3 is length of the initrd, fix up our ATAGS + ldr r1, =atag_initrd_sz + str r3, [r1] + b 1b + +2: + adr r1, dashdash + bl matchword + cmp r0, 0 + beq 2f + @ found --, r2 points at next word + @ handle rest of string (if any) as kernel args + @ If we didn't have an initrd, write the ATAG_CMDLINE + @ over the top of the ATAG_INITRD2 + ldr r0, =atag_cmdline + ldr r4, [r0, #4] @ ATAG_CMDLINE magic number + ldr r1, =atag_initrd_sz + ldr r1, [r1] + cmp r1, 0 + itt eq + ldreq r0, =atag_initrd + streq r4, [r0, #4] + add r3, r0, #8 + @ copy string from r2 to r3 +1: ldrb r1, [r2],#1 + strb r1, [r3],#1 + cmp r1, 0 + bne 1b + @ zero-pad to word boundary +1: tst r3, #3 + beq 1f + strb r1, [r3],#1 + b 1b +1: @ now write the length word + sub r4, r3, r0 + lsr r4, r4, #2 + str r4, [r0] + @ and terminate the ATAGS list with an ATAG_NONE node + str r1, [r3, #0] + str r1, [r3, #4] + + b run_kernel + +2: + @ unrecognised option + fail bad_cmd_line + +matchword: + @ Subroutine: if the first word (up to space or end) + @ in the string r2 matches the word pointed at by r1 + @ then return with r0 != 0 and r2 pointing at the + @ space/end. Otherwise return with r0 = 0, r2 unchanged. + mov r3, r2 +1: + ldrb r0, [r2] + ldrb r4, [r1] + cmp r4, 0 + beq 1f + cmp r4, r0 + bne matchfail + add r2, r2, 1 + add r1, r1, 1 + b 1b +1: + @ end of matched string, is r2 at end of word? + cmp r0, 32 + itt ne + cmpne r0, 0 + bne matchfail + @ Success + mov r0, 1 + bx lr +1: @ not end of string, match? +matchfail: + mov r2, r3 + mov r0, 0 + bx lr + +loadfile: + @ Subroutine: r2 points to a filename argument (possibly with + @ leading spaces, space or NUL terminated), r1 is the address + @ to load it at. Load the file via semihosting to the + @ specified address. On exit r2 points to the space/NUL + @ after the filename, and r3 is the length of the file in bytes + @ We modify the filename string in place, temporarily + mov r5, r1 + adr r1, loading_str + semihost SYS_WRITE0 + @ skip leading spaces +1: ldrb r0, [r2] + cmp r0, 32 + bne 1f + add r2, r2, 1 + b 1b +1: mov r3, r2 + @ advance until next space or NUL +1: ldrb r0, [r2] + cmp r0, 32 + ite ne + cmpne r0, 0 + beq 1f + add r2, r2, 1 + b 1b +1: @ filename is r3 to r2, save terminating byte and nul terminate + mov r4, r0 + mov r0, 0 + strb r0, [r2] + mov r1, r3 + semihost SYS_WRITE0 + adr r1, colonspace_str + semihost SYS_WRITE0 + adr r1, semiblk + str r3, [r1] @ filename + mov r0, 1 + str r0, [r1, #4] @ file mode: "rb" + subs r0, r2, r3 + bne 1f + fail nofilename +1: str r0, [r1, #8] @ file name length + semihost SYS_OPEN + cmp r0, -1 + bne 1f + fail openfailed +1: @ now we can restore the terminating byte + strb r4, [r2] + mov r4, r0 + str r0, [r1] @ filehandle + semihost SYS_FLEN + cmp r0, -1 + bne 1f + fail flenfailed +1: adr r1, semiblk + mov r3, r0 + str r4, [r1] @ filehandle + str r5, [r1, #4] @ buffer + str r0, [r1, #8] @ length + semihost SYS_READ + cmp r0, 0 + beq 1f + fail readfailed +1: adr r1, semiblk + str r4, [r1] + semihost SYS_CLOSE + cmp r0, 0 + beq 1f + fail closefailed +1: @ Success! r2 is pointing to the space/NUL after the filename, + @ r3 is the length of the file in bytes + adr r1, ok_str + semihost SYS_WRITE0 + bx lr + +#endif +run_kernel: @ @ Kernel parameters @ @@ -133,7 +395,98 @@ _start: #endif mov pc, lr @ jump to the kernel + + @ + @ Data + @ + +#ifdef SEMIHOSTING + .org 0x500 + @ Put the constant pool here as otherwise the assembler will + @ put it immediately after our atags and it will be overwritten + @ by the semihosting command line. + .ltorg + + @ block of four words used to pass/return values in semihosting calls + .align 2 +semiblk: + .long 0,0,0,0 + +dashdashkernel: + .asciz "--kernel" + .align 2 +dashdashinitrd: + .asciz "--initrd" + .align 2 +dashdash: + .asciz "--" + .align 2 + +get_cmd_failed: + .asciz "Failed to get semihosting command line\n" + .align 2 +bad_cmd_line: + .asciz "Bad command line format (unknown option?)\n" + .align 2 +nofilename: + .asciz "Expected filename argument\n" + .align 2 +openfailed: + .asciz "open failed!\n" + .align 2 +flenfailed: + .asciz "could not find length of file!\n" + .align 2 +readfailed: + .asciz "could not read file!\n" + .align 2 +closefailed: + .asciz "could not close file!\n" + .align 2 +loading_str: + .asciz "Loading: " + .align 2 +colonspace_str: + .asciz ": " + .align 2 +ok_str: + .asciz "OK\n" + .align 2 +atags: + @ Template for our ATAGs: we will edit these: the INITRD2 + @ is optional and the CMDLINE will be expanded to include + @ the actual command line. + @ The important thing here is that any editing we do + @ to the template should only make it shorter, so we + @ don't accidentally overwrite the semihosting commandline + @ until the very end when we copy the tail end of the + @ semihosting command line into the ATAG_CMDLINE node + @ as the kernel parameters. + + @ ATAG_CORE + .long 2 + .long 0x54410001 + + @ ATAG_INITRD2 +atag_initrd: + .long 4 + .long 0x54420005 + .long filesystem @ address +atag_initrd_sz: + .long 0 @ size + + @ ATAG_CMDLINE +atag_cmdline: + .long 0 @ length + .long 0x54410009 + @ command line string will start here + +sh_cmdline: + @ Semihosting command line will be written here + +#else /* not SEMIHOSTING */ .org 0x100 + @ Static ATAGS for when kernel/etc are compiled into the ELF file atags: @ ATAG_CORE .long 2 @@ -158,3 +511,5 @@ atags: @ ATAG_NONE .long 0 .long 0x00000000 + +#endif /* not SEMIHOSTING */ diff --git a/model.lds.S b/model.lds.S index 4769480..3af4e07 100644 --- a/model.lds.S +++ b/model.lds.S @@ -13,11 +13,12 @@ TARGET(binary) INPUT(./monitor.o) INPUT(./boot.o) +#ifndef SEMIHOSTING INPUT(./uImage) #ifdef USE_INITRD INPUT(./filesystem.cpio.gz) #endif - +#endif @@ -30,15 +31,22 @@ MON_OFFSET = 0xf0000000; SECTIONS { . = PHYS_OFFSET; + +#ifdef SEMIHOSTING + .text : { bootsemi.o } +#else .text : { boot.o } +#endif . = PHYS_OFFSET + 0x8000 - 0x40; kernel = . + 0x40; +#ifndef SEMIHOSTING .kernel : { ./uImage } +#endif . = PHYS_OFFSET + 0x00800000; filesystem = .; -#ifdef USE_INITRD +#if defined(USE_INITRD) && !defined(SEMIHOSTING) .filesystem : { ./filesystem.cpio.gz } fs_size = . - filesystem; #endif