refactor(kernel): rewrite Stage 1 kernel in C++
- Rename kernel.c -> kernel.cpp and uart.c -> uart.cpp - Add universalisos::uart namespace with constexpr register definitions - Use extern "C" linkage for kernel_main() called from boot.S - Compile with arm-none-eabi-g++ using C++17 freestanding flags (-fno-exceptions, -fno-rtti, -fno-threadsafe-statics, -fno-use-cxa-atexit) - Update Makefile to use g++ and .cpp build rules
This commit is contained in:
parent
6a33d926f9
commit
bafa872415
9 changed files with 120 additions and 69 deletions
|
|
@ -564,10 +564,10 @@ class AurelioAgentSchema:
|
|||
### Stage 1: Bare-Metal Hypervisor Skeleton ✅ Implemented
|
||||
|
||||
**Deliverables**:
|
||||
- Bootable bare-metal kernel for QEMU ARM virt
|
||||
- Bootable bare-metal kernel for QEMU ARM virt, written in **C++**
|
||||
- Assembly startup with stack/BSS setup
|
||||
- PL011 UART driver for serial output
|
||||
- Build system using `arm-none-eabi-gcc`
|
||||
- Build system using `arm-none-eabi-g++`
|
||||
|
||||
**Code Components**:
|
||||
| File | Purpose |
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ See [BUILD_ENVIRONMENT.md](BUILD_ENVIRONMENT.md) for detailed setup instructions
|
|||
## Hypervisor Kernel (C)
|
||||
|
||||
The `kernel/` directory contains the actual Universalisos type-1 hypervisor
|
||||
implementation. Stage 1 is a bootable bare-metal skeleton for QEMU ARM virt:
|
||||
implementation, written in **C++**. Stage 1 is a bootable bare-metal skeleton
|
||||
for QEMU ARM virt:
|
||||
|
||||
```bash
|
||||
cd kernel
|
||||
|
|
|
|||
|
|
@ -1,18 +1,23 @@
|
|||
# Universalisos kernel build for QEMU ARM virt
|
||||
# Universalisos kernel build for QEMU ARM virt (C++)
|
||||
|
||||
CROSS_COMPILE ?= arm-none-eabi-
|
||||
CC := $(CROSS_COMPILE)gcc
|
||||
CXX := $(CROSS_COMPILE)g++
|
||||
LD := $(CROSS_COMPILE)ld
|
||||
OBJCOPY := $(CROSS_COMPILE)objcopy
|
||||
OBJDUMP := $(CROSS_COMPILE)objdump
|
||||
|
||||
CFLAGS := \
|
||||
CXXFLAGS := \
|
||||
-mcpu=cortex-a15 \
|
||||
-marm \
|
||||
-O2 \
|
||||
-std=c++17 \
|
||||
-ffreestanding \
|
||||
-nostdlib \
|
||||
-nostartfiles \
|
||||
-fno-exceptions \
|
||||
-fno-rtti \
|
||||
-fno-threadsafe-statics \
|
||||
-fno-use-cxa-atexit \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Werror \
|
||||
|
|
@ -31,16 +36,16 @@ OBJS := \
|
|||
all: kernel.bin kernel.elf
|
||||
|
||||
kernel.elf: $(OBJS) arch/arm/linker.ld
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS)
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(OBJS)
|
||||
|
||||
kernel.bin: kernel.elf
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
dump: kernel.elf
|
||||
$(OBJDUMP) -d $<
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Universalisos Kernel — Stage 1 Bare-Metal Skeleton
|
||||
# Universalisos Kernel — Stage 1 Bare-Metal Skeleton (C++)
|
||||
|
||||
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.
|
||||
minimal bare-metal kernel written in **C++** that runs on QEMU's ARM `virt`
|
||||
machine and prints to the PL011 UART.
|
||||
|
||||
## Building
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ Expected output:
|
|||
|
||||
```
|
||||
Universalisos type-1 hypervisor booted.
|
||||
Stage 1: bare-metal skeleton running on QEMU ARM virt.
|
||||
Stage 1: bare-metal C++ skeleton running on QEMU ARM virt.
|
||||
```
|
||||
|
||||
Press `Ctrl+A` then `X` to exit QEMU.
|
||||
|
|
@ -47,9 +47,9 @@ make dump
|
|||
|------|---------|
|
||||
| `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.cpp` | PL011 UART driver |
|
||||
| `arch/arm/uart.h` | UART interface |
|
||||
| `kernel.c` | `kernel_main()` entry point |
|
||||
| `kernel.cpp` | `kernel_main()` entry point |
|
||||
|
||||
## Design notes
|
||||
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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++);
|
||||
}
|
||||
}
|
||||
73
kernel/arch/arm/uart.cpp
Normal file
73
kernel/arch/arm/uart.cpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* PL011 UART driver for QEMU ARM virt machine.
|
||||
*
|
||||
* The virt machine exposes a PL011 UART at 0x09000000.
|
||||
*/
|
||||
|
||||
#include "uart.h"
|
||||
|
||||
namespace universalisos::uart {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr unsigned int UART0_BASE = 0x09000000U;
|
||||
|
||||
constexpr unsigned int REG_DR = 0x00U; // Data Register
|
||||
constexpr unsigned int REG_FR = 0x18U; // Flag Register
|
||||
constexpr unsigned int REG_IBRD = 0x24U; // Integer Baud Rate Divisor
|
||||
constexpr unsigned int REG_FBRD = 0x28U; // Fractional Baud Rate Divisor
|
||||
constexpr unsigned int REG_LCR_H = 0x2CU; // Line Control Register
|
||||
constexpr unsigned int REG_CR = 0x30U; // Control Register
|
||||
constexpr unsigned int REG_IMSC = 0x38U; // Interrupt Mask Set/Clear
|
||||
constexpr unsigned int REG_ICR = 0x44U; // Interrupt Clear Register
|
||||
|
||||
constexpr unsigned int FR_TXFF = 1U << 5; // Transmit FIFO full
|
||||
constexpr unsigned int CR_UARTEN = 1U << 0; // UART enable
|
||||
constexpr unsigned int CR_TXE = 1U << 8; // Transmit enable
|
||||
constexpr unsigned int CR_RXE = 1U << 9; // Receive enable
|
||||
constexpr unsigned int LCR_H_WLEN_8 = 3U << 5; // 8 data bits
|
||||
constexpr unsigned int LCR_H_FEN = 1U << 4; // Enable FIFOs
|
||||
|
||||
inline volatile unsigned int ®(unsigned int offset)
|
||||
{
|
||||
return *reinterpret_cast<volatile unsigned int *>(UART0_BASE + offset);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void init()
|
||||
{
|
||||
// Disable UART while configuring.
|
||||
reg(REG_CR) = 0U;
|
||||
|
||||
// Clear pending interrupts.
|
||||
reg(REG_ICR) = 0x7FFU;
|
||||
|
||||
// 8 data bits, no parity, one stop bit, FIFO enabled.
|
||||
reg(REG_LCR_H) = LCR_H_WLEN_8 | LCR_H_FEN;
|
||||
|
||||
// Baud rate divisor for 115200 with a 24 MHz UARTCLK.
|
||||
// QEMU ignores the actual baud value, but a valid divisor is required.
|
||||
reg(REG_IBRD) = 13U;
|
||||
reg(REG_FBRD) = 1U;
|
||||
|
||||
// Enable UART, TX and RX.
|
||||
reg(REG_CR) = CR_UARTEN | CR_TXE | CR_RXE;
|
||||
}
|
||||
|
||||
void putc(char c)
|
||||
{
|
||||
while ((reg(REG_FR) & FR_TXFF) != 0U) {
|
||||
// Wait until the transmit FIFO is not full.
|
||||
}
|
||||
reg(REG_DR) = static_cast<unsigned int>(c);
|
||||
}
|
||||
|
||||
void puts(const char *s)
|
||||
{
|
||||
while (*s != '\0') {
|
||||
putc(*s++);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace universalisos::uart
|
||||
|
|
@ -1,12 +1,16 @@
|
|||
/*
|
||||
* PL011 UART driver header for QEMU ARM virt machine.
|
||||
* PL011 UART driver 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);
|
||||
namespace universalisos::uart {
|
||||
|
||||
void init();
|
||||
void putc(char c);
|
||||
void puts(const char *s);
|
||||
|
||||
} // namespace universalisos::uart
|
||||
|
||||
#endif /* UNIVERSALISOS_UART_H */
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* 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");
|
||||
}
|
||||
}
|
||||
17
kernel/kernel.cpp
Normal file
17
kernel/kernel.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Universalisos kernel entry point.
|
||||
*/
|
||||
|
||||
#include "arch/arm/uart.h"
|
||||
|
||||
extern "C" void kernel_main(void)
|
||||
{
|
||||
universalisos::uart::init();
|
||||
universalisos::uart::puts("Universalisos type-1 hypervisor booted.\r\n");
|
||||
universalisos::uart::puts("Stage 1: bare-metal C++ skeleton running on QEMU ARM virt.\r\n");
|
||||
|
||||
/* Idle loop. */
|
||||
for (;;) {
|
||||
__asm__ __volatile__("wfi");
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue