feat(kernel): add Stage 1 bare-metal hypervisor skeleton for QEMU ARM virt
- Add kernel/arch/arm/boot.S with ARMv7 assembly entry, stack setup, BSS clear - Add kernel/arch/arm/linker.ld for QEMU virt memory layout (load at 0x40000000) - Add kernel/arch/arm/uart.c/uart.h for PL011 serial output - Add kernel/kernel.c with kernel_main() idle loop - Add kernel/Makefile for arm-none-eabi-gcc cross-compile and QEMU launch - Add kernel/README.md with build/run instructions - Ignore kernel build artifacts in .gitignore
This commit is contained in:
parent
e6ec3881af
commit
173b2c3330
8 changed files with 250 additions and 0 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -55,6 +55,12 @@ test/results/
|
||||||
test/coverage/
|
test/coverage/
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
# Universalisos kernel build artifacts
|
||||||
|
kernel/*.o
|
||||||
|
kernel/*.elf
|
||||||
|
kernel/*.bin
|
||||||
|
kernel/arch/arm/*.o
|
||||||
|
|
||||||
# Temporary files
|
# Temporary files
|
||||||
*.tmp
|
*.tmp
|
||||||
*.temp
|
*.temp
|
||||||
|
|
|
||||||
52
kernel/Makefile
Normal file
52
kernel/Makefile
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Universalisos kernel build for QEMU ARM virt
|
||||||
|
|
||||||
|
CROSS_COMPILE ?= arm-none-eabi-
|
||||||
|
CC := $(CROSS_COMPILE)gcc
|
||||||
|
LD := $(CROSS_COMPILE)ld
|
||||||
|
OBJCOPY := $(CROSS_COMPILE)objcopy
|
||||||
|
OBJDUMP := $(CROSS_COMPILE)objdump
|
||||||
|
|
||||||
|
CFLAGS := \
|
||||||
|
-mcpu=cortex-a15 \
|
||||||
|
-marm \
|
||||||
|
-O2 \
|
||||||
|
-ffreestanding \
|
||||||
|
-nostdlib \
|
||||||
|
-nostartfiles \
|
||||||
|
-Wall \
|
||||||
|
-Wextra \
|
||||||
|
-Werror \
|
||||||
|
-Iinclude \
|
||||||
|
-g
|
||||||
|
|
||||||
|
LDFLAGS := -T arch/arm/linker.ld
|
||||||
|
|
||||||
|
OBJS := \
|
||||||
|
arch/arm/boot.o \
|
||||||
|
arch/arm/uart.o \
|
||||||
|
kernel.o
|
||||||
|
|
||||||
|
.PHONY: all clean run dump
|
||||||
|
|
||||||
|
all: kernel.bin kernel.elf
|
||||||
|
|
||||||
|
kernel.elf: $(OBJS) arch/arm/linker.ld
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS)
|
||||||
|
|
||||||
|
kernel.bin: kernel.elf
|
||||||
|
$(OBJCOPY) -O binary $< $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
dump: kernel.elf
|
||||||
|
$(OBJDUMP) -d $<
|
||||||
|
|
||||||
|
run: kernel.elf
|
||||||
|
qemu-system-arm -M virt -cpu cortex-a15 -nographic -kernel kernel.elf
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) kernel.elf kernel.bin
|
||||||
58
kernel/README.md
Normal file
58
kernel/README.md
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Universalisos Kernel — Stage 1 Bare-Metal Skeleton
|
||||||
|
|
||||||
|
This is the first bootable type-1 hypervisor milestone for Universalisos: a
|
||||||
|
minimal bare-metal kernel that runs on QEMU's ARM `virt` machine and prints to
|
||||||
|
the PL011 UART.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Requires `arm-none-eabi-gcc` and `qemu-system-arm`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd kernel
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
- `kernel.elf` — ELF image for debugging
|
||||||
|
- `kernel.bin` — raw binary for QEMU `-kernel`
|
||||||
|
|
||||||
|
## Running in QEMU
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make run
|
||||||
|
```
|
||||||
|
|
||||||
|
This runs `qemu-system-arm` with the ELF image so that QEMU loads the kernel
|
||||||
|
at the address specified in the linker script.
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
|
||||||
|
```
|
||||||
|
Universalisos type-1 hypervisor booted.
|
||||||
|
Stage 1: bare-metal skeleton running on QEMU ARM virt.
|
||||||
|
```
|
||||||
|
|
||||||
|
Press `Ctrl+A` then `X` to exit QEMU.
|
||||||
|
|
||||||
|
## Inspecting the binary
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make dump
|
||||||
|
```
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `arch/arm/boot.S` | Assembly entry point, stack/BSS setup |
|
||||||
|
| `arch/arm/linker.ld` | Memory layout for QEMU virt (load at 0x40000000) |
|
||||||
|
| `arch/arm/uart.c` | PL011 UART driver |
|
||||||
|
| `arch/arm/uart.h` | UART interface |
|
||||||
|
| `kernel.c` | `kernel_main()` entry point |
|
||||||
|
|
||||||
|
## Design notes
|
||||||
|
|
||||||
|
- The kernel is loaded by QEMU at RAM base `0x40000000`.
|
||||||
|
- A 64 KiB stack is reserved immediately after the BSS section.
|
||||||
|
- Interrupts are disabled in the boot stub; the kernel idles with `wfi`.
|
||||||
34
kernel/arch/arm/boot.S
Normal file
34
kernel/arch/arm/boot.S
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Universalisos ARMv7 boot code for QEMU virt machine.
|
||||||
|
*
|
||||||
|
* This is the first code executed after QEMU loads the kernel image.
|
||||||
|
* It sets up the stack, zeroes the BSS, and jumps to kernel_main().
|
||||||
|
*/
|
||||||
|
|
||||||
|
.syntax unified
|
||||||
|
.arch armv7-a
|
||||||
|
|
||||||
|
.section .text.boot
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
/* Disable interrupts until the kernel is ready. */
|
||||||
|
cpsid if
|
||||||
|
|
||||||
|
/* Set up the stack at the top of the reserved boot region. */
|
||||||
|
ldr sp, =_stack_top
|
||||||
|
|
||||||
|
/* Clear the BSS section. */
|
||||||
|
ldr r0, =_bss_start
|
||||||
|
ldr r1, =_bss_end
|
||||||
|
mov r2, #0
|
||||||
|
1:
|
||||||
|
cmp r0, r1
|
||||||
|
bge 2f
|
||||||
|
str r2, [r0], #4
|
||||||
|
b 1b
|
||||||
|
2:
|
||||||
|
/* Enter the C kernel. */
|
||||||
|
bl kernel_main
|
||||||
|
|
||||||
|
/* Halt if kernel_main ever returns. */
|
||||||
|
b .
|
||||||
39
kernel/arch/arm/linker.ld
Normal file
39
kernel/arch/arm/linker.ld
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Universalisos linker script for QEMU ARM virt machine.
|
||||||
|
*
|
||||||
|
* QEMU loads the raw kernel image at the start of RAM (0x40000000)
|
||||||
|
* when using -kernel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x40000000;
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
*(.text.boot)
|
||||||
|
*(.text .text.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
*(.data .data.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss : {
|
||||||
|
_bss_start = .;
|
||||||
|
*(.bss .bss.*)
|
||||||
|
*(COMMON)
|
||||||
|
_bss_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 64 KiB boot stack placed immediately after BSS, 8-byte aligned. */
|
||||||
|
_stack_bottom = .;
|
||||||
|
. = ALIGN(8);
|
||||||
|
. = . + 0x10000;
|
||||||
|
_stack_top = ALIGN(8);
|
||||||
|
}
|
||||||
32
kernel/arch/arm/uart.c
Normal file
32
kernel/arch/arm/uart.c
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* PL011 UART driver for QEMU ARM virt machine.
|
||||||
|
*
|
||||||
|
* The virt machine exposes a PL011 UART at 0x09000000.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "uart.h"
|
||||||
|
|
||||||
|
#define UART0_BASE 0x09000000U
|
||||||
|
#define UART_DR (*(volatile unsigned int *)(UART0_BASE + 0x00U))
|
||||||
|
#define UART_FR (*(volatile unsigned int *)(UART0_BASE + 0x18U))
|
||||||
|
#define UART_FR_TXFF (1U << 5)
|
||||||
|
|
||||||
|
void uart_init(void)
|
||||||
|
{
|
||||||
|
/* QEMU initializes the UART for us. */
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_putc(char c)
|
||||||
|
{
|
||||||
|
while ((UART_FR & UART_FR_TXFF) != 0U) {
|
||||||
|
/* Wait until the transmit FIFO is not full. */
|
||||||
|
}
|
||||||
|
UART_DR = (unsigned int)c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_puts(const char *s)
|
||||||
|
{
|
||||||
|
while (*s != '\0') {
|
||||||
|
uart_putc(*s++);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
kernel/arch/arm/uart.h
Normal file
12
kernel/arch/arm/uart.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* PL011 UART driver header for QEMU ARM virt machine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UNIVERSALISOS_UART_H
|
||||||
|
#define UNIVERSALISOS_UART_H
|
||||||
|
|
||||||
|
void uart_init(void);
|
||||||
|
void uart_putc(char c);
|
||||||
|
void uart_puts(const char *s);
|
||||||
|
|
||||||
|
#endif /* UNIVERSALISOS_UART_H */
|
||||||
17
kernel/kernel.c
Normal file
17
kernel/kernel.c
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Universalisos kernel entry point.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "arch/arm/uart.h"
|
||||||
|
|
||||||
|
void kernel_main(void)
|
||||||
|
{
|
||||||
|
uart_init();
|
||||||
|
uart_puts("Universalisos type-1 hypervisor booted.\r\n");
|
||||||
|
uart_puts("Stage 1: bare-metal skeleton running on QEMU ARM virt.\r\n");
|
||||||
|
|
||||||
|
/* Idle loop. */
|
||||||
|
for (;;) {
|
||||||
|
__asm__ __volatile__("wfi");
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue