Arm Linux内核模块作弊-Qemu-Xilinx Zynq A9

Arm Linux内核模块作弊-Qemu-Xilinx Zynq A9,arm,gdb,elf,qemu,bare-metal,Arm,Gdb,Elf,Qemu,Bare Metal,我的目标是模拟Zynq-7000上的ARM A9处理器,运行裸机软件。我已经尝试了两种不同的方法,但都遇到了障碍。如有任何关于如何继续的建议,将不胜感激 关于StackOverflow的当前答案: 哪些链接指向 (LKMC,使用v3.0) 使用/build-拱臂qemu裸金属建造 网站上使用ARM虚拟机(-virt标志)的示例运行良好。试图修改此设置以使用我的设置是导致问题的原因(详细信息如下) 我试图复制示例命令行调用,但改为使用-cpu cortex-a9选项: qemu系统ar

我的目标是模拟Zynq-7000上的ARM A9处理器,运行裸机软件。我已经尝试了两种不同的方法,但都遇到了障碍。如有任何关于如何继续的建议,将不胜感激

关于StackOverflow的当前答案:
哪些链接指向
(LKMC,使用v3.0)
使用
/build-拱臂qemu裸金属建造

网站上使用ARM虚拟机(
-virt
标志)的示例运行良好。试图修改此设置以使用我的设置是导致问题的原因(详细信息如下)

我试图复制示例命令行调用,但改为使用
-cpu cortex-a9
选项:
qemu系统arm:mach-virt:CPU cortex-a9不受支持

然后我将整个调用更改为
qemu系统arm-M xilinx-zynq-a9-cpu cortex-a9-nographic-kernel hello.elf-M 512M-serial mon:stdio-s-s

它因错误而崩溃
qemu:fatal:试图在内存或ROM外部0x40000000处执行代码

这是有道理的,因为应用程序是用LKC构建的,我试图在该框架之外运行它

然后我试着运行我自己的应用程序,该应用程序是使用Xilinx工具链的修改版本编译的。我确信它不会马上工作,因为我必须更改启动序列的某些部分。但我想弄清楚这些是什么,然后改变它们。 与
一起运行
qemu系统arm-M xilinx-zynq-a9-cpu cortex-a9-nographic-kernel helloworld.elf-M 512M-serial mon:stdio-s-s

允许GDB成功连接,但无法正确读取符号表。使用
arm none-eabi objdump-D helloworld.elf

