Buildable skeleton for ARM64 architecture specific code.

This commit is contained in:
Ali Mashtizadeh 2023-10-23 22:28:10 -04:00
parent 3cf6f55b95
commit ae669bfa83
32 changed files with 3772 additions and 10 deletions

View File

@ -20,7 +20,7 @@ opts.AddVariables(
("NUMCPUS", "Number of CPUs to use for build (0 means auto).", "0"),
("WITH_GPROF", "Include gprof profiling (0 or 1).", "0"),
("PREFIX", "Installation target directory.", "#pxelinux"),
("ARCH", "Target Architecture", "amd64"),
("ARCH", "Target Architecture", "arm64"),
("BOOTDISK", "Build boot disk (0 or 1)", "1"),
("BOOTDISK_SIZE", "Boot disk size", "128")
)
@ -51,8 +51,16 @@ if 'LDFLAGS' in os.environ:
toolenv = env.Clone()
env.Append(CFLAGS = [ "-Wshadow", "-Wno-typedef-redefinition" ])
env.Append(CPPFLAGS = [ "-target", "x86_64-freebsd-freebsd-elf",
"-fno-builtin", "-fno-stack-protector",
if env["ARCH"] == "amd64":
env.Append(CPPFLAGS = [ "-target", "x86_64-freebsd-freebsd-elf" ])
elif env["ARCH"] == "arm64":
env.Append(CPPFLAGS = [ "-target", "arm64-freebsd-freebsd-elf" ])
else:
print("Unsupported architecture: " + env["ARCH"])
sys.exit(-1)
env.Append(CPPFLAGS = [ "-fno-builtin", "-fno-stack-protector",
"-fno-optimize-sibling-calls" ])
#env.Append(LINKFLAGS = [ "-no-pie" ])
@ -78,10 +86,6 @@ else:
print("Error BUILDTYPE must be RELEASE or DEBUG")
sys.exit(-1)
if env["ARCH"] != "amd64":
print("Unsupported architecture: " + env["ARCH"])
sys.exit(-1)
try:
hf = open(".git/HEAD", 'r')
head = hf.read()

47
lib/libc/arm64/crti.S Normal file
View File

@ -0,0 +1,47 @@
/*-
* Copyright 2001 David E. O'Brien
* Copyright 2014 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Andrew Turner
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <machine/asm.h>
.section .init,"ax",@progbits
.align 4
.globl _init
.type _init,@function
_init:
sub sp, sp, #16
str lr, [sp]
.section .fini,"ax",@progbits
.align 4
.globl _fini
.type _fini,@function
_fini:
sub sp, sp, #16
str lr, [sp]

43
lib/libc/arm64/crtn.S Normal file
View File

@ -0,0 +1,43 @@
/*-
* Copyright 2001 David E. O'Brien
* Copyright 2014 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Andrew Turner
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <machine/asm.h>
.section .init,"ax",@progbits
ldr lr, [sp]
add sp, sp, #16
ret
.section .fini,"ax",@progbits
ldr lr, [sp]
add sp, sp, #16
ret
.section .note.GNU-stack,"",%progbits

13
lib/libc/arm64/syscall.S Normal file
View File

@ -0,0 +1,13 @@
/*
* System Call
*/
#include <machine/asm.h>
.text
FUNC_BEGIN(syscall)
svc 0
ret
FUNC_END(syscall)

View File

@ -22,6 +22,11 @@ getpagesizes(size_t *pagesize, int nelem)
return (nelem > 3 ? 3 : nelem);
}
return 3;
#elif defined(__aarch64__)
if (pagesize) {
pagesize[0] = PGSIZE;
}
return 1;
#else
#error "Unsupported Architecture!"
#endif

View File

@ -36,6 +36,27 @@ src_amd64 = [
"dev/x86/vgacons.c",
]
src_arm64 = [
# Multiboot requires multiboot.S to be the first file
"arm64/multiboot.S",
"arm64/mbentry.c",
# AMD64
"arm64/debug.c",
"arm64/disasm.c",
"arm64/irq.c",
"arm64/machine.c",
"arm64/mp.c",
"arm64/pci.c",
"arm64/pmap.c",
"arm64/support.S",
"arm64/switch.S",
"arm64/thread.c",
"arm64/time.c",
"arm64/trap.c",
"arm64/trapentry.S",
# Devices
]
src_common = [
"kern/copy.c",
"kern/critical.c",
@ -75,14 +96,22 @@ src_common = [
if (env["ARCH"] == "amd64"):
src.append(src_amd64)
ldscript = "#sys/amd64/kernel.lds"
elif (env["ARCH"] == "arm64"):
src.append(src_arm64)
ldscript = "#sys/arm64/kernel.lds"
src.append(src_common)
kern_env.Append(LINKFLAGS = ['-T', ldscript[1:], '-nostdlib'])
kern_env.Append(CPPFLAGS = ['-D_KERNEL'])
kern_env.Append(CPPFLAGS = ['-ffreestanding', '-fno-builtin', '-nostdinc',
'-mno-red-zone', '-mno-mmx', '-mno-sse',
'-mcmodel=large'])
# '-target', 'amd64-orion-eabi'
'-mno-red-zone'])
if env["ARCH"] == "amd64":
kern_env.Append(CPPFLAGS = ['-mno-mmx', '-mno-sse', '-mcmodel=large'])
# '-target', 'amd64-orion-eabi'
elif env["ARCH"] == "arm64":
kern_env.Append(CPPFLAGS = ['-mcmodel=large'])
kern_env.Append(CPPPATH = ['#build/include'])
kernel = kern_env.Program("castor", src)

181
sys/arm64/debug.c Normal file
View File

@ -0,0 +1,181 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/kassert.h>
#include <sys/kconfig.h>
#include <sys/kdebug.h>
#include <sys/mp.h>
#include <machine/cpu.h>
#include <machine/cpuop.h>
#include <machine/atomic.h>
#include <machine/trap.h>
#include <machine/mp.h>
TrapFrame *frames[MAX_CPUS];
volatile static uint64_t debugLock = 0;
volatile static uint64_t debugCmd = 0;
volatile static uint64_t debugHalted = 0;
void
Debug_HaltCPUs()
{
debugCmd = 0;
//if (MP_GetCPUs() == 1)
return;
//LAPIC_BroadcastNMI(T_DEBUGIPI);
// Wait for processors to enter
/*while (debugHalted < (MP_GetCPUs() - 1)) {
pause();
}*/
}
void
Debug_ResumeCPUs()
{
debugCmd = 1;
// Wait for processors to resume
while (debugHalted > 0) {
pause();
}
}
void
Debug_HaltIPI(TrapFrame *tf)
{
MP_SetState(CPUSTATE_HALTED);
__sync_fetch_and_add(&debugHalted, 1);
frames[CPU()] = tf;
while (debugCmd == 0) {
pause();
}
__sync_fetch_and_sub(&debugHalted, 1);
MP_SetState(CPUSTATE_BOOTED);
}
void
Debug_Breakpoint(TrapFrame *tf)
{
frames[CPU()] = tf;
// Should probably force all cores into the debugger
while(atomic_swap_uint64(&debugLock, 1) == 1) {
// Wait to acquire debugger lock
}
// Stop all processors
Debug_HaltCPUs();
// Enter prompt
Debug_Prompt();
// Resume all processors
Debug_ResumeCPUs();
atomic_set_uint64(&debugLock, 0);
}
static void
Debug_Registers(int argc, const char *argv[])
{
TrapFrame *tf = frames[CPU()];
if (argc == 2) {
int cpuNo = Debug_StrToInt(argv[1]);
if (cpuNo >= MAX_CPUS) {
kprintf("Invalid CPU number\n");
return;
}
tf = frames[cpuNo];
}
}
REGISTER_DBGCMD(registers, "Show CPU registers", Debug_Registers);
static void
Debug_Backtrace(int argc, const char *argv[])
{
TrapFrame *tf = frames[CPU()];
uint64_t *ptr;
uint64_t rip;
uint64_t rbp;
if (argc == 2) {
int cpuNo = Debug_StrToInt(argv[1]);
if (cpuNo >= MAX_CPUS) {
kprintf("Invalid CPU number\n");
return;
}
tf = frames[cpuNo];
}
rip = 0; //tf->rip;
rbp = 0; //tf->rbp;
kprintf("%-16s %-16s\n", "IP Pointer", "Base Pointer");
while (3) {
kprintf("%016llx %016llx\n", rip, rbp);
ptr = (uint64_t *)rbp;
if (rbp == 0ULL || rip == 0ULL) {
break;
}
rbp = ptr[0];
rip = ptr[1];
}
}
REGISTER_DBGCMD(backtrace, "Print backtrace", Debug_Backtrace);
static void
Debug_SetBreakpoint(int argc, const char *argv[])
{
if (argc != 2) {
kprintf("bkpt [ADDR]");
return;
}
uint64_t addr = Debug_StrToInt(argv[1]);
kprintf("NOT IMPLEMENTED\n");
}
REGISTER_DBGCMD(bkpt, "Set breakpoint", Debug_SetBreakpoint);
static void
Debug_ClearBreakpoint(int argc, const char *argv[])
{
if (argc != 2) {
kprintf("clrbkpt [0-3]");
return;
}
kprintf("NOT IMPLEMENTED\n");
}
REGISTER_DBGCMD(clrbkpt, "Clear breakpoint", Debug_ClearBreakpoint);
static void
Debug_ListBreakpoints(int argc, const char *argv[])
{
kprintf("NOT IMPLEMENTED\n");
}
REGISTER_DBGCMD(bkpts, "List breakpoint", Debug_ListBreakpoints);
static void
Debug_Reboot(int argc, const char *argv[])
{
kprintf("NOT IMPLEMENTED\n");
}
REGISTER_DBGCMD(reboot, "Reboot computer", Debug_Reboot);

1627
sys/arm64/disasm.c Normal file

File diff suppressed because it is too large Load Diff

10
sys/arm64/include/asm.h Normal file
View File

@ -0,0 +1,10 @@
/*
* Assembly Macros
*/
#define FUNC_BEGIN(fname) .p2align 4, 0x90; .global fname; \
.type fname, @function; \
fname:
#define FUNC_END(fname) .size fname, . - fname

View File

@ -0,0 +1,38 @@
#ifndef __ATOMIC_H__
#define __ATOMIC_H__
static INLINE uint64_t
atomic_swap_uint32(volatile uint32_t *dst, uint32_t newval)
{
uint32_t retval;
asm volatile(".arch_extension lse; swp %w2, %w0, [%w1]; .arch_extension nolse;"
: "=r" (retval)
: "r" (dst), "r" (newval)
: "memory");
return newval;
}
static INLINE uint64_t
atomic_swap_uint64(volatile uint64_t *dst, uint64_t newval)
{
uint64_t retval;
asm volatile(".arch_extension lse; swp %2, %0, [%1]; .arch_extension nolse;"
: "=r" (retval)
: "r" (dst), "r" (newval)
: "memory");
return retval;
}
static inline void
atomic_set_uint64(volatile uint64_t *dst, uint64_t newval)
{
*dst = newval;
}
#endif /* __ATOMIC_H__ */

46
sys/arm64/include/cpu.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2013-2018 Ali Mashtizadeh
* All rights reserved.
*/
#ifndef __AMD64_H__
#define __AMD64_H__
#include <sys/cdefs.h>
/*
* Page Tables
*/
#define PGNUMMASK 0xFFFFFFFFFFFFF000ULL
#define PGIDXSHIFT 9
#define PGIDXMASK (512 - 1)
#define PGSHIFT 12
#define PGSIZE (1 << PGSHIFT)
#define PGMASK (PGSIZE - 1)
#define LARGE_PGSHIFT 21
#define LARGE_PGSIZE (1 << LARGE_PGSHIFT)
#define LARGE_PGMASK (LARGE_PGSIZE - 1)
#define HUGE_PGSHIFT 30
#define HUGE_PGSIZE (1 << HUGE_PGSHIFT)
#define HUGE_PGMASK (HUGE_PGSIZE - 1)
#define ROUNDUP_PGSIZE(x) (((x) + LARGE_PGSIZE - 1) & ~LARGE_PGMASK)
#define ROUNDDOWN_PGSIZE(x) ((x) & ~LARGE_PGMASK)
#define PAGETABLE_ENTRIES 512
typedef uint64_t PageEntry;
typedef struct PageTable {
PageEntry entries[PAGETABLE_ENTRIES];
} PageTable;
#include "cpuop.h"
#endif /* __AMD64_H__ */

35
sys/arm64/include/cpuop.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2013-2023 Ali Mashtizadeh
* All rights reserved.
*/
#ifndef __ARM64OP_H__
#define __ARM64OP_H__
static INLINE void enable_interrupts()
{
asm volatile("msr daifclr, #(0x0002)\n");
}
static INLINE void disable_interrupts()
{
asm volatile("msr daifset, #(0x0002)\n");
}
static INLINE void hlt()
{
asm volatile("");
}
static INLINE void pause()
{
asm volatile("");
}
static INLINE void breakpoint()
{
asm volatile("brk #0");
}
#endif /* __ARM64OP_H__ */

View File

@ -0,0 +1,13 @@
/*
* IOAPIC Header
*/
#ifndef __IOAPIC_H__
#define __IOAPIC_H__
void IOAPIC_Init();
void IOAPIC_Enable(int irq);
void IOAPIC_Disable(int irq);
#endif /* __IOAPIC_H__ */

23
sys/arm64/include/mp.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef __MACHINE_MP_H__
#define __MACHINE_MP_H__
#define CPUSTATE_NOT_PRESENT 0
#define CPUSTATE_BOOTED 1
#define CPUSTATE_HALTED 2
#define CPUSTATE_MAX 2
void MP_Init();
void MP_InitAP();
void MP_SetState(int state);
int MP_GetCPUs();
/* Cross Calls */
typedef int (*CrossCallCB)(void *);
void MP_CrossCallTrap();
int MP_CrossCall(CrossCallCB cb, void *arg);
uint32_t LAPIC_CPU();
#endif /* __MACHINE_MP__ */

81
sys/arm64/include/pmap.h Normal file
View File

@ -0,0 +1,81 @@
#ifndef __PMAP_H__
#define __PMAP_H__
#include <machine/cpu.h>
/*
* +----------------------+
* | Zero Page (Unmapped) |
* +----------------------+ 0x00000000_00000100 User Space Start
* | |
* | User Space |
* .
* .
* .
* | |
* +----------------------+ 0x00008000_00000000 User Space End
* | |
* | Non-canonical |
* .
* .
* .
* | |
* +----------------------+ 0xFFFF8000_00000000 Direct Map
* | Direct Map |
* +----------------------+ 0xFFFF8100_00000000 XMap Start
* | XMap |
* +----------------------+ 0xFFFF8120_00000000 XMap Top
*
*
*/
#define MEM_USERSPACE_BASE 0x0000000000000000ULL
#define MEM_USERSPACE_LEN 0x0000800000000000ULL
#define MEM_USERSPACE_TOP (MEM_USERSPACE_BASE + MEM_USERSPACE_LEN)
#define MEM_USERSPACE_STKBASE 0x0000000070000000ULL
#define MEM_USERSPACE_STKLEN 0x0000000000010000ULL
#define MEM_USERSPACE_STKTOP (MEM_USERSPACE_STKBASE + MEM_USERSPACE_STKLEN)
#define MEM_DIRECTMAP_BASE 0xFFFF800000000000ULL
#define MEM_DIRECTMAP_LEN 0x0000010000000000ULL
#define MEM_XMAP_BASE 0xFFFF810000000000ULL
#define MEM_XMAP_LEN 0x0000002000000000ULL
#define PPN2DMVA(ppn) (((ppn) << PGSIZE) + MEM_DIRECTMAP_BASE)
#define DMVA2PPN(dmva) (((dmva) - MEM_DIRECTMAP_BASE) >> PGSIZE)
#define DMVA2PA(dmva) ((dmva) - MEM_DIRECTMAP_BASE)
#define DMPA2VA(pa) ((pa) + MEM_DIRECTMAP_BASE)
#define VA2PA(va) PMap_Translate(PMap_CurrentAS(), va)
typedef struct AS
{
PageTable *root;
uint64_t tables;
uint64_t mappings;
} AS;
void PMap_Init();
void PMap_InitAP();
AS* PMap_NewAS();
void PMap_DestroyAS(AS *space);
AS* PMap_CurrentAS();
void PMap_LoadAS(AS *space);
void PMap_Dump(AS *space);
uintptr_t PMap_Translate(AS *space, uintptr_t va);
// Manipulate User Memory
bool PMap_Map(AS *as, uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags);
bool PMap_AllocMap(AS *as, uint64_t virt, uint64_t len, uint64_t flags);
bool PMap_Unmap(AS *as, uint64_t virt, uint64_t pages);
// Manipulate Kernel Memory
void PMap_SystemLookup(uint64_t va, PageEntry **entry, int size);
bool PMap_SystemLMap(uint64_t phys, uint64_t virt, uint64_t lpages, uint64_t flags);
bool PMap_SystemMap(uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags);
bool PMap_SystemUnmap(uint64_t virt, uint64_t pages);
#endif /* __PMAP_H__ */

View File

@ -0,0 +1,17 @@
#ifndef __MACHINE_THREAD_H__
#define __MACHINE_THREAD_H__
#include <machine/cpu.h>
#include <machine/cpuop.h>
typedef struct ThreadArchStackFrame {
} ThreadArchStackFrame;
typedef struct ThreadArch {
bool useFP;
uint64_t rsp;
} ThreadArch;
#endif /* __MACHINE_THREAD_H__ */

91
sys/arm64/include/trap.h Normal file
View File

@ -0,0 +1,91 @@
#ifndef __TRAP_H__
#define __TRAP_H__
#define T_DE 0 /* Divide Error Exception */
#define T_DB 1 /* Debug Exception */
#define T_NMI 2 /* NMI Interrupt */
#define T_BP 3 /* Breakpoint Exception */
#define T_OF 4 /* Overflow Exception */
#define T_BR 5 /* BOUND Range Exceeded Exception */
#define T_UD 6 /* Invalid Opcode Exception */
#define T_NM 7 /* Device Not Available Exception */
#define T_DF 8 /* Double Fault Exception */
#define T_TS 10 /* Invalid TSS Exception */
#define T_NP 11 /* Segment Not Present */
#define T_SS 12 /* Stack Fault Exception */
#define T_GP 13 /* General Protection Exception */
#define T_PF 14 /* Page-Fault Exception */
#define T_MF 16 /* x87 FPU Floating-Point Error */
#define T_AC 17 /* Alignment Check Exception */
#define T_MC 18 /* Machine-Check Exception */
#define T_XF 19 /* SIMB Floating-Point Exception */
#define T_VE 20 /* Virtualization Exception */
#define T_CPU_LAST T_VE
// IRQs
#define T_IRQ_BASE 32
#define T_IRQ_LEN 24
#define T_IRQ_MAX (T_IRQ_BASE + T_IRQ_LEN - 1)
#define T_IRQ_TIMER (T_IRQ_BASE + 0)
#define T_IRQ_KBD (T_IRQ_BASE + 1)
#define T_IRQ_COM1 (T_IRQ_BASE + 4)
#define T_IRQ_MOUSE (T_IRQ_BASE + 12)
// LAPIC Special Vectors
#define T_IRQ_SPURIOUS (T_IRQ_BASE + 24)
#define T_IRQ_ERROR (T_IRQ_BASE + 25)
#define T_IRQ_THERMAL (T_IRQ_BASE + 26)
#define T_SYSCALL 60 /* System Call */
#define T_CROSSCALL 61 /* Cross Call (IPI) */
#define T_DEBUGIPI 62 /* Kernel Debugger Halt (IPI) */
#define T_UNKNOWN 63 /* Unknown Trap */
#define T_MAX 64
typedef struct TrapFrame
{
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rbp;
uint64_t rdi;
uint64_t rsi;
uint64_t rdx;
uint64_t rcx;
uint64_t rbx;
uint64_t ds;
uint64_t rax;
uint64_t vector;
uint32_t errcode;
uint32_t _unused0;
uint64_t rip;
uint16_t cs;
uint16_t _unused1;
uint16_t _unused2;
uint16_t _unused3;
uint64_t rflags;
uint64_t rsp;
uint16_t ss;
uint16_t _unused4;
uint16_t _unused5;
uint16_t _unused6;
} TrapFrame;
void Trap_Init();
void Trap_InitAP();
void Trap_Dump(TrapFrame *tf);
void Trap_Pop(TrapFrame *tf);
#endif /* __TRAP_H__ */

53
sys/arm64/irq.c Normal file
View File

@ -0,0 +1,53 @@
#include <stdint.h>
#include <sys/kassert.h>
#include <sys/irq.h>
#include <machine/trap.h>
#include <machine/ioapic.h>
LIST_HEAD(IRQHandlerList, IRQHandler);
struct IRQHandlerList handlers[T_IRQ_LEN];
void
IRQ_Init()
{
int i;
for (i = 0; i < T_IRQ_LEN; i++)
{
LIST_INIT(&handlers[i]);
}
}
void
IRQ_Handler(int irq)
{
struct IRQHandler *h;
LIST_FOREACH(h, &handlers[irq], link)
{
h->cb(h->arg);
}
}
void
IRQ_Register(int irq, struct IRQHandler *h)
{
ASSERT(irq < T_IRQ_LEN);
LIST_INSERT_HEAD(&handlers[irq], h, link);
//IOAPIC_Enable(irq);
}
void
IRQ_Unregister(int irq, struct IRQHandler *h)
{
LIST_REMOVE(h, link);
if (LIST_EMPTY(&handlers[irq])) {
//IOAPIC_Disable(irq);
}
}

227
sys/arm64/kernel.lds Normal file
View File

@ -0,0 +1,227 @@
/*OUTPUT_FORMAT("elf64-arm64-freebsd",
"elf64-arm64-freebsd",
"elf64-arm64-freebsd")*/
OUTPUT_ARCH(arm:arm64)
ENTRY(_start)
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment",
0xFFFF800000400000));
. = SEGMENT_START("text-segment", 0xFFFF800000400000) + SIZEOF_HEADERS;
.text :
{
*(.text .stub .text.* .gnu.linkonce.t.*)
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
.plt : { *(.plt) *(.iplt) }
.init :
{
KEEP (*(.init))
}
.fini :
{
KEEP (*(.fini))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.init : { *(.rela.init) }
.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
.rela.fini : { *(.rela.fini) }
.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
.rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) }
.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rela.ctors : { *(.rela.ctors) }
.rela.dtors : { *(.rela.dtors) }
.rela.got : { *(.rela.got) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
.rela.ldata : { *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) }
.rela.lbss : { *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) }
.rela.lrodata : { *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) }
.rela.ifunc : { *(.rela.ifunc) }
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = .;
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(.init_array.* .ctors.*))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array.* .dtors.*))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
/* Kernel Debugger */
.kdbgcmd ALIGN(CONSTANT(COMMONPAGESIZE)) :
{
__kdbgcmd_start = .;
*(.kdbgcmd)
__kdbgcmd_end = .;
}
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

