feat(arch): Add armv8i (32-bit ARM/AArch32) architecture & complete TUI configurator

- Support ARMv8i / ARM32 (AArch32) baremetal target with arm-linux-gnueabihf toolchain
- Implement ARMv8i boot entry point, banked exception mode stacks (IRQ, ABT, UND, SVC)
- Implement 8 exception vectors, GICv2 distributor/CPU interface, CP15 Generic Timer (100 Hz), flat Section MMU
- Support PL011 UART for early console & interactive LazyBox TTY input
- Update Makefile with make armv8i_defconfig and automated cross-compilation
- Update scripts/kconfig/menuconfig.py with dedicated armv8i options
This commit is contained in:
subhobhai943 committed 2026-08-18 11:13:23 +05:30
1 parent 70d5925b16
commit 7b646c8cc4
30 files changed
+964 -24

No files matched your search

+40 -7
View File
@@ -46,7 +46,6 @@ ifeq ($(ARCH), x86_64)
ASMFLAGS_BOOT = -f bin -I$(BOOT_DIR)/
LDFLAGS = -nostdlib -no-pie -T linker.ld
# Source files for x86_64
ARCH_C_SRCS = $(shell find arch/x86_64 -name '*.c' 2>/dev/null)
ARCH_ASM_SRCS = $(shell find arch/x86_64 -name '*.asm' 2>/dev/null)
ENTRY_OBJ = $(BUILD_DIR)/arch/x86_64/boot/entry.o
@@ -56,7 +55,7 @@ ifeq ($(ARCH), x86_64)
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \
-device e1000,netdev=net0 -serial stdio
else ifneq ($(filter $(ARCH), aarch64 armv8 armv8i),)
else ifneq ($(filter $(ARCH), aarch64 arm64),)
CROSS_COMPILE ?= aarch64-linux-gnu-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
@@ -78,13 +77,43 @@ else ifneq ($(filter $(ARCH), aarch64 armv8 armv8i),)
LDFLAGS = -nostdlib -no-pie -T arch/aarch64/linker.ld
# Source files for AArch64
ARCH_C_SRCS = $(shell find arch/aarch64 -name '*.c' 2>/dev/null)
ARCH_S_SRCS = $(shell find arch/aarch64 -name '*.S' 2>/dev/null)
ENTRY_OBJ = $(BUILD_DIR)/arch/aarch64/boot/entry.o
TARGET = $(BUILD_DIR)/kernel.elf
QEMU_CMD = qemu-system-aarch64 -M virt -cpu cortex-a57 -m 128M -nographic -kernel $(BUILD_DIR)/kernel.elf
else ifneq ($(filter $(ARCH), armv8i arm32 arm),)
CROSS_COMPILE ?= arm-linux-gnueabihf-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
AS = $(CROSS_COMPILE)as
CFLAGS = -ffreestanding \
-fno-pie \
-fno-pic \
-Wall \
-Wextra \
-Wno-unused-function \
-Wno-unused-parameter \
-O2 \
-Iinclude \
-D__arm__ \
-D__armv8i__ \
-mcpu=cortex-a15 \
-mfpu=neon-vfpv4 \
-mfloat-abi=hard \
-marm
LDFLAGS = -nostdlib -no-pie -T arch/armv8i/linker.ld
ARCH_C_SRCS = $(shell find arch/armv8i -name '*.c' 2>/dev/null)
ARCH_S_SRCS = $(shell find arch/armv8i -name '*.S' 2>/dev/null)
ENTRY_OBJ = $(BUILD_DIR)/arch/armv8i/boot/entry.o
TARGET = $(BUILD_DIR)/kernel.elf
QEMU_CMD = qemu-system-arm -M virt -cpu cortex-a15 -m 128M -nographic -kernel $(BUILD_DIR)/kernel.elf
else
$(error Unsupported Architecture '$(ARCH)'. Supported: x86_64, aarch64, armv8i)
endif
@@ -145,7 +174,7 @@ x86_64_defconfig:
aarch64_defconfig:
@python3 scripts/kconfig/menuconfig.py --aarch64
armv8_defconfig armv8i_defconfig:
armv8_defconfig armv8i_defconfig arm32_defconfig:
@python3 scripts/kconfig/menuconfig.py --armv8i
# -----------------------------------------------------------------------------
@@ -161,7 +190,7 @@ $(BUILD_DIR)/%.o: %.asm
@mkdir -p $(dir $@)
$(ASM) $(ASMFLAGS_ELF) $< -o $@
# AArch64 GNU Assembly Files (.S)
# ARM/AArch64 GNU Assembly Files (.S)
$(BUILD_DIR)/%.o: %.S
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@
@@ -178,8 +207,10 @@ $(BUILD_DIR)/boot/stage2.bin: $(BOOT_DIR)/stage2.asm $(BOOT_DIR)/gdt.asm | $(BUI
$(BUILD_DIR)/boot:
mkdir -p $(BUILD_DIR)/boot
LIBGCC ?= $(shell $(CC) $(CFLAGS) -print-libgcc-file-name 2>/dev/null)
$(BUILD_DIR)/kernel.elf: $(ENTRY_OBJ) $(OTHER_OBJS)
$(LD) $(LDFLAGS) -o $@ $(ENTRY_OBJ) $(OTHER_OBJS)
$(LD) $(LDFLAGS) -o $@ $(ENTRY_OBJ) $(OTHER_OBJS) $(LIBGCC)
@echo "=== [Kernel ELF Linked: $@ (Architecture: $(ARCH))] ==="
$(BUILD_DIR)/kernel.bin: $(BUILD_DIR)/kernel.elf
@@ -208,8 +239,10 @@ ifeq ($(ARCH), x86_64)
qemu-system-x86_64 -drive format=raw,file=$(IMAGE) \
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \
-device e1000,netdev=net0 -serial stdio -s -S
else
else ifneq ($(filter $(ARCH), aarch64 arm64),)
qemu-system-aarch64 -M virt -cpu cortex-a57 -m 128M -nographic -kernel $(BUILD_DIR)/kernel.elf -s -S
else
qemu-system-arm -M virt -cpu cortex-a15 -m 128M -nographic -kernel $(BUILD_DIR)/kernel.elf -s -S
endif
info:
+61
View File
@@ -0,0 +1,61 @@
/*
* SUB-OS ARMv8i (AArch32 / 32-Bit ARMv8) Bootstrap Entry Point
*/
.syntax unified
.arm
.section ".text.boot"
.global _start
.global armv8i_entry
_start:
armv8i_entry:
// 1. Enable VFP and NEON Coprocessors (CP10 & CP11 Full Access)
mrc p15, 0, r0, c1, c0, 2 // Read CPACR
orr r0, r0, #(0xF << 20) // Enable CP10 and CP11
mcr p15, 0, r0, c1, c0, 2 // Write CPACR
isb
// Enable VFP extension run (FPEXC.EN = 1)
mov r0, #(1 << 30)
vmsr fpexc, r0
// 2. Clear SCTLR.V bit (bit 13) to use VBAR for exception vectors
mrc p15, 0, r0, c1, c0, 0 // Read SCTLR
bic r0, r0, #(1 << 13) // Clear Hivecs (V=0)
mcr p15, 0, r0, c1, c0, 0 // Write SCTLR
isb
// 3. Set Vector Base Address Register (VBAR)
ldr r0, =vectors
mcr p15, 0, r0, c12, c0, 0 // Write VBAR
isb
// 4. Setup Banked Stack Pointers for Exception Modes
cpsid if, #0x12 // Switch to IRQ mode
ldr sp, =irq_stack_top
cpsid if, #0x17 // Switch to Abort mode
ldr sp, =abt_stack_top
cpsid if, #0x1B // Switch to Undefined mode
ldr sp, =und_stack_top
cpsid if, #0x13 // Switch back to Supervisor mode (SVC)
ldr sp, =stack_top
// 5. Zero out BSS section
ldr r0, =__bss_start
ldr r1, =__bss_end
mov r2, #0
.bss_loop:
cmp r0, r1
strlt r2, [r0], #4
blt .bss_loop
// 6. Branch to ARMv8i C Kernel Entry
bl kernel_main_armv8i
.hang:
wfi
b .hang
+37
View File
@@ -0,0 +1,37 @@
#
# Automatically generated by SUB-OS Kconfig for armv8i
#
CONFIG_ARCH=armv8i
CONFIG_ARCH_ARMV8I=y
# CONFIG_ARCH_X86_64 is not set
# CONFIG_ARCH_AARCH64 is not set
CONFIG_BPF_VM=y
CONFIG_DRV_CANVAS_2D=y
CONFIG_DRV_PTY=y
CONFIG_DRV_RAMDISK=y
CONFIG_DRV_VIRTIO_BLK=y
CONFIG_DRV_VIRTIO_NET=y
CONFIG_DRV_VIRTIO_RNG=y
CONFIG_FS_DEVFS=y
CONFIG_FS_EXT2=y
CONFIG_FS_FAT32=y
CONFIG_FS_PROCFS=y
CONFIG_FS_RAMFS=y
CONFIG_FS_SYSFS=y
CONFIG_FS_VFS=y
CONFIG_IO_URING=y
CONFIG_MM_PMM=y
CONFIG_MM_SLAB=y
CONFIG_MM_VMA=y
CONFIG_NET_FILTER=y
CONFIG_NET_HTTPD=y
CONFIG_NET_SSHD=y
CONFIG_NET_STACK=y
CONFIG_OPTIMIZATION="-O2"
CONFIG_PREEMPT=y
CONFIG_SECURITY_KEYRING=y
CONFIG_SECURITY_LSM=y
CONFIG_SMP=y
CONFIG_SUBOS_HOSTNAME="sub-os"
CONFIG_SUBOS_VERSION="0.2.0-lts"
CONFIG_USERLAND_LAZYBOX=y
+60
View File
@@ -0,0 +1,60 @@
#include <arch/arch.h>
#include <arch/armv8i/cpu.h>
#include <arch/armv8i/gic.h>
#include <arch/armv8i/timer.h>
#include <arch/armv8i/uart.h>
#include <arch/armv8i/mmu.h>
#include <arch/x86_64/cpuid.h>
#include <kernel/printk.h>
#include <lib/string.h>
static cpu_info_t armv8i_compat_cpu;
void arch_early_init(void) {
uart_pl011_init();
armv8i_mmu_init();
}
void arch_init(void) {
armv8i_cpu_init();
gic_init();
armv8i_timer_init(100);
// Populate compatibility CPU info structure for procfs / uname
memset(&armv8i_compat_cpu, 0, sizeof(armv8i_compat_cpu));
const armv8i_cpu_info_t* info = armv8i_get_cpu_info();
strncpy(armv8i_compat_cpu.vendor, "ARM Ltd", sizeof(armv8i_compat_cpu.vendor) - 1);
strncpy(armv8i_compat_cpu.model, info->model_name, sizeof(armv8i_compat_cpu.model) - 1);
armv8i_compat_cpu.has_fpu = true;
arch_enable_interrupts();
}
const char* arch_get_name(void) {
return "armv8i (AArch32)";
}
uint32_t arch_get_cpu_id(void) {
return armv8i_get_mpidr() & 0xFF;
}
// Timer Compatibility Layer
uint64_t pit_get_ticks(void) {
return armv8i_timer_get_ticks();
}
void pit_sleep(uint32_t ms) {
uint64_t count = (ms > 10) ? (ms / 10) : 1;
uint64_t target = armv8i_timer_get_ticks() + count;
while (armv8i_timer_get_ticks() < target) {
__asm__ volatile("wfi");
}
}
// Stubs for x86-specific driver compatibility
void isr_register_handler(uint8_t isr, void* handler) { (void)isr; (void)handler; }
void pic_clear_mask(uint8_t irq) { (void)irq; }
const cpu_info_t* cpuid_get_info(void) {
return &armv8i_compat_cpu;
}
+41
View File
@@ -0,0 +1,41 @@
#include <arch/armv8i/cpu.h>
#include <lib/string.h>
#include <kernel/printk.h>
static armv8i_cpu_info_t global_cpu_info;
uint32_t armv8i_get_midr(void) {
uint32_t midr;
__asm__ volatile("mrc p15, 0, %0, c0, c0, 0" : "=r"(midr));
return midr;
}
uint32_t armv8i_get_mpidr(void) {
uint32_t mpidr;
__asm__ volatile("mrc p15, 0, %0, c0, c0, 5" : "=r"(mpidr));
return mpidr;
}
void armv8i_cpu_init(void) {
memset(&global_cpu_info, 0, sizeof(global_cpu_info));
global_cpu_info.midr = armv8i_get_midr();
global_cpu_info.mpidr = armv8i_get_mpidr();
global_cpu_info.implementer = (global_cpu_info.midr >> 24) & 0xFF;
global_cpu_info.part_number = (global_cpu_info.midr >> 4) & 0xFFF;
global_cpu_info.architecture = (global_cpu_info.midr >> 16) & 0xF;
const char* part_str = "ARM Cortex-A (ARMv8i 32-Bit)";
if (global_cpu_info.part_number == 0xC0F) part_str = "ARM Cortex-A15 (ARMv7-A/v8i)";
else if (global_cpu_info.part_number == 0xC07) part_str = "ARM Cortex-A7 (ARMv7-A/v8i)";
else if (global_cpu_info.part_number == 0xD03) part_str = "ARM Cortex-A53 (AArch32)";
else if (global_cpu_info.part_number == 0xD07) part_str = "ARM Cortex-A57 (AArch32)";
strncpy(global_cpu_info.model_name, part_str, sizeof(global_cpu_info.model_name) - 1);
printk(KERN_INFO "CPU: %s (Implementer: 0x%02x, Part: 0x%03x, AArch32)\n",
global_cpu_info.model_name, global_cpu_info.implementer, global_cpu_info.part_number);
}
const armv8i_cpu_info_t* armv8i_get_cpu_info(void) {
return &global_cpu_info;
}
+16
View File
@@ -0,0 +1,16 @@
/*
* SUB-OS ARMv8i Division-by-Zero and POSIX Signal Stub
*/
#include <stdint.h>
int raise(int sig) {
(void)sig;
return 0;
}
void __aeabi_idiv0(void) {
}
void __aeabi_ldiv0(void) {
}
+68
View File
@@ -0,0 +1,68 @@
#include <arch/armv8i/arch.h>
#include <arch/armv8i/gic.h>
#include <arch/armv8i/timer.h>
#include <arch/armv8i/uart.h>
#include <kernel/printk.h>
typedef struct {
uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12;
uint32_t lr;
uint32_t spsr;
} armv8i_registers_t;
static void hex_to_str(uint32_t val, char* out) {
const char hex_chars[] = "0123456789ABCDEF";
out[0] = '0'; out[1] = 'x';
for (int i = 7; i >= 0; i--) {
out[2 + (7 - i)] = hex_chars[(val >> (i * 4)) & 0xF];
}
out[10] = '\0';
}
void armv8i_undef_handler(armv8i_registers_t* regs) {
char buf[16];
hex_to_str(regs->lr, buf);
uart_pl011_puts("\n[KERNEL PANIC] ARMv8i Undefined Instruction at PC=");
uart_pl011_puts(buf);
uart_pl011_puts("\n");
while (1) { __asm__ volatile("wfi"); }
}
void armv8i_svc_handler(armv8i_registers_t* regs) {
(void)regs;
}
void armv8i_pabt_handler(armv8i_registers_t* regs) {
char buf[16];
hex_to_str(regs->lr, buf);
uart_pl011_puts("\n[KERNEL PANIC] ARMv8i Prefetch Abort at PC=");
uart_pl011_puts(buf);
uart_pl011_puts("\n");
while (1) { __asm__ volatile("wfi"); }
}
void armv8i_dabt_handler(armv8i_registers_t* regs) {
char buf[16];
hex_to_str(regs->lr, buf);
uart_pl011_puts("\n[KERNEL PANIC] ARMv8i Data Abort at PC=");
uart_pl011_puts(buf);
uart_pl011_puts("\n");
while (1) { __asm__ volatile("wfi"); }
}
void armv8i_irq_handler(armv8i_registers_t* regs) {
(void)regs;
uint32_t iar = *(volatile uint32_t*)GICC_IAR;
uint32_t irq = iar & 0x3FF;
if (irq < 1020) {
if (irq == ARMV8I_TIMER_VIRT_IRQ) {
armv8i_timer_handle_irq();
}
*(volatile uint32_t*)GICC_EOIR = iar;
}
}
void armv8i_fiq_handler(armv8i_registers_t* regs) {
(void)regs;
}
+62
View File
@@ -0,0 +1,62 @@
#include <arch/armv8i/gic.h>
#include <arch/armv8i/io.h>
#include <kernel/printk.h>
void gic_init(void) {
// 1. Disable Distributor and CPU interface during configuration
mmio_write32(GICD_CTLR, 0);
mmio_write32(GICC_CTLR, 0);
// 2. Query lines count (TYPER ITLinesNumber)
uint32_t typer = mmio_read32(GICD_TYPER);
uint32_t lines = 32 * ((typer & 0x1F) + 1);
// 3. Disable all interrupts & clear pending
for (uint32_t i = 0; i < lines / 32; i++) {
mmio_write32(GICD_ICENABLER(i), 0xFFFFFFFF);
mmio_write32(GICD_ICPENDR(i), 0xFFFFFFFF);
}
// 4. Default priority 0xA0 and target CPU 0 (0x01)
for (uint32_t i = 0; i < lines / 4; i++) {
mmio_write32(GICD_IPRIORITYR(i), 0xA0A0A0A0);
}
for (uint32_t i = 8; i < lines / 4; i++) {
mmio_write32(GICD_ITARGETSR(i), 0x01010101);
}
// 5. Enable Distributor (Group 0 & 1)
mmio_write32(GICD_CTLR, 3);
// 6. Set CPU Interface Priority Mask to allow all interrupts (0xF0)
mmio_write32(GICC_PMR, 0xF0);
// 7. Enable CPU Interface (Group 0 & 1)
mmio_write32(GICC_CTLR, 3);
// 8. Unmask Virtual Timer PPI 27
gic_enable_irq(27);
printk(KERN_INFO "GIC: ARM Generic Interrupt Controller v2 initialized (%u IRQ lines)\n", lines);
}
void gic_enable_irq(uint32_t irq) {
uint32_t reg_idx = irq / 32;
uint32_t bit_idx = irq % 32;
mmio_write32(GICD_ISENABLER(reg_idx), (1 << bit_idx));
}
void gic_disable_irq(uint32_t irq) {
uint32_t reg_idx = irq / 32;
uint32_t bit_idx = irq % 32;
mmio_write32(GICD_ICENABLER(reg_idx), (1 << bit_idx));
}
void gic_set_priority(uint32_t irq, uint8_t prio) {
uint32_t reg_idx = irq / 4;
uint32_t shift = (irq % 4) * 8;
uint32_t val = mmio_read32(GICD_IPRIORITYR(reg_idx));
val &= ~(0xFF << shift);
val |= ((uint32_t)prio << shift);
mmio_write32(GICD_IPRIORITYR(reg_idx), val);
}
+45
View File
@@ -0,0 +1,45 @@
#include <arch/armv8i/timer.h>
#include <arch/armv8i/gic.h>
#include <kernel/timer.h>
#include <kernel/printk.h>
static volatile uint64_t armv8i_timer_ticks = 0;
static uint32_t timer_freq = 0;
static uint32_t tick_interval = 0;
uint64_t armv8i_timer_get_ticks(void) {
return armv8i_timer_ticks;
}
uint64_t armv8i_timer_get_frequency(void) {
return timer_freq;
}
void armv8i_timer_handle_irq(void) {
armv8i_timer_ticks++;
// Reset comparator for next tick
__asm__ volatile("mcr p15, 0, %0, c14, c3, 0" :: "r"(tick_interval));
timer_tick();
}
void armv8i_timer_init(uint32_t freq_hz) {
// 1. Read base counter frequency (CNTFRQ)
__asm__ volatile("mrc p15, 0, %0, c14, c0, 0" : "=r"(timer_freq));
if (timer_freq == 0) {
timer_freq = 62500000; // 62.5 MHz default in QEMU virt
}
tick_interval = timer_freq / (freq_hz ? freq_hz : 100);
// 2. Set interval in CNTV_TVAL
__asm__ volatile("mcr p15, 0, %0, c14, c3, 0" :: "r"(tick_interval));
// 3. Enable Virtual Timer (ENABLE=1, IMASK=0 in CNTV_CTL)
uint32_t ctl = 1;
__asm__ volatile("mcr p15, 0, %0, c14, c3, 1" :: "r"(ctl));
printk(KERN_INFO "Timer: ARM Generic Arch Timer active (%u Hz, Base Clock: %u MHz)\n",
freq_hz, timer_freq / 1000000);
}
+87
View File
@@ -0,0 +1,87 @@
/*
* SUB-OS ARMv8i (AArch32) Exception Vector Table
*/
.syntax unified
.arm
.section ".vectors", "ax"
.align 5
.global vectors
vectors:
ldr pc, =reset_handler
ldr pc, =undef_handler
ldr pc, =svc_handler
ldr pc, =pabt_handler
ldr pc, =dabt_handler
ldr pc, =hyp_handler
ldr pc, =irq_handler
ldr pc, =fiq_handler
.macro SAVE_REGS
sub sp, sp, #72
stmia sp, {r0 - r12}
str lr, [sp, #52]
mrs r0, spsr
str r0, [sp, #56]
.endm
.macro RESTORE_REGS
ldr r0, [sp, #56]
msr spsr_cxsf, r0
ldr lr, [sp, #52]
ldmia sp, {r0 - r12}
add sp, sp, #72
.endm
reset_handler:
b _start
undef_handler:
SAVE_REGS
mov r0, sp
bl armv8i_undef_handler
RESTORE_REGS
movs pc, lr
svc_handler:
SAVE_REGS
mov r0, sp
bl armv8i_svc_handler
RESTORE_REGS
movs pc, lr
pabt_handler:
sub lr, lr, #4
SAVE_REGS
mov r0, sp
bl armv8i_pabt_handler
RESTORE_REGS
movs pc, lr
dabt_handler:
sub lr, lr, #8
SAVE_REGS
mov r0, sp
bl armv8i_dabt_handler
RESTORE_REGS
movs pc, lr
hyp_handler:
b .
irq_handler:
sub lr, lr, #4
SAVE_REGS
mov r0, sp
bl armv8i_irq_handler
RESTORE_REGS
movs pc, lr
fiq_handler:
sub lr, lr, #4
SAVE_REGS
mov r0, sp
bl armv8i_fiq_handler
RESTORE_REGS
movs pc, lr
+38
View File
@@ -0,0 +1,38 @@
#include <arch/armv8i/uart.h>
#include <arch/armv8i/io.h>
void uart_pl011_init(void) {
// Enable UART, TX, and RX (bits 0, 8, 9)
mmio_write32(PL011_UART0_BASE + UARTCR, (1 << 0) | (1 << 8) | (1 << 9));
}
void uart_pl011_putc(char c) {
if (c == '\n') {
while (mmio_read32(PL011_UART0_BASE + UARTFR) & UARTFR_TXFF) {
__asm__ volatile("nop");
}
mmio_write32(PL011_UART0_BASE + UARTDR, '\r');
}
while (mmio_read32(PL011_UART0_BASE + UARTFR) & UARTFR_TXFF) {
__asm__ volatile("nop");
}
mmio_write32(PL011_UART0_BASE + UARTDR, (uint32_t)(uint8_t)c);
}
void uart_pl011_puts(const char* str) {
if (!str) return;
while (*str) {
uart_pl011_putc(*str++);
}
}
char uart_pl011_getc(void) {
while (mmio_read32(PL011_UART0_BASE + UARTFR) & UARTFR_RXFE) {
__asm__ volatile("wfe");
}
return (char)(mmio_read32(PL011_UART0_BASE + UARTDR) & 0xFF);
}
int uart_pl011_has_data(void) {
return !(mmio_read32(PL011_UART0_BASE + UARTFR) & UARTFR_RXFE);
}
+51
View File
@@ -0,0 +1,51 @@
OUTPUT_FORMAT("elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x40080000;
__kernel_start = .;
.text.boot : {
KEEP(*(.text.boot))
}
.vectors : ALIGN(2048) {
KEEP(*(.vectors))
}
.text : ALIGN(4096) {
*(.text .text.*)
}
.rodata : ALIGN(4096) {
*(.rodata .rodata.*)
}
.data : ALIGN(4096) {
*(.data .data.*)
}
.bss : ALIGN(4096) {
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4096);
__bss_end = .;
}
.stack : ALIGN(4096) {
. += 0x4000; /* 16 KB IRQ Stack */
irq_stack_top = .;
. += 0x2000; /* 8 KB ABT Stack */
abt_stack_top = .;
. += 0x2000; /* 8 KB UND Stack */
und_stack_top = .;
. += 0x10000; /* 64 KB SVC Kernel Stack */
stack_top = .;
}
__kernel_end = .;
}
+42
View File
@@ -0,0 +1,42 @@
#include <arch/armv8i/mmu.h>
#include <arch/armv8i/io.h>
#include <lib/string.h>
#include <kernel/printk.h>
static uint32_t __attribute__((aligned(16384))) l1_page_table[4096];
void armv8i_mmu_init(void) {
// 1. Identity map the entire 4GB flat space with 1MB sections
for (uint32_t i = 0; i < 4096; i++) {
uint32_t phys = i * 0x100000;
l1_page_table[i] = phys | (3 << 10) | (2 << 0);
}
// 2. Set Domain Access Control Register (DACR = 0xFFFFFFFF: All Manager)
uint32_t dacr = 0xFFFFFFFF;
__asm__ volatile("mcr p15, 0, %0, c3, c0, 0" :: "r"(dacr));
// 3. Set Translation Table Base Control Register (TTBCR = 0)
uint32_t ttbcr = 0;
__asm__ volatile("mcr p15, 0, %0, c2, c0, 2" :: "r"(ttbcr));
// 4. Set Translation Table Base Register 0 (TTBR0)
uint32_t ttbr0 = (uint32_t)l1_page_table;
__asm__ volatile("mcr p15, 0, %0, c2, c0, 0" :: "r"(ttbr0));
// 5. Invalidate TLB & ICache
uint32_t zero = 0;
__asm__ volatile("mcr p15, 0, %0, c8, c7, 0" :: "r"(zero));
__asm__ volatile("mcr p15, 0, %0, c7, c5, 0" :: "r"(zero));
isb();
dsb();
// 6. Enable MMU and Branch Prediction in SCTLR
uint32_t sctlr;
__asm__ volatile("mrc p15, 0, %0, c1, c0, 0" : "=r"(sctlr));
sctlr |= (1 << 0) | (1 << 11);
__asm__ volatile("mcr p15, 0, %0, c1, c0, 0" :: "r"(sctlr));
isb();
dsb();
}
+4 -2
View File
@@ -125,10 +125,12 @@ void keyboard_init(void) {
#if defined(__aarch64__)
#include <arch/aarch64/uart.h>
#elif defined(__arm__) || defined(__armv8i__)
#include <arch/armv8i/uart.h>
#endif
bool keyboard_has_key(void) {
#if defined(__aarch64__)
#if defined(__aarch64__) || defined(__arm__) || defined(__armv8i__)
if (uart_pl011_has_data()) return true;
#endif
return buffer_head != buffer_tail;
@@ -138,7 +140,7 @@ uint16_t keyboard_get_key(void) {
while (!keyboard_has_key()) {
arch_halt();
}
#if defined(__aarch64__)
#if defined(__aarch64__) || defined(__arm__) || defined(__armv8i__)
if (uart_pl011_has_data()) {
char c = uart_pl011_getc();
if (c == '\r') c = '\n';
+42 -1
View File
@@ -79,7 +79,48 @@ static inline void arch_sleep(uint32_t ms) {
}
}
// Prototype declarations for timer/interrupt compatibility
uint64_t pit_get_ticks(void);
void pit_sleep(uint32_t ms);
#elif defined(__arm__) || defined(__armv8i__)
#define ARCH_NAME "armv8i"
#define ARCH_IS_64BIT 0
#include <arch/armv8i/arch.h>
#include <arch/armv8i/cpu.h>
#include <arch/armv8i/gic.h>
#include <arch/armv8i/timer.h>
#include <arch/armv8i/mmu.h>
#include <arch/armv8i/uart.h>
#include <arch/armv8i/io.h>
static inline void arch_enable_interrupts(void) {
__asm__ volatile("cpsie i" ::: "memory");
}
static inline void arch_disable_interrupts(void) {
__asm__ volatile("cpsid i" ::: "memory");
}
static inline void arch_halt(void) {
__asm__ volatile("wfi");
}
static inline void arch_wait_for_interrupt(void) {
__asm__ volatile("cpsie i; wfi" ::: "memory");
}
static inline uint64_t arch_get_ticks(void) {
return armv8i_timer_get_ticks();
}
static inline void arch_sleep(uint32_t ms) {
uint64_t count = (ms > 10) ? (ms / 10) : 1;
uint64_t target = armv8i_timer_get_ticks() + count;
while (armv8i_timer_get_ticks() < target) {
__asm__ volatile("wfi");
}
}
uint64_t pit_get_ticks(void);
void pit_sleep(uint32_t ms);
+23
View File
@@ -0,0 +1,23 @@
#ifndef _ARCH_ARMV8I_ARCH_H
#define _ARCH_ARMV8I_ARCH_H
#include <stdint.h>
#include <stdbool.h>
#define ARMV8I_PAGE_SIZE 4096
// Mode bits in CPSR
#define CPSR_MODE_USR 0x10
#define CPSR_MODE_FIQ 0x11
#define CPSR_MODE_IRQ 0x12
#define CPSR_MODE_SVC 0x13
#define CPSR_MODE_MON 0x16
#define CPSR_MODE_ABT 0x17
#define CPSR_MODE_HYP 0x1A
#define CPSR_MODE_UND 0x1B
#define CPSR_MODE_SYS 0x1F
#define CPSR_IRQ_DISABLE (1 << 7)
#define CPSR_FIQ_DISABLE (1 << 6)
#endif // _ARCH_ARMV8I_ARCH_H
+21
View File
@@ -0,0 +1,21 @@
#ifndef _ARCH_ARMV8I_CPU_H
#define _ARCH_ARMV8I_CPU_H
#include <stdint.h>
#include <stdbool.h>
typedef struct {
uint32_t midr;
uint32_t mpidr;
uint32_t implementer;
uint32_t part_number;
uint32_t architecture;
char model_name[64];
} armv8i_cpu_info_t;
void armv8i_cpu_init(void);
const armv8i_cpu_info_t* armv8i_get_cpu_info(void);
uint32_t armv8i_get_midr(void);
uint32_t armv8i_get_mpidr(void);
#endif // _ARCH_ARMV8I_CPU_H
+37
View File
@@ -0,0 +1,37 @@
#ifndef _ARCH_ARMV8I_GIC_H
#define _ARCH_ARMV8I_GIC_H
#include <stdint.h>
#include <stdbool.h>
#define GICD_BASE 0x08000000
#define GICC_BASE 0x08010000
// Distributor Registers
#define GICD_CTLR (GICD_BASE + 0x000)
#define GICD_TYPER (GICD_BASE + 0x004)
#define GICD_IIDR (GICD_BASE + 0x008)
#define GICD_ISENABLER(n) (GICD_BASE + 0x100 + ((n) * 4))
#define GICD_ICENABLER(n) (GICD_BASE + 0x180 + ((n) * 4))
#define GICD_ISPENDR(n) (GICD_BASE + 0x200 + ((n) * 4))
#define GICD_ICPENDR(n) (GICD_BASE + 0x280 + ((n) * 4))
#define GICD_IPRIORITYR(n) (GICD_BASE + 0x400 + ((n) * 4))
#define GICD_ITARGETSR(n) (GICD_BASE + 0x800 + ((n) * 4))
#define GICD_ICFGR(n) (GICD_BASE + 0xC00 + ((n) * 4))
// CPU Interface Registers
#define GICC_CTLR (GICC_BASE + 0x000)
#define GICC_PMR (GICC_BASE + 0x004)
#define GICC_BPR (GICC_BASE + 0x008)
#define GICC_IAR (GICC_BASE + 0x00C)
#define GICC_EOIR (GICC_BASE + 0x010)
typedef void (*gic_irq_handler_t)(uint32_t irq);
void gic_init(void);
void gic_enable_irq(uint32_t irq);
void gic_disable_irq(uint32_t irq);
void gic_set_priority(uint32_t irq, uint8_t prio);
void gic_register_handler(uint32_t irq, gic_irq_handler_t handler);
#endif // _ARCH_ARMV8I_GIC_H
+75
View File
@@ -0,0 +1,75 @@
#ifndef _ARCH_ARMV8I_IO_H
#define _ARCH_ARMV8I_IO_H
#include <stdint.h>
static inline void mmio_write8(uintptr_t reg, uint8_t val) {
*(volatile uint8_t*)reg = val;
}
static inline uint8_t mmio_read8(uintptr_t reg) {
return *(volatile uint8_t*)reg;
}
static inline void mmio_write16(uintptr_t reg, uint16_t val) {
*(volatile uint16_t*)reg = val;
}
static inline uint16_t mmio_read16(uintptr_t reg) {
return *(volatile uint16_t*)reg;
}
static inline void mmio_write32(uintptr_t reg, uint32_t val) {
*(volatile uint32_t*)reg = val;
}
static inline uint32_t mmio_read32(uintptr_t reg) {
return *(volatile uint32_t*)reg;
}
static inline void mmio_write64(uintptr_t reg, uint64_t val) {
*(volatile uint32_t*)reg = (uint32_t)(val & 0xFFFFFFFF);
*(volatile uint32_t*)(reg + 4) = (uint32_t)(val >> 32);
}
static inline uint64_t mmio_read64(uintptr_t reg) {
uint32_t low = *(volatile uint32_t*)reg;
uint32_t high = *(volatile uint32_t*)(reg + 4);
return ((uint64_t)high << 32) | low;
}
// Memory barriers
static inline void dsb(void) {
__asm__ volatile("dsb" ::: "memory");
}
static inline void dmb(void) {
__asm__ volatile("dmb" ::: "memory");
}
static inline void isb(void) {
__asm__ volatile("isb" ::: "memory");
}
// x86 Port I/O Stubs
static inline void outb(uint16_t port, uint8_t val) { (void)port; (void)val; }
static inline uint8_t inb(uint16_t port) { (void)port; return 0; }
static inline void outw(uint16_t port, uint16_t val) { (void)port; (void)val; }
static inline uint16_t inw(uint16_t port) { (void)port; return 0; }
static inline void outl(uint16_t port, uint32_t val) { (void)port; (void)val; }
static inline uint32_t inl(uint16_t port) { (void)port; return 0; }
static inline void io_wait(void) { __asm__ volatile("nop"); }
static inline void cli(void) {
__asm__ volatile("cpsid i" ::: "memory");
}
static inline void sti(void) {
__asm__ volatile("cpsie i" ::: "memory");
}
static inline void hlt(void) {
__asm__ volatile("wfi");
}
#endif // _ARCH_ARMV8I_IO_H
+20
View File
@@ -0,0 +1,20 @@
#ifndef _ARCH_ARMV8I_MMU_H
#define _ARCH_ARMV8I_MMU_H
#include <stdint.h>
// VMSAv7 1MB Section Descriptor Flags
#define SECTION_TYPE_MASK (3 << 0)
#define SECTION_TYPE_FAULT (0 << 0)
#define SECTION_TYPE_SECTION (2 << 0)
#define SECTION_BUFFERABLE (1 << 2)
#define SECTION_CACHEABLE (1 << 3)
#define SECTION_AP_RW_ALL (3 << 10)
#define SECTION_TEX_DEVICE (0 << 12)
#define SECTION_TEX_NORMAL (1 << 12)
#define SECTION_SHAREABLE (1 << 16)
#define SECTION_NON_GLOBAL (1 << 17)
void armv8i_mmu_init(void);
#endif // _ARCH_ARMV8I_MMU_H
+13
View File
@@ -0,0 +1,13 @@
#ifndef _ARCH_ARMV8I_TIMER_H
#define _ARCH_ARMV8I_TIMER_H
#include <stdint.h>
#define ARMV8I_TIMER_VIRT_IRQ 27
void armv8i_timer_init(uint32_t freq_hz);
uint64_t armv8i_timer_get_ticks(void);
uint64_t armv8i_timer_get_frequency(void);
void armv8i_timer_handle_irq(void);
#endif // _ARCH_ARMV8I_TIMER_H
+24
View File
@@ -0,0 +1,24 @@
#ifndef _ARCH_ARMV8I_UART_H
#define _ARCH_ARMV8I_UART_H
#include <stdint.h>
#define PL011_UART0_BASE 0x09000000
#define UARTDR 0x000
#define UARTRSR 0x004
#define UARTFR 0x018
#define UARTCR 0x030
#define UARTIMSC 0x038
#define UARTICR 0x044
#define UARTFR_TXFF (1 << 5)
#define UARTFR_RXFE (1 << 4)
void uart_pl011_init(void);
void uart_pl011_putc(char c);
void uart_pl011_puts(const char* str);
char uart_pl011_getc(void);
int uart_pl011_has_data(void);
#endif // _ARCH_ARMV8I_UART_H
+2 -2
View File
@@ -2,8 +2,8 @@
#ifndef _AUTOCONF_H
#define _AUTOCONF_H
#define CONFIG_ARCH "aarch64"
#define CONFIG_ARCH_AARCH64 1
#define CONFIG_ARCH "armv8i"
#define CONFIG_ARCH_ARMV8I 1
#define CONFIG_BPF_VM 1
#define CONFIG_DRV_AHCI 1
#define CONFIG_DRV_ATA 1
+4
View File
@@ -14,6 +14,10 @@
#define SUBOS_VERSION_STRING "0.2.0-lts (aarch64)"
#define SUBOS_BUILD_TARGET "aarch64-linux-gnu-baremetal"
#define SUBOS_COMPILER "aarch64-linux-gnu-gcc"
#elif defined(__arm__) || defined(__armv8i__)
#define SUBOS_VERSION_STRING "0.2.0-lts (armv8i)"
#define SUBOS_BUILD_TARGET "arm-linux-gnueabihf-baremetal"
#define SUBOS_COMPILER "arm-linux-gnueabihf-gcc"
#else
#define SUBOS_VERSION_STRING "0.2.0-lts (generic)"
#define SUBOS_BUILD_TARGET "generic-elf-baremetal"
+14 -6
View File
@@ -15,15 +15,23 @@ static inline void spinlock_init(spinlock_t* lock) {
}
static inline void spin_lock(spinlock_t* lock) {
while (__atomic_test_and_set(&lock->lock, __ATOMIC_ACQUIRE)) {
#if defined(__x86_64__)
while (__atomic_test_and_set(&lock->lock, __ATOMIC_ACQUIRE)) {
__asm__ volatile ("pause");
#elif defined(__aarch64__)
__asm__ volatile ("yield");
#else
__asm__ volatile ("");
#endif
}
#elif defined(__aarch64__)
while (__atomic_test_and_set(&lock->lock, __ATOMIC_ACQUIRE)) {
__asm__ volatile ("yield");
}
#elif defined(__arm__) || defined(__armv8i__)
while (__atomic_test_and_set(&lock->lock, __ATOMIC_ACQUIRE)) {
__asm__ volatile ("nop");
}
#else
while (__atomic_test_and_set(&lock->lock, __ATOMIC_ACQUIRE)) {
__asm__ volatile ("");
}
#endif
}
static inline void spin_unlock(spinlock_t* lock) {
+24
View File
@@ -258,4 +258,28 @@ void kernel_main_aarch64(void) {
subos_modular_core_boot();
}
#elif defined(__arm__) || defined(__armv8i__)
void kernel_main_armv8i(void) {
arch_early_init();
printk_init();
printk(ANSI_BRIGHT_CYAN "=================================================================\n" ANSI_RESET);
printk(ANSI_BRIGHT_CYAN " SUB-OS 32-Bit [%s] Modular Monolithic Kernel %s\n" ANSI_RESET, arch_get_name(), kernel_get_version());
printk(ANSI_BRIGHT_CYAN "=================================================================\n\n" ANSI_RESET);
init_early("root=/dev/vda console=ttyAMA0 init=/bin/lazybox quiet");
printk(KERN_INFO "[1/14] Initializing ARMv8i CPU, GICv2, Generic Timer & MMU... ");
arch_init();
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
printk(KERN_INFO "[2/14] Initializing Physical PMM, Dynamic Heap & SLAB Cache... ");
pmm_init(NULL, 0);
heap_init();
slab_init();
vma_init();
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
subos_modular_core_boot();
}
#endif
+2 -2
View File
@@ -45,8 +45,8 @@ int vprintk(const char* fmt, va_list args) {
// 1. Output to active TTY console
tty_write(display_ptr, (size_t)len);
// 2. Output to serial console (COM1 on x86, PL011 on AArch64)
#if defined(__aarch64__)
// 2. Output to serial console (COM1 on x86, PL011 on ARM/AArch64)
#if defined(__aarch64__) || defined(__arm__) || defined(__armv8i__)
extern void uart_pl011_putc(char c);
for (int i = 0; i < len; i++) {
uart_pl011_putc(display_ptr[i]);
+1 -1
View File
@@ -49,7 +49,7 @@ void pmm_init(void* memory_map, uint64_t memory_map_count) {
// Fallback if no E820 usable regions
if (usable_memory_bytes == 0 || total_pages == 0) {
#if defined(__aarch64__)
#if defined(__aarch64__) || defined(__arm__) || defined(__armv8i__)
uint64_t dram_start = 0x40000000;
uint64_t dram_size = 128ULL * 1024 * 1024;
uint64_t start_page = dram_start / PMM_PAGE_SIZE;
+6 -2
View File
@@ -355,10 +355,14 @@ def defconfig(arch="x86_64"):
cfg["CONFIG_ARCH_X86_64"] = True
cfg["CONFIG_ARCH_AARCH64"] = False
cfg["CONFIG_ARCH_ARMV8I"] = False
elif arch in ["aarch64", "armv8", "armv8i"]:
elif arch in ["aarch64", "arm64"]:
cfg["CONFIG_ARCH_X86_64"] = False
cfg["CONFIG_ARCH_AARCH64"] = True
cfg["CONFIG_ARCH_ARMV8I"] = (arch == "armv8i")
cfg["CONFIG_ARCH_ARMV8I"] = False
elif arch in ["armv8i", "arm32", "arm", "armv8"]:
cfg["CONFIG_ARCH_X86_64"] = False
cfg["CONFIG_ARCH_AARCH64"] = False
cfg["CONFIG_ARCH_ARMV8I"] = True
save_config(cfg)
print(f"*** Default configuration for '{arch}' written to {CONFIG_FILE} and {AUTOCONF_HEADER} ***")
+4 -1
View File
@@ -109,9 +109,12 @@ static void cmd_neofetch(void) {
#elif defined(__aarch64__)
const aarch64_cpu_info_t* cpu = aarch64_get_cpu_info();
printk(ANSI_BRIGHT_CYAN " \\___ \\| | | | _ < " ANSI_BRIGHT_GREEN "CPU: " ANSI_RESET "%s (EL%u)\n", cpu->model_name, cpu->current_el);
#elif defined(__arm__) || defined(__armv8i__)
const armv8i_cpu_info_t* cpu = armv8i_get_cpu_info();
printk(ANSI_BRIGHT_CYAN " \\___ \\| | | | _ < " ANSI_BRIGHT_GREEN "CPU: " ANSI_RESET "%s (AArch32)\n", cpu->model_name);
#endif
printk(ANSI_BRIGHT_CYAN " ____) | |__| | |_) | " ANSI_BRIGHT_GREEN "Memory: " ANSI_RESET "%llu MB / %llu MB (Free: %llu MB)\n", used_mb, total_mb, (free * 4096) / (1024 * 1024));
printk(ANSI_BRIGHT_CYAN " |_____/ \\____/|____/ " ANSI_BRIGHT_GREEN "Heap: " ANSI_RESET "%llu KB used / %llu KB total\n", heap_get_used_bytes() / 1024, (heap_get_used_bytes() + heap_get_free_bytes()) / 1024);
printk(ANSI_BRIGHT_CYAN " |_____/ \\____/|____/ " ANSI_BRIGHT_GREEN "Heap: " ANSI_RESET "%llu KB used / %llu KB total\n", (uint64_t)(heap_get_used_bytes() / 1024), (uint64_t)((heap_get_used_bytes() + heap_get_free_bytes()) / 1024));
printk(ANSI_BRIGHT_CYAN " " ANSI_BRIGHT_GREEN "Uptime: " ANSI_RESET "%02llu:%02llu:%02llu\n", hours, mins, secs);
printk(ANSI_BRIGHT_CYAN " " ANSI_BRIGHT_GREEN "TTY: " ANSI_RESET "tty%d (Alt+F1-F4 to switch)\n", tty_get_current() + 1);
printk(" \n");