-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a1d7faf
commit aae265a
Showing
6 changed files
with
317 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
CROSS_COMPILE = aarch64-elf- | ||
CC = $(CROSS_COMPILE)gcc | ||
CFLAGS = -Wall -fno-common -O0 -g \ | ||
-nostdlib -nostartfiles -ffreestanding \ | ||
-march=armv8-a | ||
|
||
kernel8.img: linker.ld boot.o hello.o | ||
aarch64-elf-ld boot.o hello.o -T linker.ld -o kernel8.img | ||
aarch64-elf-objdump -d kernel8.img > kernel.list | ||
aarch64-elf-objdump -t kernel8.img | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym | ||
|
||
boot.o: boot.S | ||
aarch64-elf-gcc -c boot.S -o boot.o | ||
|
||
basicfct: | ||
aarch64-linux-gnu-as -o basicfct.o basicfct.S | ||
aarch64-linux-gnu-ld -s -o basicfct basicfct.o | ||
|
||
clean: | ||
rm -f kernel8.img *.o *.list *.sym basicfct | ||
|
||
.PHONY: all qemu clean | ||
|
||
|
||
# assembler compile: | ||
# aarch64-elf-as -c boot.S -o boot.o | ||
|
||
# c compile: | ||
# aarch64-elf-gcc -ffreestanding -c hello.c -o hello.o -O2 -Wall -Wextra | ||
|
||
# link kernel (doesn't work properly though?) | ||
# aarch64-elf-gcc -T linker.ld -o myos.elf -ffreestanding -O2 -nostdlib boot.o hello.o -lgcc | ||
# aarch64-elf-objcopy myos.elf -O binary kernel8.img | ||
|
||
# run emulator | ||
# qemu-system-aarch64 -M raspi3 -serial mon:stdio -kernel kernel8.img --nographic | ||
# extra / removable flags: | ||
# -serial mon:stdio (input works buggy) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
.data | ||
|
||
/* from: https://peterdn.com/post/2020/08/22/hello-world-in-arm64-assembly/ */ | ||
msg: | ||
.ascii "Hello, ARM64!\n" | ||
len = . - msg | ||
|
||
.text | ||
.type myadd,%function | ||
|
||
.globl printh | ||
printh: | ||
/* syscall write(int fd, const void *buf, size_t count) */ | ||
mov x0, #1 /* fd := STDOUT_FILENO */ | ||
ldr x1, =msg /* buf := msg */ | ||
ldr x2, =len /* count := len */ | ||
mov w8, #64 /* write is syscall #64 */ | ||
svc #0 /* invoke syscall */ | ||
|
||
/* syscall exit(int status) */ | ||
mov x0, #0 /* status := 0 */ | ||
mov w8, #93 /* exit is syscall #1 */ | ||
svc #0 /* invoke syscall */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// AArch64 mode | ||
|
||
// To keep this in the first portion of the binary. | ||
.section ".text.boot" | ||
|
||
// Make _start global. | ||
.globl _start | ||
|
||
.org 0x80000 | ||
// Entry point for the kernel. Registers: | ||
// x0 -> 32 bit pointer to DTB in memory (primary core only) / 0 (secondary cores) | ||
// x1 -> 0 | ||
// x2 -> 0 | ||
// x3 -> 0 | ||
// x4 -> 32 bit kernel entry point, _start location | ||
_start: | ||
// set stack before our code | ||
ldr x5, =_start | ||
mov sp, x5 | ||
|
||
// clear bss | ||
ldr x5, =__bss_start | ||
ldr w6, =__bss_size | ||
3: cbz w6, 4f | ||
str xzr, [x5], #8 | ||
sub w6, w6, #1 | ||
cbnz w6, 3b | ||
|
||
// jump to C code, should not return | ||
4: bl kernel_main | ||
// for failsafe, halt this core too | ||
// b not_here |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
#include <stddef.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
|
||
// board type | ||
int raspi = 3; // raspi 4 wird noch nicht unterstuetzt | ||
|
||
// extern void printh(); // is a system call and not printf or so at the moment so won't work I assume | ||
|
||
// Memory-Mapped I/O output | ||
static inline void mmio_write(uint32_t reg, uint32_t data) | ||
{ | ||
*(volatile uint32_t*)reg = data; | ||
} | ||
|
||
// Memory-Mapped I/O input | ||
static inline uint32_t mmio_read(uint32_t reg) | ||
{ | ||
return *(volatile uint32_t*)reg; | ||
} | ||
|
||
// Loop <delay> times in a way that the compiler won't optimize away | ||
static inline void delay(int32_t count) | ||
{ | ||
asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n" | ||
: "=r"(count): [count]"0"(count) : "cc"); | ||
} | ||
|
||
//----------- | ||
// The MMIO area base address. | ||
/*switch (raspi) { | ||
case 2: | ||
case 3: MMIO_BASE = 0x3F000000; break; // for raspi2 & 3 | ||
case 4: MMIO_BASE = 0xFE000000; break; // for raspi4 | ||
default: MMIO_BASE = 0x20000000; break; // for raspi1, raspi zero etc. | ||
}*/ | ||
#define MMIO_BASE 0x3F000000 | ||
|
||
// The offsets for reach register. | ||
#define GPIO_BASE (MMIO_BASE + 0x200000) | ||
|
||
// Controls actuation of pull up/down to ALL GPIO pins. | ||
#define GPPUD (GPIO_BASE + 0x94) | ||
|
||
// Controls actuation of pull up/down for specific GPIO pin. | ||
#define GPPUDCLK0 (GPIO_BASE + 0x98) | ||
|
||
// The base address for UART. | ||
#define UART0_BASE (GPIO_BASE + 0x1000) // for raspi4 0xFE201000, raspi2 & 3 0x3F201000, and 0x20201000 for raspi1 | ||
|
||
// The offsets for reach register for the UART. | ||
#define UART0_DR (UART0_BASE + 0x00) | ||
#define UART0_RSRECR (UART0_BASE + 0x04) | ||
#define UART0_FR (UART0_BASE + 0x18) | ||
#define UART0_ILPR (UART0_BASE + 0x20) | ||
#define UART0_IBRD (UART0_BASE + 0x24) | ||
#define UART0_FBRD (UART0_BASE + 0x28) | ||
#define UART0_LCRH (UART0_BASE + 0x2C) | ||
#define UART0_CR (UART0_BASE + 0x30) | ||
#define UART0_IFLS (UART0_BASE + 0x34) | ||
#define UART0_IMSC (UART0_BASE + 0x38) | ||
#define UART0_RIS (UART0_BASE + 0x3C) | ||
#define UART0_MIS (UART0_BASE + 0x40) | ||
#define UART0_ICR (UART0_BASE + 0x44) | ||
#define UART0_DMACR (UART0_BASE + 0x48) | ||
#define UART0_ITCR (UART0_BASE + 0x80) | ||
#define UART0_ITIP (UART0_BASE + 0x84) | ||
#define UART0_ITOP (UART0_BASE + 0x88) | ||
#define UART0_TDR (UART0_BASE + 0x8C) | ||
|
||
// The offsets for Mailbox registers | ||
#define MBOX_BASE (MMIO_BASE + 0xB880) | ||
#define MBOX_READ (MBOX_BASE + 0x00) | ||
#define MBOX_STATUS (MBOX_BASE + 0x18) | ||
#define MBOX_WRITE (MBOX_BASE + 0x20) | ||
//----------- | ||
|
||
// A Mailbox message with set clock rate of PL011 to 3MHz tag | ||
volatile unsigned int __attribute__((aligned(16))) mbox[9] = { | ||
9*4, 0, 0x38002, 12, 8, 2, 3000000, 0 ,0 | ||
}; | ||
|
||
void uart_init() | ||
{ | ||
// Disable UART0. | ||
mmio_write(UART0_CR, 0x00000000); | ||
// Setup the GPIO pin 14 && 15. | ||
|
||
// Disable pull up/down for all GPIO pins & delay for 150 cycles. | ||
mmio_write(GPPUD, 0x00000000); | ||
delay(150); | ||
|
||
// Disable pull up/down for pin 14,15 & delay for 150 cycles. | ||
mmio_write(GPPUDCLK0, (1 << 14) | (1 << 15)); | ||
delay(150); | ||
|
||
// Write 0 to GPPUDCLK0 to make it take effect. | ||
mmio_write(GPPUDCLK0, 0x00000000); | ||
|
||
// Clear pending interrupts. | ||
mmio_write(UART0_ICR, 0x7FF); | ||
|
||
// Set integer & fractional part of baud rate. | ||
// Divider = UART_CLOCK/(16 * Baud) | ||
// Fraction part register = (Fractional part * 64) + 0.5 | ||
// Baud = 115200. | ||
|
||
// For Raspi3 and 4 the UART_CLOCK is system-clock dependent by default. | ||
// Set it to 3Mhz so that we can consistently set the baud rate | ||
if (raspi >= 3) { | ||
// UART_CLOCK = 30000000; | ||
unsigned int r = (((unsigned int)(&mbox) & ~0xF) | 8); | ||
// wait until we can talk to the VC | ||
while ( mmio_read(MBOX_STATUS) & 0x80000000 ) { } | ||
// send our message to property channel and wait for the response | ||
mmio_write(MBOX_WRITE, r); | ||
while ( (mmio_read(MBOX_STATUS) & 0x40000000) || mmio_read(MBOX_READ) != r ) { } | ||
} | ||
|
||
// Divider = 3000000 / (16 * 115200) = 1.627 = ~1. | ||
mmio_write(UART0_IBRD, 1); | ||
// Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40. | ||
mmio_write(UART0_FBRD, 40); | ||
|
||
// Enable FIFO & 8 bit data transmission (1 stop bit, no parity). | ||
mmio_write(UART0_LCRH, (1 << 4) | (1 << 5) | (1 << 6)); | ||
|
||
// Mask all interrupts. | ||
mmio_write(UART0_IMSC, (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | | ||
(1 << 7) | (1 << 8) | (1 << 9) | (1 << 10)); | ||
|
||
// Enable UART0, receive & transfer part of UART. | ||
mmio_write(UART0_CR, (1 << 0) | (1 << 8) | (1 << 9)); | ||
} | ||
|
||
void uart_putc(unsigned char c) | ||
{ | ||
// Wait for UART to become ready to transmit. | ||
while ( mmio_read(UART0_FR) & (1 << 5) ) { } | ||
mmio_write(UART0_DR, c); | ||
} | ||
|
||
unsigned char uart_getc() | ||
{ | ||
// Wait for UART to have received something. | ||
while ( mmio_read(UART0_FR) & (1 << 4) ) { } | ||
return mmio_read(UART0_DR); | ||
} | ||
|
||
void uart_puts(const char* str) | ||
{ | ||
for (size_t i = 0; str[i] != '\0'; i ++) | ||
uart_putc((unsigned char)str[i]); | ||
} | ||
|
||
#if defined(__cplusplus) | ||
extern "C" /* Use C linkage for kernel_main. */ | ||
#endif | ||
|
||
#ifdef AARCH64 | ||
// arguments for AArch64 | ||
void kernel_main(uint64_t dtb_ptr32, uint64_t x1, uint64_t x2, uint64_t x3) | ||
#else | ||
// arguments for AArch32 | ||
void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) | ||
#endif | ||
{ | ||
uart_init(); | ||
// printh(); | ||
uart_puts("Hello, kernel World!\r\n"); | ||
|
||
while (1) | ||
uart_putc(uart_getc()); | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
ENTRY(_start) | ||
|
||
SECTIONS | ||
{ | ||
/* Starts at LOADER_ADDR. */ | ||
. = 0x80000; | ||
/* For AArch32, use . = 0x8000; */ | ||
__start = .; | ||
__text_start = .; | ||
.text : | ||
{ | ||
KEEP(*(.text.boot)) | ||
*(.text) | ||
} | ||
. = ALIGN(4096); /* align to page size */ | ||
__text_end = .; | ||
|
||
__rodata_start = .; | ||
.rodata : | ||
{ | ||
*(.rodata) | ||
} | ||
. = ALIGN(4096); /* align to page size */ | ||
__rodata_end = .; | ||
|
||
__data_start = .; | ||
.data : | ||
{ | ||
*(.data) | ||
} | ||
. = ALIGN(4096); /* align to page size */ | ||
__data_end = .; | ||
|
||
__bss_start = .; | ||
.bss : | ||
{ | ||
bss = .; | ||
*(.bss) | ||
} | ||
. = ALIGN(4096); /* align to page size */ | ||
__bss_end = .; | ||
__bss_size = __bss_end - __bss_start; | ||
__end = .; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/bin/bash | ||
echo "Press Ctrl-A and then X to exit QEMU" | ||
echo | ||
qemu-system-aarch64 -M raspi3 -kernel kernel8.img --nographic |