I'm writing an operating system for learning purposes, I'm focusing on the raspberry pi3 as target machine. To test my code I decided to use QEMU to emulate the raspberry hardware. By the way, the question in not about raspberry, but about ARM emulation in general or what is the standard behaviour of QEMU. The problem is that when I launch my kernel with the command:
qemu-system-aarch64 -M raspi3 -monitor stdio -d in_asm -kernel kernel8.img
I have 4 cores of my host machine (x86_64 running linux) at 100% of usage.
to be more precise, my kernel is not a kernel at all! It's just 2 lines of assembly of what will be the bootloader for the kernel:
.section ".text.boot"
.global _start
_start:
1: wfi
b 1b
So I don't think the problem is in the code. Here the dump of the kernel8.elf
~> aarch64-elf-objdump -d kernel8.elf
kernel8.elf: file format elf64-littleaarch64
Disassembly of section .text:
0000000000080000 <__start>:
80000: d503207f wfi
80004: 17ffffff b 80000 <__start>
also trying to change machine, such raspi2 or versatilepb doesn't help much, CPU usage is lower but still high (on average 70%). Using the generic ARM emulation "-M virt" reduces more the CPU usage, but still have one core always at 100% and the others at about 50%.
Is this normal?? Does emulating ARM on x86 require such a lot of CPU usage, taking into account the extreme simplicity of the code I'm emulating??
Related
I'm trying to boot a kernel (extracted from a firmware) using QEMU.
Qemu emulation seems to start at 0x0.
The problem is that the memory from 0x0 to 0x04000000 is only filled with 0.
How can i debug the bootloader?
You don't say what your command line is. The address where QEMU starts execution depends on many things:
the guest CPU architecture
which board model you are emulating
whether you passed QEMU a BIOS image file
the file format of any file passed to -kernel (ELF, plain kernel image, uImage, etc)
In general, though, you should not expect to be able to pull a random kernel image out of a firmware dump for a piece of Arm hardware and run it under QEMU. This is because every Arm board or machine is different -- RAM may be in different places, the devices such as the serial port are at different addresses, and so on -- and the kernel will only boot on systems which it has been compiled to support. The chances are very high that (a) QEMU does not have a specific emulation of the bit of hardware that the firmware dump is for and (b) the kernel from the firmware has not been built to also run on any of the board types that QEMU does support. So it will almost certainly simply crash very early on in bootup without producing any output.
If you want to debug what's going on in early bootup, the best approach is probably to use QEMU's built in gdbstub, and attach a guest-architecture-aware gdb to it. You may also find QEMU's internal logging via the '-d' option useful, though it requires some familiarity with how QEMU works to make sense of the output.
In the case of x86 the same (real mode) bootloader works on virtually any x86 device.
Is that possible on ARM or do I need to create a specific bootloader for each 'cortex'?
x86 or lets say PC compatible systems are ... pc compatible. They support the ancient bios calls so that there is massive compatibility. by design, by the chip vendor (intel) the software vendors (bios, operating system) and the motherboard vendors.
ARM is in now way shape or form like that. There are instruction sets you can choose that work almost or all the way across, but remember ARM systems you buy an ARM core and add it to your special chip, you and your special/custom stuff, then that is put on one or more different boards. There is little to no compatibility. Instruction set and arm core is a small part of the whole picture most of the code is for the non-arm stuff.
u-boot and perhaps others are fairly massive bootloaders, pretty much an operating system themselves, and have to be ported just like an operating system to each chip/board combination. The chip vendor, if this is a linux compatible system, most likely has a reference design and a BSP including a u-boot port and/or some other solution (rasberry pi is a good example). it is fairly trivial to boot linux or used to be, there is no reason for the massively overcomplicated u-boot. without a DTB you setup a few memory locations a register or two and branch to the kernel, thats it (again look at the raspberry pi), I assume with DTB you build the dtb then put it somewhere, setup a few registers and branch to the linux kernel (raspberry pi? ntc chip?)
There is a Arm open source project that can cover Armv7/v8 Cortex-A processors bootloaders.
https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/
Another open source project for Cortex-M processors:
https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/
Is it possible to compile some Linux Kernel and run it over QEMU, emulating some Big Endian ARM processor?
If QEMU is not capable of that, I'd love to hear about other system emulators than can.
My basic goal is to run and debug dedicated Big Endian ELFs in as much as possible native environment.
Every close solution or idea would help!
QEMU has support for big-endian ARM CPUs, but it does not currently have support for emulation of any specific machines (boards) which have big-endian ARM CPUs in them. ARM Linux kernels will generally only run on the hardware they're compiled for, so you can't just take a random big-endian ARM Linux kernel and run it on anything -- you'd need to model the hardware the kernel wanted to see first.
The underlying reason for this is that big-endian ARM systems are very rare -- almost everybody runs ARM CPUs in little-endian mode, and all the boards QEMU models today are little-endian.
Which kernel config file is best to use ( and eventually modify ) for FreeBSD for arm versatile Cortex A9 platform ( vexpress-a9 in qemu ).
I need to compile and run kernel with SMP support.
It's intended to be run under qemu this way
qemu-system-arm -M vexpress-a9 -smp cores=4 (...other params...)
FreeBSD/arm and FreeBSD/armv6 support a large range of ARM CPUs and development boards. Not every peripheral is supported on every CPU or board, though work continues towards this and contributions are always welcome. Conversely, many CPUs and boards not listed may work with only minimal changes needed.
Listing all supported devices on all CPUs and boards is impractical here, however much information can be obtained from the mailing list and archives, the FreeBSD/arm Wiki pages, and also from the Kernel Configuration files
PS:
Versatile Express support in QEMU
I was reading this informative blog post here about the booting process on x64. In what ways is the booting process on ARM different? I had a look at Raspberry pi and it seems that the GPU is what executes before control is handed over to ARM processor. Are there any similar resources you have come across for ARM processors?
Just like the x86 boot process is documented in documents available at intel.com arm boot process is documented at arm.com as is any other processor documented.
The full sized (non-cortex-m) arm cores start by executing at address zero for reset. There is one instruction location for reset, one for data abort, undefined instruction, etc. Similar to an interrupt vector table but instead of an address there is an instruction there ideally a branch.
processors historically have some non-volatile ram mapped into the boot space or vector table or whatever, then volatile ram if any elsewhere. x86 historically near the top of ram, arm at the bottom.
ARM does not make chips like intel, it designs processor cores which other folks that make chips include in their chip designs instead of having to design their own cores and maintain compilers, etc. So the chip vendor can solve the boot process in a number of ways, some have something non-volatile mapped low then after booting you can swap in ram to that address space, whatever. In the case of the Raspberry Pi chips which are made by broadcom, they have their own gpu which actually boots the chip, it eventually reads a file assumed to be the linux kernel and root file system, but doesnt have to be. It places that file in ram (by default) in the place where a linux kernel would be loaded by a bootloader like redboot or uboot, in this case by the gpu's arm loader. the gpu then places a few breadcrumbs including the reset instruction(s) required to branch into the linux kernel (generally a very trivial thing), then release reset on the arm core allowing it to boot. so basically the arm sees only ram which is kind of nice, but that is somewhat atypical for arm or other processors to do that. Normally the main processor boots from non-volatile storage (eeprom, flash, etc) and then itself loads linux or whatever and branches to it.
A number of other processor types will have an interrupt vector table, including the arm cortex-m series which are thumb instruction set only cores. they are designed to be microcontrollers and not carry as much overhead, so the first address slot is actually meant to be filled with the init value for the stack pointer, then the second is the address for reset, and then a zillion others. The hardware is designed to preserve registers for you so that you can have the address to C functions right in the table and not have to have "some assembly required" wrappers written by you or the folks that ported the toolchain to this platform. Other processor types will just have a vector table and some assembly is required to be wrapped around interrupts and such.