170
sys/arm64/machine.c Normal file
View File

@ -0,0 +1,170 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/kconfig.h>
#include <sys/kassert.h>
#include <sys/kmem.h>
#include <sys/mp.h>
#include <sys/irq.h>
#include <sys/spinlock.h>
#include <machine/cpu.h>
#include <machine/trap.h>
#include <machine/pmap.h>
#include <machine/mp.h>
#include <sys/thread.h>
#include <sys/disk.h>
#include <sys/bufcache.h>
#include <sys/vfs.h>
#include <sys/elf64.h>
#include "../dev/console.h"
extern void KTime_Init();
extern void KTimer_Init();
extern void RTC_Init();
extern void PCI_Init();
extern void MachineBoot_AddMem();
extern void Loader_LoadInit();
extern void PAlloc_LateInit();
/**
* Machine_SyscallInit --
*
* Configure the model specific registers (MSRs) that specify how to transfer
* control to the operating system when the system call instruction is invoked.
*/
static void
Machine_SyscallInit()
{
kprintf("Initializing Syscall... ");
NOT_IMPLEMENTED();
kprintf("Done!\n");
}
/**
* Machine_EarlyInit --
*
* Initializes early kernel state.
*/
void
Machine_EarlyInit()
{
Spinlock_EarlyInit();
Critical_Init();
Critical_Enter();
WaitChannel_EarlyInit();
Console_Init();
PAlloc_Init();
}
static void
Machine_IdleThread(void *test)
{
while (1) { enable_interrupts(); hlt(); }
}
/**
* Machine_Init --
*
* At this point the assembly startup code has setup temporary processor data
* structures sufficient to execute C code and make it through this
* initialization routine.
*/
void Machine_Init()
{
/*
* Initialize Processor State
*/
//Trap_Init();
Machine_SyscallInit();
/*
* Initialize Memory Allocation and Virtual Memory
*/
//PAlloc_AddRegion(DMPA2VA(16*1024*1024), 16*1024*1024);
PMap_Init();
XMem_Init();
PAlloc_LateInit();
MachineBoot_AddMem();
/*
* Initialize Time Keeping
*/
KTime_Init();
RTC_Init(); // Finishes initializing KTime
/*
* Initialize Interrupts
*/
IRQ_Init();
// GICv3
Thread_Init();
KTimer_Init(); // Depends on RTC and KTime
/*
* Initialize Additional Processors
*/
MP_Init();
/*
* Initialize Basic Devices
*/
PCI_Init(); // PCI BUS
BufCache_Init();
/*
* Open the primary disk and mount the root file system
*/
Disk *root = Disk_GetByID(0, 0);
if (!root)
Panic("No boot disk!");
VFS_MountRoot(root);
Critical_Exit();
/*
* Create the idle thread
*/
Thread *thr = Thread_KThreadCreate(&Machine_IdleThread, NULL);
if (thr == NULL) {
kprintf("Couldn't create idle thread!\n");
}
Sched_SetRunnable(thr);
/*
* Load the init processor
*/
Loader_LoadInit();
breakpoint();
}
/**
* Machine_InitAP --
*
* Shorter initialization routine for co-processors.
*/
void Machine_InitAP()
{
Critical_Enter();
// Setup CPU state
Trap_InitAP();
PMap_InitAP();
Machine_SyscallInit();
// Setup LAPIC
// Boot processor
MP_InitAP();
Thread_InitAP();
Critical_Exit();
Machine_IdleThread(NULL);
}

