0

I'm emulating a Cortex-M33 using QEMU on a linux host. I've installed QEMU using sudo apt-get qemu-system-arm and semihosting is working fine (printf and file IO).

I'm calling QEMU as follows:

/usr/bin/qemu-system-arm -machine mps2-an505 -cpu cortex-m33 -m 16M -nographic --semihosting-config enable=on,target=native -kernel build/ARMCM33/kernel.elf -S -s

Now however I am building QEMU from source. Build steps:

  1. git clone https://gitlab.com/qemu-project/qemu.git
  2. Navigate to the cloned repo
  3. ./configure --target-list=arm-softmmu,arm-linux-user, from here
  4. make

I can see the executable here: qemu/build/qemu-system-arm, however when I run

<path to repo>qemu/build/qemu-system-arm -machine mps2-an505 -cpu cortex-m33 -m 16M -nographic --semihosting-config enable=on,target=native -kernel build/ARMCM33/kernel.elf -S -s

the semihosting no longer works (the program no longer prints to the console).

I've looked through configure --help but cannot see anything obvious. Is there something I've missed?

Edit:

I think I now have a minimal example (kubuntu jammy)

  • CMSIS tag v5.6.0
  • QEMU v7.2.0 (built locally)

File: microbit.s:

                                .cpu    cortex-m33
                                .code   16
                                .equ    SYS_WRITE0 , 0x04
                                .equ     angel_SWIreason_ReportException, 0x18
                                .global  _start
_start:                          mov r0, #SYS_WRITE0
                                ldr     r1,=hello
                                bkpt    0xab
                                mov     r0, #angel_SWIreason_ReportException
                                ldr     r1,=ADP_Stopped_ApplicationExit
                                bkpt    0xab

                               .balign  4
hello:                          .asciz   "Hello, World!\n"
ADP_Stopped_ApplicationExit:    .word    0x20026
                               .end

gcc_arm.ld (taken from CMSIS_5/Device/ARM/ARMCM33/Source/GCC where the memory regions have been updated according to the an505):

/******************************************************************************
 * @file     gcc_arm.ld
 * @brief    GNU Linker Script for Cortex-M based device
 * @version  V2.2.0
 * @date     16. December 2020
 ******************************************************************************/
/*
 * Copyright (c) 2009-2020 Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 *-------- <<< Use Configuration Wizard in Context Menu >>> -------------------
 */

/*---------------------- Flash Configuration ----------------------------------
  <h> Flash Configuration
    <o0> Flash Base Address <0x0-0xFFFFFFFF:8>
    <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>
  </h>
  -----------------------------------------------------------------------------*/
/* See https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwiY67e2meD8AhUKQ0EAHSwmBSIQFnoECCAQAQ&url=https%3A%2F%2Fdocumentation-service.arm.com%2Fstatic%2F5ed11469ca06a95ce53f8ed7%3Ftoken%3D&usg=AOvVaw0o2b4qMG6MiKjhd_STNKqR
*/
__ROM_BASE = 0x10000000;
__ROM_SIZE = 512K;

/*--------------------- Embedded RAM Configuration ----------------------------
  <h> RAM Configuration
    <o0> RAM Base Address    <0x0-0xFFFFFFFF:8>
    <o1> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
  </h>
 -----------------------------------------------------------------------------*/
/* See https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwiY67e2meD8AhUKQ0EAHSwmBSIQFnoECCAQAQ&url=https%3A%2F%2Fdocumentation-service.arm.com%2Fstatic%2F5ed11469ca06a95ce53f8ed7%3Ftoken%3D&usg=AOvVaw0o2b4qMG6MiKjhd_STNKqR
*/
__RAM_BASE = 0x38000000;
__RAM_SIZE = 2048K;

/*--------------------- Stack / Heap Configuration ----------------------------
  <h> Stack / Heap Configuration
    <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
    <o1> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
  </h>
  -----------------------------------------------------------------------------*/
__STACK_SIZE = 0x00100000;
__HEAP_SIZE  = 0x00000100;

/*
 *-------------------- <<< end of configuration section >>> -------------------
 */

MEMORY
{
  FLASH (rx)  : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE
  RAM   (rwx) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE
}

/* Linker script to place sections and symbol values. Should be used together
 * with other linker script that defines memory regions FLASH and RAM.
 * It references following symbols, which must be defined in code:
 *   Reset_Handler : Entry of reset handler
 *
 * It defines following symbols, which code can use without definition:
 *   __exidx_start
 *   __exidx_end
 *   __copy_table_start__
 *   __copy_table_end__
 *   __zero_table_start__
 *   __zero_table_end__
 *   __etext
 *   __data_start__
 *   __preinit_array_start
 *   __preinit_array_end
 *   __init_array_start
 *   __init_array_end
 *   __fini_array_start
 *   __fini_array_end
 *   __data_end__
 *   __bss_start__
 *   __bss_end__
 *   __end__
 *   end
 *   __HeapLimit
 *   __StackLimit
 *   __StackTop
 *   __stack
 */
ENTRY(Reset_Handler)

SECTIONS
{
  .text :
  {
    KEEP(*(.vectors))
    *(.text*)

    KEEP(*(.init))
    KEEP(*(.fini))

    /* .ctors */
    *crtbegin.o(.ctors)
    *crtbegin?.o(.ctors)
    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
    *(SORT(.ctors.*))
    *(.ctors)

    /* .dtors */
    *crtbegin.o(.dtors)
    *crtbegin?.o(.dtors)
    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
    *(SORT(.dtors.*))
    *(.dtors)

    *(.rodata*)

    KEEP(*(.eh_frame*))
  } > FLASH

  /*
   * SG veneers:
   * All SG veneers are placed in the special output section .gnu.sgstubs. Its start address
   * must be set, either with the command line option --section-start or in a linker script,
   * to indicate where to place these veneers in memory.
   */
/*
  .gnu.sgstubs :
  {
    . = ALIGN(32);
  } > FLASH
*/
  .ARM.extab :
  {
    *(.ARM.extab* .gnu.linkonce.armextab.*)
  } > FLASH

  __exidx_start = .;
  .ARM.exidx :
  {
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
  } > FLASH
  __exidx_end = .;

  .copy.table :
  {
    . = ALIGN(4);
    __copy_table_start__ = .;
    LONG (__etext)
    LONG (__data_start__)
    LONG (__data_end__ - __data_start__)
    /* Add each additional data section here */
/*
    LONG (__etext2)
    LONG (__data2_start__)
    LONG (__data2_end__ - __data2_start__)
*/
    __copy_table_end__ = .;
  } > FLASH

  .zero.table :
  {
    . = ALIGN(4);
    __zero_table_start__ = .;
    /* Add each additional bss section here */
/*
    LONG (__bss2_start__)
    LONG (__bss2_end__ - __bss2_start__)
*/
    __zero_table_end__ = .;
  } > FLASH

  /**
   * Location counter can end up 2byte aligned with narrow Thumb code but
   * __etext is assumed by startup code to be the LMA of a section in RAM
   * which must be 4byte aligned 
   */
  __etext = ALIGN (4);

  .data : AT (__etext)
  {
    __data_start__ = .;
    *(vtable)
    *(.data)
    *(.data.*)

    . = ALIGN(4);
    /* preinit data */
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP(*(.preinit_array))
    PROVIDE_HIDDEN (__preinit_array_end = .);

    . = ALIGN(4);
    /* init data */
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP(*(SORT(.init_array.*)))
    KEEP(*(.init_array))
    PROVIDE_HIDDEN (__init_array_end = .);


    . = ALIGN(4);
    /* finit data */
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP(*(SORT(.fini_array.*)))
    KEEP(*(.fini_array))
    PROVIDE_HIDDEN (__fini_array_end = .);

    KEEP(*(.jcr*))
    . = ALIGN(4);
    /* All data end */
    __data_end__ = .;

  } > RAM

  /*
   * Secondary data section, optional
   *
   * Remember to add each additional data section
   * to the .copy.table above to asure proper
   * initialization during startup.
   */
/*
  __etext2 = ALIGN (4);

  .data2 : AT (__etext2)
  {
    . = ALIGN(4);
    __data2_start__ = .;
    *(.data2)
    *(.data2.*)
    . = ALIGN(4);
    __data2_end__ = .;

  } > RAM2
*/

  .bss :
  {
    . = ALIGN(4);
    __bss_start__ = .;
    *(.bss)
    *(.bss.*)
    *(COMMON)
    . = ALIGN(4);
    __bss_end__ = .;
  } > RAM AT > RAM

  /*
   * Secondary bss section, optional
   *
   * Remember to add each additional bss section
   * to the .zero.table above to asure proper
   * initialization during startup.
   */
/*
  .bss2 :
  {
    . = ALIGN(4);
    __bss2_start__ = .;
    *(.bss2)
    *(.bss2.*)
    . = ALIGN(4);
    __bss2_end__ = .;
  } > RAM2 AT > RAM2
*/

  .heap (COPY) :
  {
    . = ALIGN(8);
    __end__ = .;
    PROVIDE(end = .);
    . = . + __HEAP_SIZE;
    . = ALIGN(8);
    __HeapLimit = .;
  } > RAM

  .stack (ORIGIN(RAM) + LENGTH(RAM) - __STACK_SIZE) (COPY) :
  {
    . = ALIGN(8);
    __StackLimit = .;
    . = . + __STACK_SIZE;
    . = ALIGN(8);
    __StackTop = .;
  } > RAM
  PROVIDE(__stack = __StackTop);

  /* Check if data + heap + stack exceeds RAM limit */
  ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
}


