mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-26 00:52:50 +00:00
feat(arch): Add AArch64 / ARMv8i CPU support, cross-compilation & Linux Kconfig TUI
- Implement AArch64 HAL, vector table (16 aligned vectors), GICv2, Generic Timer, Stage-1 MMU (39-bit VA), PL011 UART - Build unified multi-architecture abstraction layer in include/arch/arch.h - Create interactive Linux-like Kconfig TUI menuconfig in scripts/kconfig/menuconfig.py - Support make menuconfig, defconfig, x86_64_defconfig, aarch64_defconfig - Update master Makefile for cross-compiling x86_64 (x86_64-elf-) and AArch64 (aarch64-linux-gnu-) - Dynamic architecture awareness across printk, uname, neofetch, and LazyBox
This commit is contained in:
1 parent
125a891621
commit
70d5925b16
41 files changed
+1926
-187
No files matched your search
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* SUB-OS AArch64 / ARMv8 Bootstrap Entry Point
|
||||
* Handles EL2/EL3 -> EL1 drop, sets up stack, zeroes BSS, and jumps to kernel_main_aarch64
|
||||
*/
|
||||
|
||||
.section ".text.boot"
|
||||
.global _start
|
||||
.global aarch64_entry
|
||||
|
||||
_start:
|
||||
aarch64_entry:
|
||||
// Early UART debug ping
|
||||
mov x0, #0x09000000
|
||||
mov w1, #'['
|
||||
str w1, [x0]
|
||||
mov w1, #'S'
|
||||
str w1, [x0]
|
||||
mov w1, #'U'
|
||||
str w1, [x0]
|
||||
mov w1, #'B'
|
||||
str w1, [x0]
|
||||
mov w1, #'-'
|
||||
str w1, [x0]
|
||||
mov w1, #'O'
|
||||
str w1, [x0]
|
||||
mov w1, #'S'
|
||||
str w1, [x0]
|
||||
mov w1, #']'
|
||||
str w1, [x0]
|
||||
mov w1, #'\n'
|
||||
str w1, [x0]
|
||||
|
||||
// 1. Primary Core Check (Core 0 proceeds, other cores halt)
|
||||
mrs x0, mpidr_el1
|
||||
and x0, x0, #0xFF
|
||||
cbz x0, .primary_core
|
||||
|
||||
.secondary_halt:
|
||||
wfe
|
||||
b .secondary_halt
|
||||
|
||||
.primary_core:
|
||||
// 2. Check current Exception Level (EL)
|
||||
mrs x0, CurrentEL
|
||||
lsr x0, x0, #2
|
||||
cmp x0, #2
|
||||
b.eq .from_el2
|
||||
cmp x0, #3
|
||||
b.eq .from_el3
|
||||
b .in_el1
|
||||
|
||||
.from_el3:
|
||||
// Setup Secure Configuration Register (SCR_EL3)
|
||||
mov x0, #(1 << 10) // RW=1 (64-bit execution in EL2/EL1)
|
||||
orr x0, x0, #(1 << 0) // NS=1 (Non-secure)
|
||||
msr scr_el3, x0
|
||||
mov x0, #0b01001 // EL2h mode with DAIF masked
|
||||
msr spsr_el3, x0
|
||||
adr x0, .from_el2
|
||||
msr elr_el3, x0
|
||||
eret
|
||||
|
||||
.from_el2:
|
||||
// Setup Hypervisor Configuration Register (HCR_EL2)
|
||||
mov x0, #(1 << 31) // RW=1 (64-bit execution in EL1)
|
||||
msr hcr_el2, x0
|
||||
|
||||
// Setup SPSR_EL2 for drop to EL1h (EL1 with dedicated SP_EL1)
|
||||
mov x0, #0b00101 // M[3:0] = 0101 (EL1h)
|
||||
orr x0, x0, #(0xF << 6) // Mask DAIF
|
||||
msr spsr_el2, x0
|
||||
|
||||
adr x0, .in_el1
|
||||
msr elr_el2, x0
|
||||
eret
|
||||
|
||||
.in_el1:
|
||||
// Enable Floating-Point and Advanced SIMD (NEON) in EL1
|
||||
mov x0, #(3 << 20)
|
||||
msr cpacr_el1, x0
|
||||
isb
|
||||
|
||||
// 3. Set up Kernel Stack (64 KB dedicated EL1 stack)
|
||||
ldr x0, =stack_top
|
||||
mov sp, x0
|
||||
|
||||
// 4. Enable Vector Table
|
||||
ldr x0, =vectors
|
||||
msr vbar_el1, x0
|
||||
|
||||
// 5. Zero out BSS
|
||||
ldr x0, =__bss_start
|
||||
ldr x1, =__bss_end
|
||||
.bss_loop:
|
||||
cmp x0, x1
|
||||
b.ge .bss_done
|
||||
str xzr, [x0], #8
|
||||
b .bss_loop
|
||||
.bss_done:
|
||||
|
||||
// 6. Jump to AArch64 C Entry
|
||||
bl kernel_main_aarch64
|
||||
|
||||
.hang:
|
||||
wfi
|
||||
b .hang
|
||||
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Automatically generated by SUB-OS Kconfig for aarch64
|
||||
#
|
||||
CONFIG_ARCH=aarch64
|
||||
CONFIG_ARCH_AARCH64=y
|
||||
# CONFIG_ARCH_X86_64 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
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <arch/arch.h>
|
||||
#include <arch/aarch64/cpu.h>
|
||||
#include <arch/aarch64/gic.h>
|
||||
#include <arch/aarch64/timer.h>
|
||||
#include <arch/aarch64/uart.h>
|
||||
#include <arch/aarch64/mmu.h>
|
||||
#include <arch/x86_64/cpuid.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
static cpu_info_t aarch64_compat_cpu;
|
||||
|
||||
void arch_early_init(void) {
|
||||
uart_pl011_init();
|
||||
}
|
||||
|
||||
void arch_init(void) {
|
||||
aarch64_cpu_init();
|
||||
gic_init();
|
||||
aarch64_timer_init(100);
|
||||
aarch64_mmu_init();
|
||||
|
||||
// Populate compatibility CPU info structure for procfs
|
||||
memset(&aarch64_compat_cpu, 0, sizeof(aarch64_compat_cpu));
|
||||
const aarch64_cpu_info_t* info = aarch64_get_cpu_info();
|
||||
strncpy(aarch64_compat_cpu.vendor, "ARM Ltd", sizeof(aarch64_compat_cpu.vendor) - 1);
|
||||
strncpy(aarch64_compat_cpu.model, info->model_name, sizeof(aarch64_compat_cpu.model) - 1);
|
||||
aarch64_compat_cpu.has_fpu = true;
|
||||
|
||||
arch_enable_interrupts();
|
||||
}
|
||||
|
||||
const char* arch_get_name(void) {
|
||||
return "aarch64 (ARMv8-A)";
|
||||
}
|
||||
|
||||
uint32_t arch_get_cpu_id(void) {
|
||||
return (uint32_t)(aarch64_get_mpidr() & 0xFF);
|
||||
}
|
||||
|
||||
// Timer Compatibility Layer for Portable Drivers
|
||||
uint64_t pit_get_ticks(void) {
|
||||
return aarch64_timer_get_ticks();
|
||||
}
|
||||
|
||||
void pit_sleep(uint32_t ms) {
|
||||
uint64_t count = (ms > 10) ? (ms / 10) : 1;
|
||||
uint64_t target = aarch64_timer_get_ticks() + count;
|
||||
while (aarch64_timer_get_ticks() < target) {
|
||||
__asm__ volatile("wfi");
|
||||
}
|
||||
}
|
||||
|
||||
// Interrupt & CPUID Compatibility Stubs
|
||||
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 &aarch64_compat_cpu;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <arch/aarch64/cpu.h>
|
||||
#include <lib/string.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
static aarch64_cpu_info_t cpu_info;
|
||||
|
||||
uint64_t aarch64_get_midr(void) {
|
||||
uint64_t midr;
|
||||
__asm__ volatile("mrs %0, midr_el1" : "=r"(midr));
|
||||
return midr;
|
||||
}
|
||||
|
||||
uint64_t aarch64_get_mpidr(void) {
|
||||
uint64_t mpidr;
|
||||
__asm__ volatile("mrs %0, mpidr_el1" : "=r"(mpidr));
|
||||
return mpidr;
|
||||
}
|
||||
|
||||
uint32_t aarch64_get_current_el(void) {
|
||||
uint64_t cur_el;
|
||||
__asm__ volatile("mrs %0, CurrentEL" : "=r"(cur_el));
|
||||
return (uint32_t)(cur_el >> 2);
|
||||
}
|
||||
|
||||
void aarch64_cpu_init(void) {
|
||||
memset(&cpu_info, 0, sizeof(cpu_info));
|
||||
|
||||
uint64_t midr = aarch64_get_midr();
|
||||
cpu_info.implementer = (uint32_t)((midr >> 24) & 0xFF);
|
||||
cpu_info.variant = (uint32_t)((midr >> 20) & 0x0F);
|
||||
cpu_info.architecture = (uint32_t)((midr >> 16) & 0x0F);
|
||||
cpu_info.part_num = (uint32_t)((midr >> 4) & 0xFFF);
|
||||
cpu_info.revision = (uint32_t)(midr & 0x0F);
|
||||
cpu_info.current_el = aarch64_get_current_el();
|
||||
|
||||
if (cpu_info.implementer == 0x41) { // ARM Limited
|
||||
switch (cpu_info.part_num) {
|
||||
case 0xD03: strcpy(cpu_info.model_name, "ARM Cortex-A53 (ARMv8.0-A)"); break;
|
||||
case 0xD07: strcpy(cpu_info.model_name, "ARM Cortex-A57 (ARMv8.0-A)"); break;
|
||||
case 0xD08: strcpy(cpu_info.model_name, "ARM Cortex-A72 (ARMv8.0-A)"); break;
|
||||
case 0xD09: strcpy(cpu_info.model_name, "ARM Cortex-A73 (ARMv8.0-A)"); break;
|
||||
case 0xD0B: strcpy(cpu_info.model_name, "ARM Cortex-A76 (ARMv8.2-A)"); break;
|
||||
case 0xD40: strcpy(cpu_info.model_name, "ARM Neoverse-V1 (ARMv8.4-A)"); break;
|
||||
default: strcpy(cpu_info.model_name, "ARMv8-A Compatible 64-Bit Processor"); break;
|
||||
}
|
||||
} else if (cpu_info.implementer == 0x61) { // Apple Silicon
|
||||
strcpy(cpu_info.model_name, "Apple Silicon M-Series (ARMv8-A)");
|
||||
} else {
|
||||
strcpy(cpu_info.model_name, "Generic AArch64 / ARMv8 64-Bit Core");
|
||||
}
|
||||
|
||||
printk(KERN_INFO "CPU: %s (Implementer: 0x%02x, Part: 0x%03x, EL%u)\n",
|
||||
cpu_info.model_name, cpu_info.implementer, cpu_info.part_num, cpu_info.current_el);
|
||||
}
|
||||
|
||||
const aarch64_cpu_info_t* aarch64_get_cpu_info(void) {
|
||||
return &cpu_info;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <arch/aarch64/arch.h>
|
||||
#include <arch/aarch64/gic.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
void aarch64_sync_handler(aarch64_context_t* ctx) {
|
||||
uint64_t esr, elr, far;
|
||||
__asm__ volatile("mrs %0, esr_el1" : "=r"(esr));
|
||||
__asm__ volatile("mrs %0, elr_el1" : "=r"(elr));
|
||||
__asm__ volatile("mrs %0, far_el1" : "=r"(far));
|
||||
|
||||
uint32_t ec = (esr >> 26) & 0x3F;
|
||||
printk(ANSI_BRIGHT_RED "\n[KERNEL PANIC] AArch64 Synchronous Exception!\n" ANSI_RESET);
|
||||
printk("ESR_EL1: 0x%016llx (EC: 0x%02x, ISS: 0x%08x)\n", esr, ec, (uint32_t)(esr & 0x01FFFFFF));
|
||||
printk("ELR_EL1 (PC): 0x%016llx FAR_EL1: 0x%016llx\n", elr, far);
|
||||
printk("Registers:\n");
|
||||
for (int i = 0; i < 30; i += 2) {
|
||||
printk(" X%02d: 0x%016llx X%02d: 0x%016llx\n", i, ctx->r[i], i + 1, ctx->r[i + 1]);
|
||||
}
|
||||
printk(" X30 (LR): 0x%016llx SP: 0x%016llx\n", ctx->r[30], ctx->sp);
|
||||
|
||||
while (1) {
|
||||
__asm__ volatile("wfe");
|
||||
}
|
||||
}
|
||||
|
||||
void aarch64_irq_handler(aarch64_context_t* ctx) {
|
||||
(void)ctx;
|
||||
gic_handle_irq();
|
||||
}
|
||||
|
||||
void aarch64_fiq_handler(aarch64_context_t* ctx) {
|
||||
(void)ctx;
|
||||
printk(KERN_WARNING "AArch64: Unexpected FIQ caught\n");
|
||||
}
|
||||
|
||||
void aarch64_serror_handler(aarch64_context_t* ctx) {
|
||||
(void)ctx;
|
||||
printk(ANSI_BRIGHT_RED "[KERNEL PANIC] AArch64 SError Interrupt caught!\n" ANSI_RESET);
|
||||
while (1) {
|
||||
__asm__ volatile("wfe");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#include <arch/aarch64/gic.h>
|
||||
#include <arch/aarch64/io.h>
|
||||
#include <lib/string.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
#define MAX_GIC_IRQS 256
|
||||
|
||||
static gic_irq_handler_t irq_handlers[MAX_GIC_IRQS];
|
||||
|
||||
void gic_init(void) {
|
||||
memset(irq_handlers, 0, sizeof(irq_handlers));
|
||||
|
||||
// 1. Disable Distributor
|
||||
mmio_write32(GIC_DIST_BASE + GICD_CTLR, 0);
|
||||
|
||||
// 2. Clear pending and enable default priorities
|
||||
uint32_t typer = mmio_read32(GIC_DIST_BASE + GICD_TYPER);
|
||||
uint32_t num_irqs = 32 * ((typer & 0x1F) + 1);
|
||||
if (num_irqs > MAX_GIC_IRQS) num_irqs = MAX_GIC_IRQS;
|
||||
|
||||
for (uint32_t i = 32; i < num_irqs; i += 32) {
|
||||
mmio_write32(GIC_DIST_BASE + GICD_ICENABLER(i / 32), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_irqs; i += 4) {
|
||||
mmio_write32(GIC_DIST_BASE + GICD_IPRIORITYR(i / 4), 0xA0A0A0A0);
|
||||
}
|
||||
|
||||
for (uint32_t i = 32; i < num_irqs; i += 4) {
|
||||
mmio_write32(GIC_DIST_BASE + GICD_ITARGETSR(i / 4), 0x01010101); // Target Core 0
|
||||
}
|
||||
|
||||
// 3. Enable Distributor
|
||||
mmio_write32(GIC_DIST_BASE + GICD_CTLR, 1);
|
||||
|
||||
// 4. Enable CPU Interface
|
||||
mmio_write32(GIC_CPU_BASE + GICC_PMR, 0xF0); // Priority mask
|
||||
mmio_write32(GIC_CPU_BASE + GICC_CTLR, 1); // Enable signaling
|
||||
|
||||
printk(KERN_INFO "GIC: ARM Generic Interrupt Controller v2 initialized (%u IRQ lines)\n", num_irqs);
|
||||
}
|
||||
|
||||
void gic_enable_irq(uint32_t irq) {
|
||||
if (irq >= MAX_GIC_IRQS) return;
|
||||
mmio_write32(GIC_DIST_BASE + GICD_ISENABLER(irq / 32), (1U << (irq % 32)));
|
||||
}
|
||||
|
||||
void gic_disable_irq(uint32_t irq) {
|
||||
if (irq >= MAX_GIC_IRQS) return;
|
||||
mmio_write32(GIC_DIST_BASE + GICD_ICENABLER(irq / 32), (1U << (irq % 32)));
|
||||
}
|
||||
|
||||
void gic_register_handler(uint32_t irq, gic_irq_handler_t handler) {
|
||||
if (irq < MAX_GIC_IRQS) {
|
||||
irq_handlers[irq] = handler;
|
||||
gic_enable_irq(irq);
|
||||
}
|
||||
}
|
||||
|
||||
void gic_handle_irq(void) {
|
||||
uint32_t iar = mmio_read32(GIC_CPU_BASE + GICC_IAR);
|
||||
uint32_t irq = iar & 0x3FF;
|
||||
|
||||
if (irq < 1020) {
|
||||
if (irq_handlers[irq]) {
|
||||
irq_handlers[irq](irq);
|
||||
}
|
||||
// End of Interrupt (EOIR)
|
||||
mmio_write32(GIC_CPU_BASE + GICC_EOIR, iar);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <arch/aarch64/timer.h>
|
||||
#include <arch/aarch64/gic.h>
|
||||
#include <kernel/timer.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
static uint64_t timer_ticks = 0;
|
||||
static uint64_t timer_freq = 62500000; // Standard 62.5MHz QEMU virt frequency
|
||||
static uint32_t tick_interval = 0;
|
||||
|
||||
void aarch64_timer_handle_irq(void) {
|
||||
timer_ticks++;
|
||||
|
||||
// Reset next comparator interval
|
||||
__asm__ volatile("msr cntv_tval_el0, %0" :: "r"((uint64_t)tick_interval));
|
||||
|
||||
// Call generic kernel timer tick
|
||||
timer_tick();
|
||||
}
|
||||
|
||||
static void gic_timer_wrapper(uint32_t irq) {
|
||||
(void)irq;
|
||||
aarch64_timer_handle_irq();
|
||||
}
|
||||
|
||||
void aarch64_timer_init(uint32_t freq_hz) {
|
||||
if (freq_hz == 0) freq_hz = 100;
|
||||
|
||||
__asm__ volatile("mrs %0, cntfrq_el0" : "=r"(timer_freq));
|
||||
tick_interval = (uint32_t)(timer_freq / freq_hz);
|
||||
|
||||
// Register with GIC (PPI 27 = Virtual Timer IRQ)
|
||||
gic_register_handler(ARCH_TIMER_VIRT_IRQ, gic_timer_wrapper);
|
||||
|
||||
// Set countdown and enable virtual timer
|
||||
__asm__ volatile("msr cntv_tval_el0, %0" :: "r"((uint64_t)tick_interval));
|
||||
uint64_t ctl = 1; // Enable=1, IMASK=0
|
||||
__asm__ volatile("msr cntv_ctl_el0, %0" :: "r"(ctl));
|
||||
|
||||
printk(KERN_INFO "Timer: ARM Generic Arch Timer active (%u Hz, Base Clock: %llu MHz)\n",
|
||||
freq_hz, timer_freq / 1000000);
|
||||
}
|
||||
|
||||
uint64_t aarch64_timer_get_ticks(void) {
|
||||
return timer_ticks;
|
||||
}
|
||||
|
||||
uint64_t aarch64_timer_get_freq(void) {
|
||||
return timer_freq;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SUB-OS AArch64 Exception Vector Table
|
||||
* 16 vectors aligned on 128-byte (0x80) boundaries
|
||||
*/
|
||||
|
||||
.macro SAVE_ALL
|
||||
sub sp, sp, #272
|
||||
stp x0, x1, [sp, #0]
|
||||
stp x2, x3, [sp, #16]
|
||||
stp x4, x5, [sp, #32]
|
||||
stp x6, x7, [sp, #48]
|
||||
stp x8, x9, [sp, #64]
|
||||
stp x10, x11, [sp, #80]
|
||||
stp x12, x13, [sp, #96]
|
||||
stp x14, x15, [sp, #112]
|
||||
stp x16, x17, [sp, #128]
|
||||
stp x18, x19, [sp, #144]
|
||||
stp x20, x21, [sp, #160]
|
||||
stp x22, x23, [sp, #176]
|
||||
stp x24, x25, [sp, #192]
|
||||
stp x26, x27, [sp, #208]
|
||||
stp x28, x29, [sp, #224]
|
||||
mrs x0, elr_el1
|
||||
mrs x1, spsr_el1
|
||||
stp x30, x0, [sp, #240]
|
||||
str x1, [sp, #256]
|
||||
.endm
|
||||
|
||||
.macro RESTORE_ALL
|
||||
ldr x1, [sp, #256]
|
||||
msr spsr_el1, x1
|
||||
ldp x30, x0, [sp, #240]
|
||||
msr elr_el1, x0
|
||||
ldp x28, x29, [sp, #224]
|
||||
ldp x26, x27, [sp, #208]
|
||||
ldp x24, x25, [sp, #192]
|
||||
ldp x22, x23, [sp, #176]
|
||||
ldp x20, x21, [sp, #160]
|
||||
ldp x18, x19, [sp, #144]
|
||||
ldp x16, x17, [sp, #128]
|
||||
ldp x14, x15, [sp, #112]
|
||||
ldp x12, x13, [sp, #96]
|
||||
ldp x10, x11, [sp, #80]
|
||||
ldp x8, x9, [sp, #64]
|
||||
ldp x6, x7, [sp, #48]
|
||||
ldp x4, x5, [sp, #32]
|
||||
ldp x2, x3, [sp, #16]
|
||||
ldp x0, x1, [sp, #0]
|
||||
add sp, sp, #272
|
||||
eret
|
||||
.endm
|
||||
|
||||
.section ".vectors", "ax"
|
||||
.align 11
|
||||
.global vectors
|
||||
|
||||
vectors:
|
||||
// 1. Current EL with SP0
|
||||
.align 7; b handle_sync_curr_sp0
|
||||
.align 7; b handle_irq_curr_sp0
|
||||
.align 7; b handle_fiq_curr_sp0
|
||||
.align 7; b handle_serror_curr_sp0
|
||||
|
||||
// 2. Current EL with SPx
|
||||
.align 7; b handle_sync_curr_spx
|
||||
.align 7; b handle_irq_curr_spx
|
||||
.align 7; b handle_fiq_curr_spx
|
||||
.align 7; b handle_serror_curr_spx
|
||||
|
||||
// 3. Lower EL using AArch64
|
||||
.align 7; b handle_sync_lower_aarch64
|
||||
.align 7; b handle_irq_lower_aarch64
|
||||
.align 7; b handle_fiq_lower_aarch64
|
||||
.align 7; b handle_serror_lower_aarch64
|
||||
|
||||
// 4. Lower EL using AArch32
|
||||
.align 7; b handle_sync_lower_aarch32
|
||||
.align 7; b handle_irq_lower_aarch32
|
||||
.align 7; b handle_fiq_lower_aarch32
|
||||
.align 7; b handle_serror_lower_aarch32
|
||||
|
||||
// Common Vector Handlers
|
||||
handle_sync_curr_sp0:
|
||||
handle_sync_curr_spx:
|
||||
handle_sync_lower_aarch64:
|
||||
handle_sync_lower_aarch32:
|
||||
SAVE_ALL
|
||||
mov x0, sp
|
||||
bl aarch64_sync_handler
|
||||
RESTORE_ALL
|
||||
|
||||
handle_irq_curr_sp0:
|
||||
handle_irq_curr_spx:
|
||||
handle_irq_lower_aarch64:
|
||||
handle_irq_lower_aarch32:
|
||||
SAVE_ALL
|
||||
mov x0, sp
|
||||
bl aarch64_irq_handler
|
||||
RESTORE_ALL
|
||||
|
||||
handle_fiq_curr_sp0:
|
||||
handle_fiq_curr_spx:
|
||||
handle_fiq_lower_aarch64:
|
||||
handle_fiq_lower_aarch32:
|
||||
SAVE_ALL
|
||||
mov x0, sp
|
||||
bl aarch64_fiq_handler
|
||||
RESTORE_ALL
|
||||
|
||||
handle_serror_curr_sp0:
|
||||
handle_serror_curr_spx:
|
||||
handle_serror_lower_aarch64:
|
||||
handle_serror_lower_aarch32:
|
||||
SAVE_ALL
|
||||
mov x0, sp
|
||||
bl aarch64_serror_handler
|
||||
RESTORE_ALL
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <arch/aarch64/uart.h>
|
||||
#include <arch/aarch64/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);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
OUTPUT_FORMAT("elf64-littleaarch64")
|
||||
OUTPUT_ARCH(aarch64)
|
||||
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) {
|
||||
. += 0x20000; /* 128 KB dedicated kernel stack */
|
||||
stack_top = .;
|
||||
}
|
||||
|
||||
__kernel_end = .;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#include <arch/aarch64/mmu.h>
|
||||
#include <arch/aarch64/io.h>
|
||||
#include <lib/string.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
// Level 1 Translation Table (PUD / L1, 512 x 1GB entries, root table for 39-bit VA)
|
||||
static uint64_t __attribute__((aligned(4096))) l1_table[512];
|
||||
// Level 2 Translation Table (PMD / L2, 512 x 2MB entries for first 1GB: 0x00000000 - 0x3FFFFFFF Device MMIO)
|
||||
static uint64_t __attribute__((aligned(4096))) l2_dev_table[512];
|
||||
// Level 2 Translation Table (PMD / L2, 512 x 2MB entries for second 1GB: 0x40000000 - 0x7FFFFFFF RAM)
|
||||
static uint64_t __attribute__((aligned(4096))) l2_ram_table[512];
|
||||
|
||||
void aarch64_mmu_init(void) {
|
||||
memset(l1_table, 0, sizeof(l1_table));
|
||||
memset(l2_dev_table, 0, sizeof(l2_dev_table));
|
||||
memset(l2_ram_table, 0, sizeof(l2_ram_table));
|
||||
|
||||
// L1 Table Entry 0 points to L2 Device Table (0 - 1GB)
|
||||
l1_table[0] = ((uint64_t)l2_dev_table) | PTE_VALID | PTE_TABLE;
|
||||
// L1 Table Entry 1 points to L2 RAM Table (1GB - 2GB: QEMU virt RAM is 0x40000000)
|
||||
l1_table[1] = ((uint64_t)l2_ram_table) | PTE_VALID | PTE_TABLE;
|
||||
|
||||
// 1. Identity map Device MMIO (0x00000000 - 0x3FFFFFFF) as Device-nGnRnE
|
||||
for (uint64_t i = 0; i < 512; i++) {
|
||||
uint64_t phys = i * 0x200000; // 2MB blocks
|
||||
l2_dev_table[i] = phys | PTE_VALID | PTE_AF | PTE_SH_INNER | PTE_ATTRINDX(MT_DEVICE_nGnRnE);
|
||||
}
|
||||
|
||||
// 2. Identity map System RAM (0x40000000 - 0x7FFFFFFF, 1GB) as Normal Cacheable
|
||||
for (uint64_t i = 0; i < 512; i++) {
|
||||
uint64_t phys = 0x40000000 + (i * 0x200000);
|
||||
l2_ram_table[i] = phys | PTE_VALID | PTE_AF | PTE_SH_INNER | PTE_ATTRINDX(MT_NORMAL_WB);
|
||||
}
|
||||
|
||||
// 3. Set Memory Attribute Indirection Register (MAIR_EL1)
|
||||
__asm__ volatile("msr mair_el1, %0" :: "r"((uint64_t)MAIR_VAL));
|
||||
|
||||
// 4. Configure Translation Control Register (TCR_EL1)
|
||||
// T0SZ=25 (39-bit VA starting at L1 / 1GB chunks), TG0=0 (4KB granule), Inner/Outer WBWA, Inner Shareable
|
||||
uint64_t tcr = (25ULL << 0) | // T0SZ = 25 (39-bit VA)
|
||||
(1ULL << 8) | // IRGN0 = Normal WBWA
|
||||
(1ULL << 10) | // ORGN0 = Normal WBWA
|
||||
(3ULL << 12) | // SH0 = Inner Shareable
|
||||
(0ULL << 14) | // TG0 = 4KB
|
||||
(1ULL << 23) | // EPD1 = Disable TTBR1 translations
|
||||
(2ULL << 32); // IPS = 40-bit Physical Address (1TB)
|
||||
__asm__ volatile("msr tcr_el1, %0" :: "r"(tcr));
|
||||
|
||||
// 5. Load Translation Table Base Register 0 (TTBR0_EL1)
|
||||
__asm__ volatile("msr ttbr0_el1, %0" :: "r"((uint64_t)l1_table));
|
||||
|
||||
isb();
|
||||
|
||||
// 6. Enable MMU and Caching in SCTLR_EL1 (M=1, C=1, I=1)
|
||||
uint64_t sctlr;
|
||||
__asm__ volatile("mrs %0, sctlr_el1" : "=r"(sctlr));
|
||||
sctlr |= (1 << 0) | // M: Enable MMU
|
||||
(1 << 2) | // C: Enable Data Cache
|
||||
(1 << 12); // I: Enable Instruction Cache
|
||||
__asm__ volatile("msr sctlr_el1, %0" :: "r"(sctlr));
|
||||
|
||||
isb();
|
||||
}
|
||||
Reference in new issue
Block a user