61
sys/arm64/mbentry.c Normal file
View File

@ -0,0 +1,61 @@
/*
* Multiboot C Entry
*/
#include <stdbool.h>
#include <stdint.h>
#include <sys/kassert.h>
#include <sys/cdefs.h>
#include "../dev/console.h"
#include <machine/pmap.h>
void MachineBoot_Entry(unsigned long magic, unsigned long addr);
#define PAGE_ALIGN __attribute__((aligned(PGSIZE)))
#define DATA_SECTION __attribute__((section(".data")))
extern void Machine_EarlyInit();
extern void Machine_Init();
extern void PAlloc_AddRegion(uintptr_t start, uintptr_t len);
#define MAX_REGIONS 16
static uintptr_t memRegionStart[MAX_REGIONS];
static uintptr_t memRegionLen[MAX_REGIONS];
static int memRegionIdx;
void
MachineBoot_Entry(unsigned long magic, unsigned long addr)
{
// Main initialization
Machine_Init();
return;
}
void
MachineBoot_AddMem()
{
int i;
uintptr_t initRamEnd = 32*1024*1024;
for (i = 0; i < memRegionIdx; i++)
{
uintptr_t start = memRegionStart[i];
uintptr_t len = memRegionLen[i];
if (start + len < initRamEnd)
continue;
if (start < initRamEnd) {
len = initRamEnd - start;
start = initRamEnd;
}
kprintf("AddRegion: %08llx %08llx\n", start, len);
PAlloc_AddRegion(start + MEM_DIRECTMAP_BASE, len);
}
}