Building:

gcc-arm-none-eabi-9-2020-q2-update/bin/arm-none-eabi-gcc -O0 -ggdb -mthumb -mcpu=cortex-m33 -nostartfiles -ffreestanding --specs=rdimon.specs -DARMCM33_DSP_FP -I<PATH_TO_CMSIS_5>/CMSIS/Core/Include -I<PATH_TO_CMSIS_5>/Device/ARM/ARMCM33/Include -L. -Wl,-T,gcc_arm.ld -o cortex_m33.elf <PATH_TO_CMSIS_5>/Device/ARM/ARMCM33/Source/GCC/startup_ARMCM33.S <PATH_TO_CMSIS_5>/Device/ARM/ARMCM33/Source/system_ARMCM33.c microbit.s

where I had to add the --specs=rdimon.specs and -DARMCM33_DSP_FP flags to get CMSIS to compile.

Another note is that gcc gives errors if I use -mtune=cortex-m33:

conflicting CPU architectures 17/2

Start system installed qemu:

qemu-system-arm  --semihosting-config enable=on,target=native -m 16M -nographic -cpu cortex-m33 -machine mps2-an505 -kernel cortex_m33.elf
Hello, World!

Local build:

Documents/qemu/build/qemu-system-arm  --semihosting-config enable=on,target=native -m 16M -nographic -cpu cortex-m33 -machine mps2-an505 -kernel cortex_m33.elf

where there is no output.

cberk1
  • 35
  • 6
  • That ought in theory to be working. You could have a look at the debug logs or use the gdbstub to see what's actually happening to your program (e.g. is it just crashing for some non-semihosting-related-reason on the new QEMU, or is it actually making the semihosting syscalls but QEMU is ignoring them?) – Peter Maydell Feb 02 '23 at 16:55
  • Hi Peter, thanks for the reply. GDB is working perfectly with the apt-get installation. Looking closer, GDB is struggling with the built-from-source executable - my local variables report 'No symbol "" in current context'. I'm using exactly the same cmd line commands with the executable switched out. – cberk1 Feb 03 '23 at 10:29
  • For clarity, I meant "use a guest-architecture gdb talking to QEMU's gdbstub to debug the guest binary", not "use a host-architecture gdb to debug QEMU itself". – Peter Maydell Feb 04 '23 at 15:10

1 Answers1

0

This is difficult to say if you missed something because we don't have all the source code and the linker script you are using.

I therefore cannot answer your specific question, but here is a procedure that worked for me on debian bullseye, ubuntu focal and ubuntu jammy for building qemu-system-arm 7.2.0.

But the first step would be to make sure you are using version v7.2.0, that is revision b67b00e6b4 of the source code. You did not mention the extra git command required for getting this revision, it would be step 1.1):

git checkout v7.2.0
Note: switching to 'v7.2.0'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at b67b00e6b4 Update VERSION for v7.2.0

Retrieving/building qemu (using wget):

cd /tmp
wget https://download.qemu.org/qemu-7.2.0.tar.xz
tar Jxf qemu-7.2.0.tar.xz
mkdir qemu
cd qemu
../qemu-7.2.0/configure --target-list=arm-softmmu,arm-linux-user --prefix=/tmp/qemu --extra-cflags=-I/tmp/qemu-7.2.0/packages/include --extra-ldflags=-L/tmp/qemu-7.2.0/packages/lib --enable-slirp
make install 

microbit.s, a minimal semihosting program for the microbit machine:

                                 .cpu    cortex-m0
                                 .code   16
                                 .equ    SYS_WRITE0 , 0x04
                                 .equ     angel_SWIreason_ReportException, 0x18
                                 .global  _start
_start:                          mov r0, #SYS_WRITE0
                                 ldr     r1,=hello
                                 bkpt    0xab 
                                 mov     r0, #angel_SWIreason_ReportException    
                                 ldr     r1,=ADP_Stopped_ApplicationExit
                                 bkpt    0xab 

                                .balign  4
hello:                          .asciz   "Hello, World!\n"
ADP_Stopped_ApplicationExit:    .word    0x20026
                                .end

microbit.ld:

/*
 *-------- <<< Use Configuration Wizard in Context Menu >>> -------------------
 */

/*---------------------- Flash Configuration ----------------------------------
  <h> Flash Configuration
    <o0> Flash Base Address <0x0-0xFFFFFFFF:8>
    <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>
  </h>
  -----------------------------------------------------------------------------*/
__ROM_BASE = 0x00000000;
__ROM_SIZE = 0x00020000;

/*--------------------- Embedded RAM Configuration ----------------------------
  <h> RAM Configuration
    <o0> RAM Base Address    <0x0-0xFFFFFFFF:8>
    <o1> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
  </h>
 -----------------------------------------------------------------------------*/
__RAM_BASE = 0x20000000;
__RAM_SIZE = 0x00004000;

/*--------------------- Stack / Heap Configuration ----------------------------
  <h> Stack / Heap Configuration
    <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
    <o1> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
  </h>
  -----------------------------------------------------------------------------*/
__STACK_SIZE = 0x00000400;
__HEAP_SIZE  = 0x00000C00;

/*
 *-------------------- <<< end of configuration section >>> -------------------
 */

INCLUDE gcc_arm32.ld

gcc_arm32.ld:

/******************************************************************************
 * @file     gcc_arm32.ld
 * @brief    GNU Linker Script for Cortex-M based device
 * @version  V2.0.0
 * @date     21. May 2019
 ******************************************************************************/
/*
 * Copyright (c) 2009-2019 Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

MEMORY
{
  FLASH (rx)  : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE
  RAM   (rwx) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE
}

/* Linker script to place sections and symbol values. Should be used together
 * with other linker script that defines memory regions FLASH and RAM.
 * It references following symbols, which must be defined in code:
 *   Reset_Handler : Entry of reset handler
 *
 * It defines following symbols, which code can use without definition:
 *   __exidx_start
 *   __exidx_end
 *   __copy_table_start__
 *   __copy_table_end__
 *   __zero_table_start__
 *   __zero_table_end__
 *   __etext
 *   __data_start__
 *   __preinit_array_start
 *   __preinit_array_end
 *   __init_array_start
 *   __init_array_end
 *   __fini_array_start
 *   __fini_array_end
 *   __data_end__
 *   __bss_start__
 *   __bss_end__
 *   __end__
 *   end
 *   __HeapLimit
 *   __StackLimit
 *   __StackTop
 *   __stack
 */
ENTRY(Reset_Handler)

