This post begins with a goal to compile and run some assembly programs in AA64 on ARMv8-A architecture for students in a microcontroller course. My prior solution to this was failing so I have came up with the idea to run the ARM FVP (Fixed Virtual Platform) with Linux and use a gdbserver inside the FVP Linux to enable remote debugging with VSCode.

# Setup the FVP and Linux

ARM has a few basic FVPs for their ARMv8 architecture available and I am using the Foundation version of it, which gives a much simpler network configuration that will be used for ssh and gdb. You can download it from this page here.

## Bootloader, Linux kernel, and filesystem disk

In order to let the FVP runs Linux, we will be using a set of tools from Linaro:

1. Bootloader and FVP run script:  download the fvp-latest-oe-uboot.zip archive which contains a run_model.sh, the Linux kernel, and the device tree file for Foundation FVP foundation-v8-gicv3.dtb.
2. Filesystem image: download and uncompress the vexpress64-openembedded_lamp-armv8-gcc-4.9_20150620-722.img.gz archive

## Boot up Linux

To boot up Linux, you will need to tell the run_model.sh where to find the Foundation model, the device tree, and the filesystem.

In the expanded folder of fvp-latest-oe-uboot.zip, run the following shell commands:

export MODEL=FVP_FOUNDATION_FOLDER//Foundation_Platformpkg/models/Linux64_GCC-9.3/Foundation_Platform
export DTB=./foundation-v8-gicv3.dtb
export DISK=path/to/vexpress64-openembedded_lamp-armv8-gcc-4.9_20150620-722.img

chmod +x run_model.sh

./run_model.sh


Now you should see the FVP model running. If you have xTerm install, the FVP will launch two terminals at start with terminal 0 attached to the Linux. You could also attach to it by using telnet localhost 5000.

Since the filesystem we choose contains a lot of development tools (LAMP), it might take ~3 min for first time boot up.

# Debug with FVP

To debug program within FVP, I choose to use gdbserver that expose connection to the host so that the host debugger can pick it up. To do so, we will need to enable network NAT between FVP and the host.

In the ./run_model.sh, add this option which launching the FVP: --network=nat --network-nat-ports=8022=22,9234=1234. This will allow us to ssh into the FVP at localhost:8022 and setup gdbserver at FVP port 1234 and pick it up at host with port 9234. See this doc from fedora for more details.

Now you could either ssh into the FVP with ssh -p 8022 root@localhost or connect to it with telnet. With either way, after you have shell prompt, launch the program within FVP you want to debug with gdbserver :1234 PROG. Then you could use gdb at host with command target remote :9234 to start. Note you can use scp to copy the program from host to FVP and vice versa:

# Copy from host directory to FVP
scp -P 8022 HOST_DIR/from root@localhost:FVP_DIR/to

# Copy from FVP to host
scp -P 8022 root@localhost:FVP_DIR/from HOST_DIR/to

Noted the Linux version on the prebuilt filesystem might be old (GCC 4.9 version installed) and you will mostly want to use the same version of GCC toolchain to compile and debug. You can download them from Linaro release here.

With a little bit of work, you can also get VSCode debugger to work with this FVP. You will need the C/C++ extension from Microsoft, then use the following launch.json file which will use the Linaro gdb and connect to localhost:9234. Noted you will need to set the miDebuggerPath to the Linaro one.

{
"version": "0.2.0",
"configurations": [
{
"name": "FVP Debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/lab", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"miDebuggerPath": "\${env:HOME}/Desktop/FVP_Linux/gcc-linaro-4.9.4-2017.01-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gdb",
]