213
sys/arm64/mp.c Normal file
View File

@ -0,0 +1,213 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/kassert.h>
#include <sys/kconfig.h>
#include <sys/kdebug.h>
#include <sys/kmem.h>
#include <sys/ktime.h>
#include <sys/mp.h>
#include <machine/cpu.h>
#include <machine/cpuop.h>
#include <machine/pmap.h>
#include <machine/mp.h>
#include <machine/trap.h>
extern uint8_t mpstart_begin[];
extern uint8_t mpstart_end[];
extern AS systemAS;
#define MP_WAITTIME 250000000ULL
typedef struct CrossCallFrame {
CrossCallCB cb;
void *arg;
volatile int count;
volatile int done[MAX_CPUS];
volatile int status[MAX_CPUS];
} CrossCallFrame;
const char *CPUStateToString[] = {
"NOT PRESENT",
"BOOTED",
"HALTED",
};
typedef struct CPUState {
int state;
UnixEpochNS heartbeat;
CrossCallFrame *frame;
} CPUState;
volatile static bool booted;
volatile static int lastCPU;
volatile static CPUState cpus[MAX_CPUS];
void
MP_Init()
{
int i;
kprintf("Booting on CPU %u\n", CPU());
cpus[CPU()].state = CPUSTATE_BOOTED;
cpus[CPU()].frame = NULL;
for (i = 1; i < MAX_CPUS; i++) {
cpus[i].state = CPUSTATE_NOT_PRESENT;
cpus[i].frame = NULL;
}
/*
* XXX: We really should read from the MP Table, but this appears to be
* reliable for now.
*/
lastCPU = 0;
/*
for (i = 1; i < MAX_CPUS; i++) {
if (MPBootAP(i) < 0)
break;
lastCPU = i;
}
*/
lastCPU++;
}
void
MP_InitAP()
{
kprintf("AP %d booted!\n", CPU());
cpus[CPU()].state = CPUSTATE_BOOTED;
booted = 1;
}
void
MP_SetState(int state)
{
ASSERT(state > 0 && state <= CPUSTATE_MAX);
cpus[CPU()].state = state;
}
int
MP_GetCPUs()
{
return lastCPU;
}
void
MP_CrossCallTrap()
{
int c;
Critical_Enter();
for (c = 0; c <= lastCPU; c++) {
CrossCallFrame *frame = cpus[c].frame;
if (frame == NULL)
continue;
if (frame->done[CPU()] == 1)
continue;
frame->status[CPU()] = (frame->cb)(frame->arg);
frame->done[CPU()] = 1;
// Increment
__sync_add_and_fetch(&frame->count, 1);
}
Critical_Exit();
}
// XXX: The thread should not be migrated in the middle of this call.
int
MP_CrossCall(CrossCallCB cb, void *arg)
{
volatile CrossCallFrame frame;
// Setup frame
memset((void *)&frame, 0, sizeof(frame));
frame.cb = cb;
frame.arg = arg;
frame.count = 1;
Critical_Enter();
cpus[CPU()].frame = (CrossCallFrame *)&frame;
/*
if (LAPIC_Broadcast(T_CROSSCALL) < 0)
return -1;
*/
// Run on the local CPU
frame.status[CPU()] = cb(arg);
frame.done[CPU()] = 1;
// Wait for all to respond
while (frame.count < lastCPU) {
// Check for timeout
// XXX: Should dump the crosscall frame
}
cpus[CPU()].frame = NULL;
Critical_Exit();
return 0;
}
static int
MPPing(void *arg)
{
//kprintf("CPU %d Ack\n", CPU());
return 0;
}
static void
Debug_CrossCall(int argc, const char *argv[])
{
int i;
UnixEpochNS startTS, stopTS;
startTS = KTime_GetEpochNS();
for (i = 0; i < 32; i++) {
MP_CrossCall(&MPPing, NULL);
}
stopTS = KTime_GetEpochNS();
// XXX: Print min and max
kprintf("Average CrossCall Latency: %llu ns\n",
(stopTS - startTS) / 32ULL);
return;
}
REGISTER_DBGCMD(crosscall, "Ping crosscall", Debug_CrossCall);
static void
Debug_CPUS(int argc, const char *argv[])
{
int c;
for (c = 0; c < MAX_CPUS; c++) {
if (cpus[c].state != CPUSTATE_NOT_PRESENT) {
kprintf("CPU %d: %s\n", c, CPUStateToString[cpus[c].state]);
}
}
}
REGISTER_DBGCMD(cpus, "Show MP information", Debug_CPUS);
static void
Debug_CPU(int argc, const char *argv[])
{
kprintf("CPU %d\n", CPU());
}
REGISTER_DBGCMD(cpu, "Current CPU number", Debug_CPU);