SECTIONS
{
  .text :
  {
    KEEP(*(.vectors))
    *(.text*)

    KEEP(*(.init))
    KEEP(*(.fini))

    /* .ctors */
    *crtbegin.o(.ctors)
    *crtbegin?.o(.ctors)
    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
    *(SORT(.ctors.*))
    *(.ctors)

    /* .dtors */
    *crtbegin.o(.dtors)
    *crtbegin?.o(.dtors)
    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
    *(SORT(.dtors.*))
    *(.dtors)

    *(.rodata*)

    KEEP(*(.eh_frame*))
  } > FLASH

  /*
   * SG veneers:
   * All SG veneers are placed in the special output section .gnu.sgstubs. Its start address
   * must be set, either with the command line option ‘--section-start’ or in a linker script,
   * to indicate where to place these veneers in memory.
   */
/*
  .gnu.sgstubs :
  {
    . = ALIGN(32);
  } > FLASH
*/
  .ARM.extab :
  {
    *(.ARM.extab* .gnu.linkonce.armextab.*)
  } > FLASH

  __exidx_start = .;
  .ARM.exidx :
  {
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
  } > FLASH
  __exidx_end = .;

  .copy.table :
  {
    . = ALIGN(4);
    __copy_table_start__ = .;
    LONG (__etext)
    LONG (__data_start__)
    LONG (__data_end__ - __data_start__)
    /* Add each additional data section here */
/*
    LONG (__etext2)
    LONG (__data2_start__)
    LONG (__data2_end__ - __data2_start__)
*/
    __copy_table_end__ = .;
  } > FLASH

  .zero.table :
  {
    . = ALIGN(4);
    __zero_table_start__ = .;
    /* Add each additional bss section here */
/*
    LONG (__bss2_start__)
    LONG (__bss2_end__ - __bss2_start__)
*/
    __zero_table_end__ = .;
  } > FLASH

  /**
   * Location counter can end up 2byte aligned with narrow Thumb code but
   * __etext is assumed by startup code to be the LMA of a section in RAM
   * which must be 4byte aligned 
   */
  __etext = ALIGN (4);

  .data : AT (__etext)
  {
    __data_start__ = .;
    *(vtable)
    *(.data)
    *(.data.*)

    . = ALIGN(4);
    /* preinit data */
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP(*(.preinit_array))
    PROVIDE_HIDDEN (__preinit_array_end = .);

    . = ALIGN(4);
    /* init data */
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP(*(SORT(.init_array.*)))
    KEEP(*(.init_array))
    PROVIDE_HIDDEN (__init_array_end = .);


    . = ALIGN(4);
    /* finit data */
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP(*(SORT(.fini_array.*)))
    KEEP(*(.fini_array))
    PROVIDE_HIDDEN (__fini_array_end = .);

    KEEP(*(.jcr*))
    . = ALIGN(4);
    /* All data end */
    __data_end__ = .;

  } > RAM

  /*
   * Secondary data section, optional
   *
   * Remember to add each additional data section
   * to the .copy.table above to asure proper
   * initialization during startup.
   */
/*
  __etext2 = ALIGN (4);

  .data2 : AT (__etext2)
  {
    . = ALIGN(4);
    __data2_start__ = .;
    *(.data2)
    *(.data2.*)
    . = ALIGN(4);
    __data2_end__ = .;

  } > RAM2
*/

  .bss :
  {
    . = ALIGN(4);
    __bss_start__ = .;
    *(.bss)
    *(.bss.*)
    *(COMMON)
    . = ALIGN(4);
    __bss_end__ = .;
  } > RAM AT > RAM

  /*
   * Secondary bss section, optional
   *
   * Remember to add each additional bss section
   * to the .zero.table above to asure proper
   * initialization during startup.
   */
/*
  .bss2 :
  {
    . = ALIGN(4);
    __bss2_start__ = .;
    *(.bss2)
    *(.bss2.*)
    . = ALIGN(4);
    __bss2_end__ = .;
  } > RAM2 AT > RAM2
*/

  .heap (COPY) :
  {
    . = ALIGN(8);
    __end__ = .;
    PROVIDE(end = .);
    . = . + __HEAP_SIZE;
    . = ALIGN(8);
    __HeapLimit = .;
  } > RAM

  .stack (ORIGIN(RAM) + LENGTH(RAM) - __STACK_SIZE) (COPY) :
  {
    . = ALIGN(8);
    __StackLimit = .;
    . = . + __STACK_SIZE;
    . = ALIGN(8);
    __StackTop = .;
  } > RAM
  PROVIDE(__stack = __StackTop);

  /* Check if data + heap + stack exceeds RAM limit */
  ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
}

Building microbit.elf using CMSIS 5.6.0 - you can retrieve it here.

rm -f microbit.elf *.o microbit.lst
/opt/arm/9/gcc-arm-none-eabi-9-2020-q2-update/bin/arm-none-eabi-gcc -O0 -ggdb -mthumb -mtune=cortex-m0 -nostdlib -nostartfiles -ffreestanding -I/opt/arm/ARM.CMSIS.5.6.0//CMSIS/Include -I/opt/arm/ARM.CMSIS.5.6.0//Device/ARM/ARMCM0/Include -L. -Wl,-T,microbit.ld -o microbit.elf /opt/arm/ARM.CMSIS.5.6.0//Device/ARM/ARMCM0/Source/startup_ARMCM0.c  /opt/arm/ARM.CMSIS.5.6.0//Device/ARM/ARMCM0/Source/system_ARMCM0.c microbit.s 
/opt/arm/9/gcc-arm-none-eabi-9-2020-q2-update/bin/arm-none-eabi-objdump -d microbit.elf > microbit.lst

Executing microbit.elf:

/tmp/qemu/bin/qemu-system-arm --semihosting-config enable=on,target=native -m 16M -nographic -cpu cortex-m0 -machine microbit -kernel microbit.elf
Hello, World!

I tested with this project after having implemented some changes.

First, modify the Makefile according the following diff output:

diff --git a/Makefile b/Makefile
index 505b967..698bf71 100644
--- a/Makefile
+++ b/Makefile
@@ -5,12 +5,13 @@ BINARY_ALL = image_s_ns.elf
 
 MACHINE_NAME := mps2-an505
 
-CMSIS_PATH ?= ./CMSIS_5
-QEMU_PATH ?= ./qemu/build/arm-softmmu/qemu-system-arm
-TOOLCHAIN_PATH ?= ./gcc-arm-none-eabi-8-2019-q3-update/bin
+CMSIS_PATH ?= /opt/arm/ARM.CMSIS.5.9.0
+QEMU_PATH ?= /opt/qemu-7.2.0/bin/qemu-system-arm
+TOOLCHAIN_PATH ?= /opt/arm/11/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin
 
 CROSS_COMPILE = $(TOOLCHAIN_PATH)/arm-none-eabi-
 CC = $(CROSS_COMPILE)gcc
+AS = $(CROSS_COMPILE)as
 LD = $(CROSS_COMPILE)ld
 GDB = $(CROSS_COMPILE)gdb
 OBJ = $(CROSS_COMPILE)objdump
@@ -116,6 +117,7 @@ run: $(BINARY_S) $(BINARY_NS)
                -m 16M \
                -nographic \
                -semihosting \
+                --semihosting-config enable=on,target=native \
                -d int,cpu_reset \
                -device loader,file=$(BINARY_NS) \
                -device loader,file=$(BINARY_S)
@@ -127,6 +129,7 @@ gdbserver: $(BINARY_S) $(BINARY_NS)
                -m 16M \
                -nographic \
                -semihosting \
+                --semihosting-config enable=on,target=native \
                -device loader,file=$(BINARY_NS) \
                -device loader,file=$(BINARY_S) \
                -d int,cpu_reset \

Second, delete non_secure/main_ns.c:

rm non_secure/main_ns.c

Third, create non_secure/main_ns.s with the following content:

                                 .syntax unified
                                 .cpu    cortex-m33
                                 .code   16
                                 .equ    SYS_WRITE0 , 0x04
                                 .equ     angel_SWIreason_ReportException, 0x18
                                 .global  main
main:                            mov r0, #SYS_WRITE0
                                 ldr     r1,=hello
                                 bkpt    0xab