告诉我
main
位于
0x001004fc
,但GDB认为它位于
0x40000324
(使用命令
info address main

我目前的工作 PYNQ-Z1(,)有一个32位ARM Cortex-A9处理器,因此我使用
qemu系统ARM
而不是
qemu-system-aarch64
。如果那是错的,有人可以纠正我

值得注意的是,我不能简单地切换到不同的体系结构;我正在使用的代码不能容忍除了小的调整以外的更改,以使Board Support Package(BSP)与模拟器兼容,而不会损害我研究的有效性

一段时间以来我一直在做的是
/run--拱臂-m 512M--裸金属pynq/helloworld--等待gdb

/run gdb--arch arm--baremetal pynq/helloworld--no continue--main

我逐步使用GDB查找哪里有数据中断,并找出Qemu不支持哪种硬件

我运行的软件是使用经过修改的Xilinx工具链构建的,因此包含了许多Xilinx标准库函数。在修改代码以使用虚拟机时,我发现了一些变化,例如更改UART设备的地址,禁用一些启动任务,例如使SCU无效或更改缓存控制器配置,可能是因为Qemu没有模拟这些任务

调试启动时,我遇到的下一个启动问题是XTime函数(XTime_l.c)。这些函数是读取全局系统计时器的包装。Qemu界面中命令
info mtree
的结果似乎表明没有全局计时器设备可与之交互。是否有方法将计时器设备添加到ARM虚拟机?基址是什么并不重要,只要它可以像在Zynq上一样使用,使用寄存器读写

然后我尝试使用特定的机器标志
xilinx-zynq-a9
。LKMC生成以下命令:

+ /home/$USER/$INSTALL_DIR/out/qemu/default/arm-softmmu/qemu-system-arm \
  -machine xilinx-zynq-a9 \
  -gdb tcp::45457 \
  -kernel /home/$USER/$INSTALL_DIR/out/baremetal/arm/qemu/xilinx-zynq-a9/hello.elf \
  -m 512M \
  -monitor telnet::45454,server,nowait \
  -netdev user,hostfwd=tcp::45455-:45455,hostfwd=tcp::45456-:22,id=net0 \
  -no-reboot \
  -smp 1 \
  -virtfs local,path=/home/$USER/$INSTALL_DIR/data/9p,mount_tag=host_data,security_model=mapped,id=host_data \
  -virtfs local,path=/home/$USER/$INSTALL_DIR/out,mount_tag=host_out,security_model=mapped,id=host_out \
  -virtfs local,path=/home/$USER/$INSTALL_DIR/rootfs_overlay,mount_tag=host_rootfs_overlay,security_model=mapped,id=host_rootfs_overlay \
  -serial mon:stdio \
  -trace enable=load_file,file=/home/$USER/$INSTALL_DIR/out/run/qemu/arm/0/trace.bin \
  -cpu cortex-a9 \
  -device virtio-gpu-pci \
  -nographic \
  -serial tcp::45458,server,nowait \
  -semihosting \
;
此虚拟机与通用虚拟机之间的唯一区别是指定机器和cpu的行,这两行过去分别是
-machine virt-machine highmem=off
-cpu cortex-a15
(实际上我必须修改LKCC代码以使其为机器输出正确的cpu名称)

但是,此操作失败,出现错误
qemu系统arm:-设备rtl8139,netdev=net0:找不到设备“rtl8139”的“PCI”总线

这是有道理的,因为不是所有的Zynq部件都有PCI总线。所以我最想知道的是,当目标是纯金属时,为什么LKMC会生成这样一系列的命令

我认为第一个选项最有可能起作用,因为它似乎比某些特定目标具有更好的支持。有趣的是,Xilinx SDK附带的Qemu版本不支持Zynq的裸机(在中称为“独立”)

总结: 有没有办法将计时器设备添加到ARM虚拟机
有人在Qemu Xilinx ARM A9上运行裸机代码吗

我试着尽可能具体,但请随意提出澄清问题

  • 与添加对计时器的支持相比,这可能是一项非常重要的任务 将设备连接到现有QEMU机器。更具体地说,这可能不是 因为有相当数量的支撑臂 架构计时器或特定的计时器硬件。

    在xilinx-zynq-a9的特定情况下,它似乎是全局的 支持第1448页中描述的计时器计数器
  • 在读了几遍你的文章之后,我得出结论,你正在使用的工具集(KMC、toolchain、QEMU)可能会出现很多问题。因此,我创建了一个裸机应用程序,使用我信任的arm工具链,使用QEMU xilinx-zynq-a9机器,以及最新版本的QEMU,4.2.0,b
    #!/bin/bash
    
    set -e 
    
    QEMU_VERSION=4.2.0
    # xenial
    PERL_MODULES_VERSION=5.22
    # eoan
    PERL_MODULES_VERSION=5.28
    
    # bionic
    PERL_MODULES_VERSION=5.26
    
    PREFIX=/opt/qemu-${QEMU_VERSION}
    
    do_install_prerequisites()
    {
      sudo apt-get install libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev libaio-dev libbluetooth-dev libbrlapi-dev libbz2-dev  libcap-dev libcap-ng-dev libcurl4-gnutls-dev libgtk-3-dev libibverbs-dev \
      libjpeg8-dev libncurses5-dev libnuma-dev librbd-dev librdmacm-dev libsasl2-dev libsdl2-dev libseccomp-dev libsnappy-dev libssh2-1-dev libvde-dev libvdeplug-dev libvte-2.91-dev libxen-dev liblzo2-dev \
      valgrind xfslibs-dev liblzma-dev flex bison texinfo perl perl-modules-${PERL_MODULES_VERSION}  python-sphinx gettext
    }
    
    do_download_qemu()
    {
        if [ ! -f qemu-${QEMU_VERSION}.tar.xz ]
      then
        wget https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz
      fi
    }
    
    do_extract_qemu()
    {
      echo "extracting..."
      rm -rf qemu-${QEMU_VERSION}
      tar Jxf qemu-${QEMU_VERSION}.tar.xz
    }
    
    do_configure_qemu()
    {
      local TARGET_LIST="arm-softmmu"
      pushd qemu-${QEMU_VERSION}
      ./configure --target-list="${TARGET_LIST}" --prefix=${PREFIX} --extra-cflags="-I$(pwd)/packages/include" --extra-ldflags="-L$(pwd)/packages/lib" 
      popd
    }
    
    
    do_build_qemu()
    {
      echo "building..."
      pushd qemu-${QEMU_VERSION}
      make all
      popd
    }
    
    do_install_qemu()
    {
      echo "installing..."
      pushd qemu-${QEMU_VERSION}
      sudo make install
      popd
    }
    
    
    do_build()
    {
      do_download_qemu
      do_extract_qemu
      do_configure_qemu
      do_build_qemu
      do_install_qemu
    }
    
    # main
    
    do_install_prerequisites
    do_build
    
    ls -gG /opt/qemu-4.2.0/bin/
    total 22992
    -rwxr-xr-x 1    22520 Feb 21 23:57 elf2dmp
    -rwxr-xr-x 1    18424 Feb 21 23:57 ivshmem-client
    -rwxr-xr-x 1   218264 Feb 21 23:57 ivshmem-server
    -rwxr-xr-x 1    30864 Feb 21 23:57 qemu-edid
    -rwxr-xr-x 1   374328 Feb 21 23:57 qemu-ga
    -rwxr-xr-x 1  1767744 Feb 21 23:57 qemu-img
    -rwxr-xr-x 1  1719104 Feb 21 23:57 qemu-io
    -rwxr-xr-x 1   505016 Feb 21 23:57 qemu-keymap
    -rwxr-xr-x 1  1727744 Feb 21 23:57 qemu-nbd
    -rwxr-xr-x 1   599848 Feb 21 23:57 qemu-pr-helper
    -rwxr-xr-x 1 16510840 Feb 21 23:57 qemu-system-arm
    -rwxr-xr-x 1    26856 Feb 21 23:57 virtfs-proxy-helper
    
    /******************************************************************************
     * @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
    {
      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*))
      } > RAM
    
      /*
       * 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);
      } > RAM
    */
      .ARM.extab :
      {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
      } > RAM
    
      __exidx_start = .;
      .ARM.exidx :
      {
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
      } > RAM
      __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__ = .;
      } > RAM
    
      .zero.table :
      {
        . = ALIGN(4);
        __zero_table_start__ = .;
        /* Add each additional bss section here */
    /*
        LONG (__bss2_start__)
        LONG (__bss2_end__ - __bss2_start__)
    */
        __zero_table_end__ = .;
      } > RAM
    
      /**
       * 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")
    }
    
    # Shared Makefile 
    
    .PHONY:         clean
    all:            $(MACHINE).elf
    
    $(MACHINE).elf: $(SOURCES) $(MACHINE).c
                    $(CC) $(CFLAGS) $(LDFLAGS) -o $(MACHINE).elf $(MACHINE).c $(SOURCES)
                    $(OBJDUMP) -d $(MACHINE).elf > $(MACHINE).lst
    
    qemu:           $(MACHINE).elf
                    $(QEMU_SYSTEM) -m 513M -nographic -machine $(MACHINE) $(QEMU_DEBUG_OPTIONS) -cpu $(CPU) -kernel $(MACHINE).elf
    
    gdb:            $(MACHINE).elf
                    $(GDB) --quiet --command=$(GDB_COMMANDS) $(MACHINE).elf
    
    clean:
                    rm -f $(MACHINE).elf $(MACHINE).lst
    
                    .title startup-aarch32.s
                    .arch armv7-a
                    .text
                    .section .text.startup,"ax"    
                    .globl Reset_Handler   
    Reset_Handler:
                    ldr r0, =__StackTop
                    mov sp, r0
                    bl start
    wait:           wfe
                    b wait
                   .end
    
    #include <stdint.h>
    
    /* Reference: https://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf - page 1449.
    
     1. Read the upper 32-bit timer counter register
     2. Read the lower 32-bit timer counter register
     3. Read the upper 32-bit timer counter register again.
        If the value is different to the32-bit upper value read previously, go back to step 2.
        Otherwise the 64-bit timercounter value is correct.
    */
    
    static const uintptr_t Global_Timer_Counter_Register0 = 0xF8F00200;
    static const uintptr_t Global_Timer_Counter_Register1 = 0xF8F00204;
    
    void start()
    {
      uint64_t global_timer_counter = 0;
      uint32_t upper = 0;
      uint32_t upper2 = 0;
      uint32_t lower = 0;
    
      for (;;) {
        upper = *(volatile uint32_t*) Global_Timer_Counter_Register1;
        lower = *(volatile uint32_t*) Global_Timer_Counter_Register0;
    
        upper2 = *(volatile uint32_t*) Global_Timer_Counter_Register1;
        if (upper != upper2) {
            lower = *(volatile uint32_t*) Global_Timer_Counter_Register0;
        }
    
        global_timer_counter = (uint64_t) upper << 32 | lower;
    
      }
    }
    
    target remote localhost:1234
    monitor reset halt
    load
    break Reset_Handler
    break start
    
    /*
     *-------- <<< Use Configuration Wizard in Context Menu >>> -------------------
     */
    
    /*--------------------- Embedded RAM Configuration ----------------------------
      <h> RAM Configuration
        <o0> RAM Base Address    <0x0-0xFFFFFFFF:8>
        <o1> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
      </h>
     -----------------------------------------------------------------------------*/
    __RAM_BASE = 0x00100000;
    __RAM_SIZE = 0x20000000;
    
    /*--------------------- 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 = 0x00020000;
    __HEAP_SIZE  = 0x00080000;
    
    /*
     *-------------------- <<< end of configuration section >>> -------------------
     */
    
    INCLUDE gcc_arm32_ram.ld
    
    # Toolchain
    CROSS_COMPILE=/opt/arm/9/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi/bin/arm-none-eabi-
    CC=$(CROSS_COMPILE)gcc
    OBJDUMP=$(CROSS_COMPILE)objdump
    OBJCOPY=$(CROSS_COMPILE)objcopy
    
    # Target
    CPU=cortex-a9
    MACHINE=xilinx-zynq-a9
    CFLAGS=-O0 -ggdb -mtune=$(CPU) -nostdlib -nostartfiles -ffreestanding 
    LDFLAGS=-L. -Wl,-T,$(MACHINE).ld
    SOURCES=startup-aarch32.s 
    
    # qemu
    QEMU_DEBUG_OPTIONS=-S -gdb tcp::1234,ipv4
    QEMU_SYSTEM=/opt/qemu-4.2.0/bin/qemu-system-arm
    
    # GDB
    GDB=$(CROSS_COMPILE)gdb
    GDB_COMMANDS=${MACHINE}.gdb
    
    include Makefile.inc
    
    wget "https://developer.arm.com/-/media/Files/downloads/gnu-a/9.2-2019.12/binrel/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi.tar.xz?revision=64186c5d-b471-4c97-a8f5-b1b300d6594a&la=en&hash=5E9204DA5AF0B055B5B0F50C53E185FAA10FF625" -o gcc-arm-9.2-2019.12-x86_64-arm-none-eabi.tar.xz
    mkdir -p /opt/arm/9
    tar Jxf gcc-arm-9.2-2019.12-x86_64-arm-none-eabi.tar.xz -C /opt/arm/9
    
    make -f xilinx-zynq-a9.mak clean all
    
    rm -f xilinx-zynq-a9.elf xilinx-zynq-a9.lst
    /opt/arm/9/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc -O0 -ggdb -mtune=cortex-a9 -nostdlib -nostartfiles -ffreestanding  -L. -Wl,-T,xilinx-zynq-a9.ld -o xilinx-zynq-a9.elf xilinx-zynq-a9.c startup-aarch32.s 
    /opt/arm/9/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi/bin/arm-none-eabi-objdump -d xilinx-zynq-a9.elf > xilinx-zynq-a9.lst
    
    make -f xilinx-zynq-a9.mak qemu
    
    /opt/qemu-4.2.0/bin/qemu-system-arm -m 513M -nographic -machine xilinx-zynq-a9 -S -gdb tcp::1234,ipv4 -cpu cortex-a9 -kernel xilinx-zynq-a9.elf
    
    make -f xilinx-zynq-a9.mak gdb
    
    /opt/arm/9/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi/bin/arm-none-eabi-gdb --quiet --command=xilinx-zynq-a9.gdb xilinx-zynq-a9.elf
    Reading symbols from xilinx-zynq-a9.elf...
    Reset_Handler () at startup-aarch32.s:7
    7                       ldr r0, =__StackTop
    unknown command: 'reset'
    Loading section .text, size 0xd8 lma 0x100000
    Loading section .copy.table, size 0xc lma 0x1000d8
    Start address 0x1000b8, load size 228
    Transfer rate: 222 KB/sec, 114 bytes/write.
    Breakpoint 1 at 0x1000b8: file startup-aarch32.s, line 7.
    Breakpoint 2 at 0x10000c: file xilinx-zynq-a9.c, line 17.
    (gdb) 
    
    (gdb) continue
    Continuing.
    
    Breakpoint 2, start () at xilinx-zynq-a9.c:17
    17        uint64_t global_timer_counter = 0;
    
    31          global_timer_counter = (uint64_t) upper << 32 | lower;
    
    (gdb) p/x global_timer_counter
    $2 = 0xa6f2a0a
    
    (gdb) p/x global_timer_counter
    $9 = 0xa84315b
    
    (gdb)  p/x global_timer_counter
    $10 = 0xabe77cf