30
sys/arm64/multiboot.S Normal file
View File

@ -0,0 +1,30 @@
/*
* Multiboot Entry
*/
#define STACK_SIZE 0x4000
#define KERNEL_BASE 0xFFFF800000000000
#define LOWMEM(_x) (_x - KERNEL_BASE)
.extern mb_entry
.text
/**
* _start --
*
* ELF entry point.
*/
.globl _start
_start:
#call MachineBoot_Entry
loop:
#hlt
#jmp loop
// Boot stack
.p2align 12
.globl stack
.comm stack, STACK_SIZE

77
sys/arm64/pci.c Normal file
View File

@ -0,0 +1,77 @@
#include <stdint.h>
#include <sys/kassert.h>
#include <sys/pci.h>
#include <machine/cpu.h>
#include <machine/cpuop.h>
#define PCI_PORT_ADDR 0xCF8
#define PCI_PORT_DATABASE 0xCFC
static inline uint32_t
PCIGetAddr(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg)
{
ASSERT(bus < 256 && slot < 64 && func < 8 && reg < 256);
return (1 << 31) | (bus << 16) | (slot << 11) | (func << 8) | (reg & 0x00fc);
}
uint8_t
PCICfgRead8(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg)
{
uint32_t addr = PCIGetAddr(bus, slot, func, reg);
uint16_t port = PCI_PORT_DATABASE + (reg & 0x3);
return 0;
}
uint16_t
PCICfgRead16(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg)
{
uint32_t addr = PCIGetAddr(bus, slot, func, reg);
uint16_t port = PCI_PORT_DATABASE + (reg & 0x2);
ASSERT((reg & 0x1) == 0);
return 0;
}
uint32_t
PCICfgRead32(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg)
{
uint32_t addr = PCIGetAddr(bus, slot, func, reg);
uint16_t port = PCI_PORT_DATABASE;
ASSERT((reg & 0x3) == 0);
return 0;
}
void
PCICfgWrite8(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg,
uint8_t data)
{
uint32_t addr = PCIGetAddr(bus, slot, func, reg);
uint16_t port = PCI_PORT_DATABASE + (reg & 0x3);
}
void
PCICfgWrite16(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg,
uint16_t data)
{
uint32_t addr = PCIGetAddr(bus, slot, func, reg);
uint16_t port = PCI_PORT_DATABASE + (reg & 0x3);
}
void
PCICfgWrite32(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg,
uint32_t data)
{
uint32_t addr = PCIGetAddr(bus, slot, func, reg);
uint16_t port = PCI_PORT_DATABASE + (reg & 0x3);
}

323
sys/arm64/pmap.c Normal file
View File

@ -0,0 +1,323 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/kconfig.h>
#include <sys/kassert.h>
#include <sys/kdebug.h>
#include <sys/kmem.h>
#include <sys/mp.h>
#include <machine/cpu.h>
#include <machine/cpuop.h>
#include <machine/pmap.h>
AS systemAS;
AS *currentAS[MAX_CPUS];
void
PMap_Init()
{
int i, j;
kprintf("Initializing PMAP ... ");
// Setup global state
for (i = 0; i < MAX_CPUS; i++) {
currentAS[i] = 0;
}
// Allocate system page table
systemAS.root = PAlloc_AllocPage();
systemAS.tables = PAGETABLE_ENTRIES / 2 + 1;
systemAS.mappings = 0;
if (!systemAS.root)
PANIC("Cannot allocate system page table");
// Setup system mappings
PMap_SystemLMap(0x0, MEM_DIRECTMAP_BASE + 0x0,
3*512, 0); // 3GB RWX
PMap_SystemLMap(0xC0000000, MEM_DIRECTMAP_BASE + 0xC0000000,
512, 0); // 1GB RW + PCD
PMap_SystemLMap(0x100000000, MEM_DIRECTMAP_BASE + 0x100000000,
60*512, 0); // 60GB RWX
PMap_LoadAS(&systemAS);
kprintf("Done!\n");
}
void
PMap_InitAP()
{
PMap_LoadAS(&systemAS);
}
/**
* PMap_NewAS --
*
* Create a new address space.
*
* @return Newly created address space.
*/
AS*
PMap_NewAS()
{
int i;
AS *as = PAlloc_AllocPage();
if (!as)
return NULL;
as->root = PAlloc_AllocPage();
as->tables = 1;
as->mappings = 0;
// NOT IMPLEMENTED
return as;
}
/**
* PMap_DestroyAS --
*
* Destroys an address space and releases the physical pages.
*
* @param [in] space Address space to destroy.
*/
void
PMap_DestroyAS(AS *space)
{
}
/**
* PMap_CurrentAS --
*
* Get the current address space on this CPU.
*
* @return Current address space.
*/
AS *
PMap_CurrentAS()
{
return currentAS[CPU()];
}
/**
* PMap_LoadAS --
*
* Load an address space into the CPU. Reloads the CR3 register in x86-64 that
* points the physical page tables and flushes the TLB entries.
*
* @param [in] space Address space to load.
*/
void
PMap_LoadAS(AS *space)
{
// Flush TLB
currentAS[CPU()] = space;
}
/**
* PMapAllocPageTable --
*
* Allocates and initializes a page table.
*
* @return Newly created PageTable.
*/
static PageTable *
PMapAllocPageTable()
{
NOT_IMPLEMENTED();
return NULL;
}
/**
* PMap_Translate --
*
* Translates a virtual address to physical address for a given address space.
*
* @param [in] space Address space we wish to lookup a mapping in.
* @param [in] va Virtual address we wish to translate.
*/
uintptr_t
PMap_Translate(AS *space, uintptr_t va)
{
NOT_IMPLEMENTED();
return 0;
}
/**
* PMapLookupEntry --
*
* Lookup a virtual address in a page table and return a pointer to the page
* entry. This function allocates page tables as necessary to fill in the
* 4-level heirarchy.
*
* @param [in] space Address space to search.
* @param [in] va Virtual address to lookup.
* @param [out] entry Pointer will point to the PageEntry.
* @param [in] size Page size we want to use.
*/
static void
PMapLookupEntry(AS *space, uint64_t va, PageEntry **entry, int size)
{
NOT_IMPLEMENTED();
return;
}
/**
* PMap_Map --
*
* Map a physical to virtual mapping in an address space.
*
* @param [in] as Address space.
* @param [in] phys Physical address.
* @param [in] virt Virtual address.
* @param [in] pages Pages to map in.
* @param [in] flags Flags to apply to the mapping.
*
* @retval true On success
* @retval false On failure
*/
bool
PMap_Map(AS *as, uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags)
{
NOT_IMPLEMENTED();
return true;
}
/**
* PMap_Unmap --
*
* Unmap a range of addresses.
*
* @param [in] as Address space.
* @param [in] va Virtual address.
* @param [in] pages Pages to map in.
*
* @retval true On success
* @retval false On failure
*/
bool
PMap_Unmap(AS *as, uint64_t va, uint64_t pages)
{
NOT_IMPLEMENTED();
return true;
}
/**
* PMap_AllocMap --
*
* Map a virtual mapping in an address space and back it by newly allocated
* memory.
*
* @param [in] as Address space.
* @param [in] virt Virtual address.
* @param [in] pages Pages to map in.
* @param [in] flags Flags to apply to the mapping.
*
* @retval true On success
* @retval false On failure
*/
bool
PMap_AllocMap(AS *as, uint64_t virt, uint64_t len, uint64_t flags)
{
NOT_IMPLEMENTED();
return true;
}
/**
* PMap_SystemLookup --
*
* Lookup a kernel virtual address in a page table and return a pointer to the
* page entry. This function allocates page tables as necessary to fill in the
* 4-level heirarchy.
*
* @param [in] va Virtual address to lookup.
* @param [out] entry Pointer will point to the PageEntry.
* @param [in] size Page size we want to use.
*/
void
PMap_SystemLookup(uint64_t va, PageEntry **entry, int size)
{
PMapLookupEntry(&systemAS, va, entry, size);
}
/**
* PMap_SystemLMap --
*
* Map a range of large (2MB) physical pages to virtual pages in the kernel
* address space that is shared by all processes.
*
* @param [in] phys Physical address.
* @param [in] virt Virtual address.
* @param [in] lpages Large pages to map in.
* @param [in] flags Flags to apply to the mapping.
*
* @retval true On success
* @retval false On failure
*/
bool
PMap_SystemLMap(uint64_t phys, uint64_t virt, uint64_t lpages, uint64_t flags)
{
NOT_IMPLEMENTED();
return true;
}
/**
* PMap_SystemLMap --
*
* Map a range of physical pages to virtual pages in the kernel address space
* that is shared by all processes.
*
* @param [in] phys Physical address.
* @param [in] virt Virtual address.
* @param [in] pages Pages to map in.
* @param [in] flags Flags to apply to the mapping.
*
* @retval true On success
* @retval false On failure
*/
bool
PMap_SystemMap(uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags)
{
NOT_IMPLEMENTED();
return true;
}
/**
* PMap_SystemUnmap --
*
* We do not currently use this!
*/
bool
PMap_SystemUnmap(uint64_t virt, uint64_t pages)
{
NOT_IMPLEMENTED();
return false;
}
static uint64_t
AddrFromIJKL(uint64_t i, uint64_t j, uint64_t k, uint64_t l)
{
return (i << 39) | (j << HUGE_PGSHIFT) | (k << LARGE_PGSHIFT) | (l << PGSHIFT);
}
void
PMap_Dump(AS *space)
{
return;
}
static void
Debug_PMapDump(int argc, const char *argv[])
{
PMap_Dump(currentAS[CPU()]);
}
REGISTER_DBGCMD(pmapdump, "Dump memory mappings", Debug_PMapDump);