done:                            wfi
                                 b done

                                .balign  4
hello:                          .asciz   "Hello, World!\n"
                                .end

Then build and execute:

make run

You should see a lot of messages displayed by the various initialization code, then the message displayed by using the semihosting services:

Taking exception 16 [Semihosting call] on CPU 0
...handling as semihosting call 0x4
Hello, World!

I would say that this does demonstrate that semihosting works with a QEMU 7.2.0 compiled from its source code using the procedure above, and the problem may reside in your code as suggested by Peter Maydell:

it might also be a bug in your program which the older version of QEMU just didn't happen to trigger.

It may work differently though that with an armv7-m core because of the specific armv8-m security features - I am not familiar with armv8-m - since it seems that the semihosting call made in non-secure mode is being intercepted, then honored in secure mode.

But this should probably be the topic for another question once you will have studied the example code, what I have to do myself.

Frant
  • 5,382
  • 1
  • 16
  • 22
  • Thanks for the thoughts. I've tried the `make install` you suggested but the same results. Because the bare metal program is working with the QEMU version installed via apt get, I don't think the problem is here...? – cberk1 Feb 03 '23 at 10:20
  • Frant's example proves that the semihosting interface in QEMU 7.2 is working. The problem is likely therefore that your program is crashing before it gets to the semihosting. That might be a bug in QEMU, but it might also be a bug in your program which the older version of QEMU just didn't happen to trigger. You need to debug to find out exactly when in your program's execution it is going wrong and what is happening. – Peter Maydell Feb 03 '23 at 10:52
  • @cberk1 I just noticed you may be missing a crucial step between 1. and 2 in order to get v7.2.0. This would be: `1a. git checkout v7.2.0`. You should see the following message afterwards: `HEAD is now at b67b00e6b4 Update VERSION for v7.2.0`. If you did not execute this command, you are using a revision of the qemu source code that is more recent than `b67b00e6b4`. This may be a raison for the behaviour you observed. An alternative is to use `wget https://download.qemu.org/qemu-7.2.0.tar.xz` as in the example above, in order to make sure you are using an official release of the source code. – Frant Feb 03 '23 at 12:03
  • @cberk1: I would suggest you to write a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) for the `mps2-an505` similar to the one provided above for the `microbit`. it should contain the source code/linker script and build procedure, in fact anything needed so that others may attempt reproducing the problem. – Frant Feb 03 '23 at 12:20
  • Semihosting should *also* work with head-of-git for QEMU, so I doubt that not using exactly 7.2.0 is the issue. – Peter Maydell Feb 03 '23 at 13:20
  • @Peter Maydell: Agree, no doubts it does, this is just that, technically, I did not test the example above with a revision other than b67b00e6b4, and wanted to point it out. – Frant Feb 03 '23 at 16:00
  • As suggested by @Peter Maydell, head-of-git (revision `0730eab4d38f74589da4a7d55814773260491f89` at the time being) is working perfectly fine with the example. – Frant Feb 03 '23 at 20:03
  • @cberk1: Where you able to validate that the QEMU you built is working with the example above ? thanks. – Frant Feb 08 '23 at 01:49
  • Hi @Frant, I've had to temporarily work on something else but will get back to this and follow up ASAP. I really appreciate your time. – cberk1 Feb 08 '23 at 09:34
  • Hi, I've just tried this and it works - thanks for the pointers, I'll now try and create a similarly simple example on my M33 :). – cberk1 Feb 08 '23 at 14:32
  • @cberk1: If you think the answer helped solving your problem, please feel free to accept it. There is of course no obligation to do so. – Frant Feb 09 '23 at 12:28
  • @Frant: I'm afraid the M33 is still not working (see the edit to the original post). – cberk1 Feb 09 '23 at 13:17
  • @cberk1: I think I managed to make it work with a ready-to-use example. This would be interesting to see if the QEMU you built is displaying the 'Hello, World!' too with this new example. – Frant Feb 10 '23 at 04:47
  • @cberk1: By the way, could you add to your original question what the exact version of `QEMU` you installed using `apt-get` is ? thanks. – Frant Feb 10 '23 at 15:23