initial commit

This commit is contained in:
Lauchmelder 2022-01-20 12:34:33 +01:00
commit 1e778fc163
12 changed files with 431 additions and 0 deletions

30
Makefile Normal file
View file

@ -0,0 +1,30 @@
GCCPATH = /opt/gcc-arm/bin
CC = $(GCCPATH)/aarch64-none-elf-gcc
LD = $(GCCPATH)/aarch64-none-elf-ld
OBJCOPY = $(GCCPATH)/aarch64-none-elf-objcopy
GCCFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
OUTDIR = ./out/bin
HFILES = $(wildcard *.h include/*.h)
CFILES = $(wildcard *.c src/*.c)
_OFILES = $(CFILES:.c=.o)
OFILES = $(_OFILES:src/%=out/%)
all: clean kernel8.img
out/%.o: src/%.c $(HFILES)
@echo "Building $@"
@mkdir -p $(@D)
@$(CC) -Iinclude -c $< -o $@ $(GCCLFAGS)
kernel8.img: $(OFILES)
@echo "Linking kernel"
@mkdir -p bin
@$(LD) -nostdlib $(OFILES) -T link.ld -o out/kernel8.elf
@$(OBJCOPY) -O binary out/kernel8.elf bin/kernel8.img
@echo "Done!"
clean:
@/bin/rm -rf out/ > /dev/null 2> /dev/null || true

6
burn.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
mount -t drvfs f: /mnt/f
cp bin/kernel8.img /mnt/f
umount /mnt/f
echo "Done!"

6
include/convert.h Normal file
View file

@ -0,0 +1,6 @@
#pragma once
#include "stdint.h"
int stoi(const char* string);
char* itoa(int number, char* string);

15
include/gpio.h Normal file
View file

@ -0,0 +1,15 @@
#include "stdint.h"
// Functions for peeking/poking into memory
void poke(int64_t addr, uint32_t val);
uint32_t peek(int64_t addr);
int32_t gpio_call(uint32_t pin, uint32_t reg, uint32_t value, uint32_t field_size);
uint32_t gpio_set (uint32_t pin, uint32_t value);
uint32_t gpio_clear (uint32_t pin, uint32_t value);
uint32_t gpio_fselect(uint32_t pin, uint32_t value);
uint32_t gpio_pull (uint32_t pin, uint32_t value);
void gpio_setAltMode5(uint32_t pin);

11
include/io.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include "stdint.h"
void uart_init();
void uart_putchar(char c);
void uart_puts(const char* string);
char uart_getchar();
char* uart_gets(char* string);

13
include/stdint.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
typedef char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long uint64_t;
typedef uint64_t size_t;

19
link.ld Normal file
View file

@ -0,0 +1,19 @@
SECTIONS
{
. = 0x80000;
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
}
_end = .;
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start) >> 3;

29
src/boot.S Normal file
View file

@ -0,0 +1,29 @@
.section ".text.boot"
.global _start
_start:
# Check if on main core
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, 2f
1: # Infinite loop
b 1b
2: # Set up stack
ldr x1, =_start
mov sp, x1
# memzero the BSS section
ldr x1, =__bss_start
ldr w2, =__bss_size
3: cbz w2, 4f
str xzr, [x1], #8
sub w2, w2, #1
cbnz w2, 3b
4: # Jump to main() in C
ldr x4, =_start
bl main
b 1b

54
src/convert.c Normal file
View file

@ -0,0 +1,54 @@
#include "convert.h"
#include "io.h"
int stoi(const char* string)
{
int output = 0;
int32_t sign = 1;
if(*string == '-')
{
string++;
sign = -1;
}
while(*string >= '0' && *string <= '9')
{
output *= 10;
output += sign * (*string++ - '0');
}
return output;
}
char* itoa(int number, char* string)
{
volatile char* temp = (volatile char*)0x40000000;
int i = 0;
if(number == 0)
{
temp[i++] = '0';
}
else
{
for(int n = (number < 0 ? -number : number); n > 0; n /= 10)
{
temp[i++] = '0' + (n % 10);
}
}
if(number < 0)
{
temp[i++] = '-';
}
temp[i] = '\0';
string[i] = '\0';
while(*temp)
{
string[--i] = *temp++;
}
return string;
}

76
src/gpio.c Normal file
View file

@ -0,0 +1,76 @@
#include "gpio.h"
void poke(int64_t addr, uint32_t val)
{
*(volatile uint32_t*)addr = val;
}
uint32_t peek(int64_t addr)
{
return *(volatile uint32_t*)addr;
}
enum
{
PERIPHERAL_BASE = 0xFE000000,
GPFSEL0 = PERIPHERAL_BASE + 0x200000,
GPSET0 = PERIPHERAL_BASE + 0x20001C,
GPCLR0 = PERIPHERAL_BASE + 0x200028,
GPPUPPDN0 = PERIPHERAL_BASE + 0x2000E4
};
enum
{
MAX_PINS = 57
};
int32_t gpio_call(uint32_t pin, uint32_t reg, uint32_t value, uint32_t field_size)
{
// Calculate a mask for the field. The mask is a string of 1's that is field_size long
uint32_t field_mask = (1 << field_size) - 1;
// Can't access pins that don't exist
if(pin > MAX_PINS) return 0;
// Can't write values that exceed the width of the field
if(value > field_mask) return 0;
uint32_t fields_per_register = 32 / field_size; // Number of fields per register
uint32_t register_addr = reg + (pin / fields_per_register) * 4; // Offset of register to base register. E.g. GPSET1 = GPSET0 + 4 bytes
uint32_t field_offset = (pin % fields_per_register) * field_size; // Number of bits the field is offset into the register
uint32_t current_value = peek(register_addr);
current_value &= ~(field_mask << field_offset); // zero the field
current_value |= value << field_offset; // set the field
poke(register_addr, current_value); // poke back into memory
return 1;
}
uint32_t gpio_set(uint32_t pin, uint32_t value)
{
return gpio_call(pin, GPSET0, value, 1);
}
uint32_t gpio_clear(uint32_t pin, uint32_t value)
{
return gpio_call(pin, GPCLR0, value, 1);
}
uint32_t gpio_fselect(uint32_t pin, uint32_t value)
{
return gpio_call(pin, GPFSEL0, value, 3);
}
uint32_t gpio_pull(uint32_t pin, uint32_t value)
{
return gpio_call(pin, GPPUPPDN0, value, 2);
}
void gpio_setAltMode5(uint32_t pin)
{
// UART1 requires the pins to float
gpio_pull(pin, 0);
gpio_fselect(pin, 2);
}

79
src/io.c Normal file
View file

@ -0,0 +1,79 @@
#include "io.h"
#include "gpio.h"
// Mini UART registers
enum
{
AUX_BASE = 0xFE000000 + 0x215000,
AUX_ENABLES = AUX_BASE + 0x04,
AUX_MU_IO_REG = AUX_BASE + 0x40,
AUX_MU_IER_REG = AUX_BASE + 0x44,
AUX_MU_IIR_REG = AUX_BASE + 0x48,
AUX_MU_LCR_REG = AUX_BASE + 0x4C,
AUX_MU_MCR_REG = AUX_BASE + 0x50,
AUX_MU_LSR_REG = AUX_BASE + 0x54,
AUX_MU_CNTL_REG = AUX_BASE + 0x60,
AUX_MU_STAT_REG = AUX_BASE + 0x64,
AUX_MU_BAUD_REG = AUX_BASE + 0x68,
AUX_UART_CLOCK = 500000000,
UART_MAX_QUEUE = 16 * 1024
};
void uart_init()
{
poke(AUX_ENABLES, 1); // Enable UART1
poke(AUX_MU_LCR_REG, 3); // 8 bit communication
poke(AUX_MU_MCR_REG, 0); // Pull RTS high
poke(AUX_MU_IER_REG, 0);
poke(AUX_MU_IIR_REG, 0xC6); // Disable interrupts
poke(AUX_MU_BAUD_REG, AUX_UART_CLOCK / (112500 * 8) - 1);
gpio_setAltMode5(14);
gpio_setAltMode5(15);
poke(AUX_MU_CNTL_REG, 3);
}
uint32_t uart_isReceiveFIFOReady() { return peek(AUX_MU_LSR_REG) & 1; }
uint32_t uart_isTransmitFIFOReady() { return peek(AUX_MU_LSR_REG) & (1 << 5); }
void uart_writeBlocking(uint8_t ch)
{
while(!uart_isTransmitFIFOReady());
poke(AUX_MU_IO_REG, (uint32_t)ch);
}
char uart_getchar()
{
while(!uart_isReceiveFIFOReady());
char in = (char)peek(AUX_MU_IO_REG);
uart_putchar(in);
if(in == '\r')
uart_writeBlocking('\n');
return in;
}
char* uart_gets(char* string)
{
char* start = string;
do
{
*string = uart_getchar();
} while(*string++ != '\r');
*(string - 1) = '\0';
return start;
}
void uart_putchar(char ch)
{
if(ch == '\n')
uart_writeBlocking('\r');
uart_writeBlocking(ch);
}
void uart_puts(const char* string)
{
while(*string)
uart_putchar(*string++);
}

93
src/kernel.c Normal file
View file

@ -0,0 +1,93 @@
#include "io.h"
#include "convert.h"
void print_clippy();
void main()
{
const char* hex_chars = "0123456789ABCDEF";
register int* start_address asm ("x4");
long int start = (long int)start_address;
uart_init();
print_clippy();
uart_puts("Boot successful! \n");
uart_puts("Started execution at 0x");
for(int i = 0; i < 8; i++)
{
uart_putchar(hex_chars[start & 0xF]);
start >>= 4;
}
char buffer[1024];
for(;;)
{
/*
uart_puts("\n\n📎 ");
int a = stoi(uart_gets(buffer));
int b = -a;
uart_puts("a: ");
uart_puts(itoa(a, buffer));
uart_puts("\nb: ");
uart_puts(itoa(b, buffer));
*/
uart_puts("\n\nPlease enter first operand\n");
uart_puts("📎 ");
int a = stoi(uart_gets(buffer));
uart_puts("\nPlease enter second operand\n");
uart_puts("📎 ");
int b = stoi(uart_gets(buffer));
uart_puts("\n");
uart_puts(itoa(a, buffer));
uart_puts(" * ");
uart_puts(itoa(b, buffer));
uart_puts(" = ");
uart_puts(itoa(a * b, buffer));
// uart_puts(buffer);
}
__asm("hlt");
}
void print_clippy()
{
uart_puts(" \n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠠⡀⢄⢀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ \n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢐⠌⡢⢑⠌⠢⢑⢐⠅⡢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⢤⣤⣴⢴⡦⣧⣌⠄⠀⠀⠀⠀⠀⠑⡰⠨⡊⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ \n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣟⣯⣷⣻⣽⣯⢷⣟⡆⠀⠀⠀⠀⠀⠀⠐⢅⢊⢌⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⢘⠨⡊⢔⠈⠉⠁⠀⠀⠀⠀⠀⠀⡤⡤⣅⣆⡢⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠊⠔⠌⠂⠀⠀⠀⠀⠀⠀⠀⠀⠘⢟⣿⢽⣷⣻⢷⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢐⣨⡴⣤⣢⡈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠩⡊⡛⢟⣿⣻⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠈⣴⢿⡽⣯⢿⣞⡿⣎⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠂⠑⠈⠄⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠠⣻⣽⢿⡽⣯⢿⣽⣻⠀⡀⠀⠀⠀⠀⠠⣈⣤⢦⣦⣂⣁⠀⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠀⠙⣾⣻⣽⣻⣽⢷⠋⠀⠀⠀⠀⠀⠈⣴⣟⣾⣻⣞⣿⣺⢧⠀⠈⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⡀⠁⠍⠑⠁⠁⠀⠀⠀⠀⠀⠀⡈⣾⣗⣯⣷⣻⣗⣿⣻⠀⠁⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠠⡠⢐⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠱⣯⡷⣟⣾⡽⣞⠏⡀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡑⢌⢂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠈⠙⠙⠓⢉⠈⢀⠀⠐⠀⠀⠠⠠⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡪⢐⠔⠀⠀⠀⠀⠠⡠⡀⠀⠀⠀⠀⠀⡅⠢⡁⠀⠀⠀⠀⠀⢀⢌⠪⠨⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡪⢐⠌⠀⠀⠀⠀⡑⡐⢌⠀⠀⠀⠀⠐⢌⠪⡀⠀⠀⠀⠀⠠⡑⢄⠕⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡪⢐⠡⠀⠀⠀⠀⠌⡌⠢⠀⠀⠀⠀⠈⡢⢑⠄⠀⠀⠀⠠⡑⢌⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢌⠢⡡⠀⠀⠀⠀⠡⡊⢌⠀⠀⠀⠀⠀⡪⢐⠌⠀⠀⠀⢌⢌⠢⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠢⡑⡐⡀⠀⠀⠀⠡⢊⠔⡀⠀⠀⠀⠀⢌⠢⡑⠀⠀⠀⡢⠢⠡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢈⠢⡑⡀⠀⠀⠀⠈⡢⢑⠄⠀⠀⠀⠀⢐⠅⡊⠄⠀⠀⡊⢌⢊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢑⠔⡐⡀⠀⠀⠀⢌⢂⠪⠀⠀⠀⠀⢐⠅⡪⠀⠀⠀⢌⠢⠡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts(" ⠀⠀⠡⡊⠔⢄⠀⠀⠀⠀⠪⠨⡊⢄⢀⢀⠢⡑⡐⠁⠀⠀⠠⡑⠅⠅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠌⡪⢐⠄⠀⠀⠀⠈⠈⠢⠡⠢⡡⢑⠐⠁⠀⠀⠀⠀⡪⠨⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts(" ⠀⠀⠀⠀⠨⢂⢅⠢⠀⠀⠀⠀⠀⠀⠁⠁⠀⠀⠀⠀⠀⠀⠀⠀⢌⢌⠢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠡⢂⠕⡡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢅⠢⡡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠡⠢⡡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠨⡂⢕⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts(" ⠀⠀⠀⠀⠀⠀⠀⠈⢊⠔⡑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠣⠨⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts(" ⠀⠀⠀⠀⠀⠊⢔⠡⡡⡁⡀⢀⠀⠀⡀⢀⠌⢌⠢⠡⡃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⡐⠌⡌⡂⡊⡢⢊⠔⢌⠢⠑⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n");
uart_puts("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠈⠂⠈⠂⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ \n");
uart_puts(" \n");
}