26
sys/arm64/support.S Normal file
View File

@ -0,0 +1,26 @@
/*
* Support Functions
*/
#include <errno.h>
#include <machine/asm.h>
.text
// copy_unsafe(to, from, len)
FUNC_BEGIN(copy_unsafe)
.globl copy_unsafe_done
copy_unsafe_done:
.globl copy_unsafe_fault
copy_unsafe_fault:
FUNC_END(copy_unsafe)
// copystr_unsafe(to, from, len)
FUNC_BEGIN(copystr_unsafe)
.globl copystr_unsafe_done
copystr_unsafe_done:
.globl copystr_unsafe_fault
copystr_unsafe_fault:
.globl copystr_unsafe_toolong
FUNC_END(copystr_unsafe)

19
sys/arm64/switch.S Normal file
View File

@ -0,0 +1,19 @@
/*
* Trap Handlers
*/
#include <machine/asm.h>
.text
# switch(uint64_t *oldsp, uint64_t newsp)
# %rdi: oldsp
# %rsi: newsp
FUNC_BEGIN(switchstack)
# Save callee saved registers of old thread
# Switch stack from old to new thread
# Restore callee saved registers of new thread
FUNC_END(switchstack)

68
sys/arm64/thread.c Normal file
View File

@ -0,0 +1,68 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/kconfig.h>
#include <sys/kassert.h>
#include <sys/kmem.h>
#include <sys/mp.h>
#include <sys/thread.h>
#include <machine/cpu.h>
#include <machine/cpuop.h>
#include <machine/trap.h>
#include <machine/pmap.h>
extern void ThreadKThreadEntry(TrapFrame *tf);
extern void switchstack(uint64_t *oldrsp, uint64_t rsp);
void
Thread_InitArch(Thread *thr)
{
thr->arch.useFP = true;
}
void
Thread_SetupKThread(Thread *thr, void (*f)(),
uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
{
// Initialize stack
uint64_t stacktop = thr->kstack + PGSIZE;
ThreadArchStackFrame *sf;
TrapFrame *tf;
tf = (TrapFrame *)(stacktop - sizeof(*tf));
sf = (ThreadArchStackFrame *)(stacktop - sizeof(*tf) - sizeof(*sf));
memset(tf, 0, sizeof(*tf));
memset(sf, 0, sizeof(*sf));
// Setup thread exit function on stack
}
static void
ThreadEnterUserLevelCB(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
{
TrapFrame tf;
memset(&tf, 0, sizeof(tf));
Trap_Pop(&tf);
}
void
Thread_SetupUThread(Thread *thr, uintptr_t rip, uintptr_t arg)
{
Thread_SetupKThread(thr, ThreadEnterUserLevelCB, rip,
thr->ustack, arg);
}
void
Thread_SwitchArch(Thread *oldthr, Thread *newthr)
{
// Jump to trapframe
switchstack(&oldthr->arch.rsp, newthr->arch.rsp);
}

25
sys/arm64/time.c Normal file
View File

@ -0,0 +1,25 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/kassert.h>
#include <sys/kdebug.h>
#include <sys/ktime.h>
#include <machine/cpu.h>
#include <machine/cpuop.h>
uint64_t
Time_GetTSC()
{
return 0;
}
static void
Debug_ReadTSC(int argc, const char *argv[])
{
kprintf("RDTSC: %lld\n", Time_GetTSC());
}
REGISTER_DBGCMD(readtsc, "Print current timestamp", Debug_ReadTSC);

121
sys/arm64/trap.c Normal file
View File

@ -0,0 +1,121 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/kconfig.h>
#include <sys/kassert.h>
#include <sys/kdebug.h>
#include <sys/kmem.h>
#include <sys/ktime.h>
#include <sys/spinlock.h>
#include <sys/irq.h>
#include <sys/syscall.h>
#include <sys/mp.h>
#include <machine/cpu.h>
#include <machine/trap.h>
#include <machine/mp.h>
#include <sys/thread.h>
extern uint64_t trap_table[T_MAX];
extern void trap_pop(TrapFrame *tf);
extern void Debug_Breakpoint(TrapFrame *tf);
extern void Debug_HaltIPI(TrapFrame *tf);
extern void KTimer_Process();
static uint64_t intStats[256];
void
Trap_Init()
{
int i;
kprintf("Initializing IDT... ");
for (i = 0; i < 256; i++) {
intStats[i] = 0;
}
kprintf("Done!\n");
}
void
Trap_InitAP()
{
}
void
Trap_Dump(TrapFrame *tf)
{
kprintf("CPU %d\n", CPU());
kprintf("Interrupt %d Error Code: %016llx\n",
tf->vector, tf->errcode);
}
void
Trap_StackDump(TrapFrame *tf)
{
uint64_t rsp;
uint64_t *data;
// XXX: This should use safe copy
for (rsp = tf->rsp; (rsp & 0xFFF) != 0; rsp += 8) {
data = (uint64_t *)rsp;
kprintf("%016llx: %016llx\n", rsp, *data);
}
}
extern int copy_unsafe(void *to, void *from, uintptr_t len);
extern void copy_unsafe_done(void);
extern void copy_unsafe_fault(void);
extern int copystr_unsafe(void *to, void *from, uintptr_t len);
extern void copystr_unsafe_done(void);
extern void copystr_unsafe_fault(void);
void
trap_entry(TrapFrame *tf)
{
// XXX: USE ATOMIC!
intStats[tf->vector]++;
// Debug NMI
// Kernel
// Kernel Debugger
// User IO
// Halt on kernel errors
// User space exceptions
// IRQs
// Debug IPI
// Cross calls
kprintf("Unhandled Interrupt 0x%x!\n", tf->vector);
Trap_Dump(tf);
while (1)
hlt();
}
static void
Debug_Traps(int argc, const char *argv[])
{
int i;
kprintf("Trap Interrupts Trap Interrupts\n");
for (i = 0; i < T_MAX / 2; i++)
{
kprintf("%-4d %-12d %-4d %-12d\n",
i, intStats[i],
T_MAX / 2 + i, intStats[T_MAX / 2 + i]);
}
}
REGISTER_DBGCMD(traps, "Print trap statistics", Debug_Traps);

38
sys/arm64/trapentry.S Normal file
View File

@ -0,0 +1,38 @@
/*
* Trap Handlers
*/
.extern trap_entry
.text
.macro TRAP_NOEC TRAPNUM
trap\TRAPNUM:
# Push top of the trap frame
.endm
.macro TRAP_EC TRAPNUM
trap\TRAPNUM:
# Push top of the trap frame
.endm
.globl trap_table
trap_table:
.quad trap0
TRAP_NOEC 0 // DE
trap_common:
# Create the rest of the trap frame
# Pass the trap frame as an argument to trap_entry
.globl trap_return
trap_return:
# Skip error code and vector number
# Return to userspace
.globl Trap_Pop
Trap_Pop:

View File

@ -2,9 +2,17 @@
#ifndef __MP_H__
#define __MP_H__
#if defined(__x86_64__)
uint32_t LAPIC_CPU();
#define CPU LAPIC_CPU
#elif defined(__aarch64__)
static inline int ARM_CPU()
{
return 0;
}
#define CPU ARM_CPU
#endif
#endif /* __MP_H__ */