commit 01af0bade13dc0667ed6eee565ddb94ed8520463 Author: Daniil Gentili Date: Sat Jan 29 21:48:37 2022 +0100 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e99d373 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.img +build diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8686cc3 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all: kernel8.img + +install: all + udisksctl mount -b /dev/mmcblk0p1 + cp kernel8.img /run/media/daniil/*/ + umount /run/media/daniil/* + sync + +clean: + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img diff --git a/include/mini_uart.h b/include/mini_uart.h new file mode 100644 index 0000000..61e018b --- /dev/null +++ b/include/mini_uart.h @@ -0,0 +1,6 @@ +#pragma once + +void uart_init(void); +void uart_send(char c); +char uart_recv(); +void uart_send_string(const char *str); \ No newline at end of file diff --git a/include/mm.h b/include/mm.h new file mode 100644 index 0000000..56308d3 --- /dev/null +++ b/include/mm.h @@ -0,0 +1,4 @@ +#pragma once + +// Lower memory limit at 4mb, kernel stack grows down back to 0 but we don't need much, 4mb is enough. +#define LOW_MEMORY (4 << 20) \ No newline at end of file diff --git a/include/reg.h b/include/reg.h new file mode 100644 index 0000000..5025c27 --- /dev/null +++ b/include/reg.h @@ -0,0 +1,22 @@ +#pragma once + +#define BUS_OFFSET 0x3F000000 + +#define AUX_MU_IER_REG (0x7E215044 - BUS_OFFSET) + +#define GPFSEL1 (0x7E200004 - BUS_OFFSET) +#define GPPUD (0x7E200094 - BUS_OFFSET) +#define GPPUDCLK0 (0x7E200098 - BUS_OFFSET) +#define AUX_ENABLES (0x7E215004 - BUS_OFFSET) +#define AUX_MU_CNTL_REG (0x7E215060 - BUS_OFFSET) +#define AUX_MU_IO_REG (0x7E215040 - BUS_OFFSET) +#define AUX_MU_IER_REG (0x7E215044 - BUS_OFFSET) +#define AUX_MU_IIR_REG (0x7E215048 - BUS_OFFSET) +#define AUX_MU_LCR_REG (0x7E21504c - BUS_OFFSET) +#define AUX_MU_MCR_REG (0x7E215050 - BUS_OFFSET) +#define AUX_MU_LSR_REG (0x7E215054 - BUS_OFFSET) +#define AUX_MU_BAUD_REG (0x7E215068 - BUS_OFFSET) + +#define UART_BASE (0x7E201000-BUS_OFFSET) + +#define ST_CLO (0x7e003004 - BUS_OFFSET) diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..53ac73b --- /dev/null +++ b/include/utils.h @@ -0,0 +1,6 @@ +#pragma once + +extern void put32(unsigned long reg, unsigned int value); +extern unsigned int get32(unsigned long reg); + +extern void delay(unsigned long duration); diff --git a/src/boot.S b/src/boot.S new file mode 100644 index 0000000..1969449 --- /dev/null +++ b/src/boot.S @@ -0,0 +1,20 @@ +#include "mm.h" + +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 // Copy processor affinity register into x0 + and x0, x0, #0xFF // Affinity 0 @ 0:7 is the core ID + cbnz x0, halt // Halt if core != 0 + + adr x0, bss_begin // Argument 1: bss_begin + adr x1, bss_end + sub x1, x1, x0 // Argument 2: bss_end-bss_begin + bl memzero // memzero(bss_begin, bss_end-bss_begin) + + mov sp, #LOW_MEMORY // Initialize the kernel stack pointer to +4mb, growing downwards + bl kernel_main // kernel_main() + +halt: + b halt \ No newline at end of file diff --git a/src/kernel.c b/src/kernel.c new file mode 100644 index 0000000..989dd2a --- /dev/null +++ b/src/kernel.c @@ -0,0 +1,13 @@ +#include "mini_uart.h" +#include "reg.h" +#include "utils.h" + +void kernel_main(void) +{ + uart_init(); + uart_send_string("Hello, world!\r\n"); + + while (1) { + uart_send(uart_recv()); + } +} diff --git a/src/linker.ld b/src/linker.ld new file mode 100644 index 0000000..313eaa5 --- /dev/null +++ b/src/linker.ld @@ -0,0 +1,11 @@ +SECTIONS +{ + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + . = ALIGN(0x8); + bss_begin = .; + .bss : { *(.bss*) } + bss_end = .; +} \ No newline at end of file diff --git a/src/mini_uart.c b/src/mini_uart.c new file mode 100644 index 0000000..617011b --- /dev/null +++ b/src/mini_uart.c @@ -0,0 +1,89 @@ +#include "mini_uart.h" +#include "reg.h" + +#define UART_DR (UART_BASE+0x0) +#define UART_FR (UART_BASE+0x18) + +#define UART_IBRD (UART_BASE+0x24) +#define UART_FBRD (UART_BASE+0x28) +#define UART_LCRH (UART_BASE+0x2C) +#define UART_CR (UART_BASE+0x30) +#define UART_ICR (UART_BASE+0x44) + +// UART clock baud rate divisor register +// Why is this undocumented?? +#define CM_UARTDIV (0x7e1010f4-BUS_OFFSET) + +// UART control register +// Why is this undocumented?? +#define CM_UARTCTL 0x7e1010f0 + + +// cucumber moment +#define CM_PASSWORD 0x5a000000 +#define CM_SRC_OSC 1 + +#define CM_UARTCTL_FRAC_SET 0x00000200 +#define CM_UARTCTL_ENAB_SET 0x00000010 + +void uart_init(void) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7<<12); // clean gpio14 + selector |= 4<<12; // set alt1 for gpio14 + selector &= ~(7<<15); // clean gpio15 + selector |= 4<<15; // set alt1 for gpio 15 + put32(GPFSEL1,selector); + + put32(UART_CR, 0); + + put32(GPPUD,0); + delay(150); + put32(GPPUDCLK0,(1<<14)|(1<<15)); + delay(150); + put32(GPPUDCLK0,0); + + /*put32(AUX_ENABLES,1); //Enable mini uart (this also enables access to its registers) + put32(AUX_MU_CNTL_REG,0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(AUX_MU_IER_REG,0); //Disable receive and transmit interrupts + put32(AUX_MU_LCR_REG,3); //Enable 8 bit mode + put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high + put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200 + + put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver*/ + + put32(CM_UARTDIV, CM_PASSWORD | 0x6666); + put32(CM_UARTDIV, CM_PASSWORD | CM_SRC_OSC | CM_UARTCTL_FRAC_SET | CM_UARTCTL_ENAB_SET); + + put32(UART_ICR, 0x7FF); + put32(UART_IBRD, 1); + put32(UART_FBRD, 40); + put32(UART_LCRH, 0x70); + put32(UART_CR, 0x301); +} + +void uart_send(char c) +{ + //while(!(get32(AUX_MU_LSR_REG) & 0x20)); + //put32(AUX_MU_IO_REG, c); + + while(get32(UART_FR) & 0x20); + put32(UART_DR, c); +} +char uart_recv() +{ + //while (!(get32(AUX_MU_LSR_REG) & 0x1)); + //return get32(AUX_MU_IO_REG) & 0xFF; + + while(get32(UART_FR) & 0x10); + return put32(UART_DR) & 0xFF; +} + +void uart_send_string(const char *str) +{ + for (int i = 0; str[i] != '\0'; i++) { + uart_send(str[i]); + } +} \ No newline at end of file diff --git a/src/utils.S b/src/utils.S new file mode 100644 index 0000000..8d29330 --- /dev/null +++ b/src/utils.S @@ -0,0 +1,22 @@ +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret + +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret