diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 16 | ||||
-rw-r--r-- | src/common.h | 102 | ||||
-rw-r--r-- | src/main.c | 12 | ||||
-rw-r--r-- | src/shorthand.h | 46 | ||||
-rw-r--r-- | src/start.s | 29 |
6 files changed, 196 insertions, 10 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore | |||
@@ -0,0 +1 @@ | |||
build | |||
@@ -3,17 +3,18 @@ | |||
3 | .PHONY: clean run | 3 | .PHONY: clean run |
4 | 4 | ||
5 | # Compiler. | 5 | # Compiler. |
6 | AS := arm-none-eabi-as | 6 | AS := aarch64-elf-as |
7 | CC := arm-none-eabi-gcc | 7 | CC := aarch64-elf-gcc |
8 | OBJCOPY := arm-none-eabi-objcopy | 8 | LD := aarch64-elf-ld |
9 | OBJCOPY := aarch64-elf-objcopy | ||
9 | 10 | ||
10 | # Paths. | 11 | # Paths. |
11 | SRC_DIR := src | 12 | SRC_DIR := src |
12 | BUILD_DIR := build | 13 | BUILD_DIR := build |
13 | 14 | ||
14 | # Output files. | 15 | # Output files. |
15 | ELF := $(BUILD_DIR)/kernel7.elf | 16 | ELF := $(BUILD_DIR)/kernel8.elf |
16 | IMG := $(BUILD_DIR)/kernel7.img | 17 | IMG := $(BUILD_DIR)/kernel8.img |
17 | 18 | ||
18 | # Bootstrapping files. | 19 | # Bootstrapping files. |
19 | OBJ_START = $(BUILD_DIR)/start.o | 20 | OBJ_START = $(BUILD_DIR)/start.o |
@@ -22,6 +23,7 @@ SRC_LINK = $(SRC_DIR)/linker.ld | |||
22 | 23 | ||
23 | CFLAGS := -Wall -ffreestanding -O2 -nostdlib -lgcc -mgeneral-regs-only | 24 | CFLAGS := -Wall -ffreestanding -O2 -nostdlib -lgcc -mgeneral-regs-only |
24 | AFLAGS := | 25 | AFLAGS := |
26 | LDFLAGS := | ||
25 | 27 | ||
26 | default: $(IMG) | 28 | default: $(IMG) |
27 | 29 | ||
@@ -35,7 +37,7 @@ $(IMG): $(BUILD_DIR) $(ELF) | |||
35 | $(OBJCOPY) $(ELF) -O binary $(IMG) | 37 | $(OBJCOPY) $(ELF) -O binary $(IMG) |
36 | 38 | ||
37 | $(ELF): $(OBJ_START) $(OBJ_MAIN) | 39 | $(ELF): $(OBJ_START) $(OBJ_MAIN) |
38 | $(CC) $(CFLAGS) -T $(SRC_LINK) -o $(ELF) $(OBJ_START) $(OBJ_MAIN) | 40 | $(LD) $(LDFLAGS) -T $(SRC_LINK) -o $(ELF) $(OBJ_START) $(OBJ_MAIN) |
39 | 41 | ||
40 | clean: | 42 | clean: |
41 | rm -rf $(BUILD_DIR) | 43 | rm -rf $(BUILD_DIR) |
@@ -44,4 +46,4 @@ $(BUILD_DIR): | |||
44 | mkdir -p $(BUILD_DIR) | 46 | mkdir -p $(BUILD_DIR) |
45 | 47 | ||
46 | run: $(IMG) | 48 | run: $(IMG) |
47 | qemu-system-aarch64 -M raspi3 -kernel $(IMG) -d in_asm -serial null -serial stdio | 49 | qemu-system-aarch64 -M raspi3 -kernel $(IMG) -serial null -serial stdio |
diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..c306c6c --- /dev/null +++ b/src/common.h | |||
@@ -0,0 +1,102 @@ | |||
1 | // Header definitions for memory mapped IO and common utilities. | ||
2 | |||
3 | #include "shorthand.h" | ||
4 | |||
5 | #define MEM_BASE 0x3F000000 | ||
6 | |||
7 | // GPIO registers. | ||
8 | #define GPIO_GPFSEL0 ((vu32*)(MEM_BASE + 0x00200000)) | ||
9 | #define GPIO_GPFSEL1 ((vu32*)(MEM_BASE + 0x00200004)) | ||
10 | #define GPIO_GPFSEL2 ((vu32*)(MEM_BASE + 0x00200008)) | ||
11 | #define GPIO_GPFSEL3 ((vu32*)(MEM_BASE + 0x0020000C)) | ||
12 | #define GPIO_GPFSEL4 ((vu32*)(MEM_BASE + 0x00200010)) | ||
13 | #define GPIO_GPFSEL5 ((vu32*)(MEM_BASE + 0x00200014)) | ||
14 | #define GPIO_GPSET0 ((vu32*)(MEM_BASE + 0x0020001C)) | ||
15 | #define GPIO_GPSET1 ((vu32*)(MEM_BASE + 0x00200020)) | ||
16 | #define GPIO_GPCLR0 ((vu32*)(MEM_BASE + 0x00200028)) | ||
17 | #define GPIO_GPLEV0 ((vu32*)(MEM_BASE + 0x00200034)) | ||
18 | #define GPIO_GPLEV1 ((vu32*)(MEM_BASE + 0x00200038)) | ||
19 | #define GPIO_GPEDS0 ((vu32*)(MEM_BASE + 0x00200040)) | ||
20 | #define GPIO_GPEDS1 ((vu32*)(MEM_BASE + 0x00200044)) | ||
21 | #define GPIO_GPHEN0 ((vu32*)(MEM_BASE + 0x00200064)) | ||
22 | #define GPIO_GPHEN1 ((vu32*)(MEM_BASE + 0x00200068)) | ||
23 | #define GPIO_GPPUD ((vu32*)(MEM_BASE + 0x00200094)) | ||
24 | #define GPIO_GPPUDCLK0 ((vu32*)(MEM_BASE + 0x00200098)) | ||
25 | #define GPIO_GPPUDCLK1 ((vu32*)(MEM_BASE + 0x0020009C)) | ||
26 | |||
27 | // Auxiliary registers (Mini UART and SPI). | ||
28 | #define AUX_ENABLE ((vu8*) (MEM_BASE + 0x00215004)) | ||
29 | #define AUX_MU_IO ((vu8*) (MEM_BASE + 0x00215040)) | ||
30 | #define AUX_MU_IER ((vu8*) (MEM_BASE + 0x00215044)) | ||
31 | #define AUX_MU_IIR ((vu8*) (MEM_BASE + 0x00215048)) | ||
32 | #define AUX_MU_LCR ((vu8*) (MEM_BASE + 0x0021504C)) | ||
33 | #define AUX_MU_MCR ((vu8*) (MEM_BASE + 0x00215050)) | ||
34 | #define AUX_MU_LSR ((vu8*) (MEM_BASE + 0x00215054)) | ||
35 | #define AUX_MU_MSR ((vu8*) (MEM_BASE + 0x00215058)) | ||
36 | #define AUX_MU_SCRATCH ((vu8*) (MEM_BASE + 0x0021505C)) | ||
37 | #define AUX_MU_CNTL ((vu8*) (MEM_BASE + 0x00215060)) | ||
38 | #define AUX_MU_STAT ((vu32*)(MEM_BASE + 0x00215064)) | ||
39 | #define AUX_MU_BAUD ((vu16*)(MEM_BASE + 0x00215068)) | ||
40 | |||
41 | /** | ||
42 | * Set baud rate and characteristics (115200 8N1) and map to GPIO | ||
43 | */ | ||
44 | void uart_init() | ||
45 | { | ||
46 | register unsigned int r; | ||
47 | |||
48 | /* initialize UART */ | ||
49 | *AUX_ENABLE |=1; // enable UART1, AUX mini uart | ||
50 | *AUX_MU_CNTL = 0; | ||
51 | *AUX_MU_LCR = 3; // 8 bits | ||
52 | *AUX_MU_MCR = 0; | ||
53 | *AUX_MU_IER = 0; | ||
54 | *AUX_MU_IIR = 0xc6; // disable interrupts | ||
55 | *AUX_MU_BAUD = 270; // 115200 baud | ||
56 | /* map UART1 to GPIO pins */ | ||
57 | r=*GPIO_GPFSEL1; | ||
58 | r&=~((7<<12)|(7<<15)); // gpio14, gpio15 | ||
59 | r|=(2<<12)|(2<<15); // alt5 | ||
60 | *GPIO_GPFSEL1 = r; | ||
61 | *GPIO_GPPUD = 0; // enable pins 14 and 15 | ||
62 | r=150; while(r--) { asm volatile("nop"); } | ||
63 | *GPIO_GPPUDCLK0 = (1<<14)|(1<<15); | ||
64 | r=150; while(r--) { asm volatile("nop"); } | ||
65 | *GPIO_GPPUDCLK0 = 0; // flush GPIO setup | ||
66 | *AUX_MU_CNTL = 3; // enable Tx, Rx | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * Send a character | ||
71 | */ | ||
72 | void uart_send(unsigned int c) { | ||
73 | /* wait until we can send */ | ||
74 | do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); | ||
75 | /* write the character to the buffer */ | ||
76 | *AUX_MU_IO=c; | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * Receive a character | ||
81 | */ | ||
82 | char uart_getc() { | ||
83 | char r; | ||
84 | /* wait until something is in the buffer */ | ||
85 | do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); | ||
86 | /* read it and return */ | ||
87 | r=(char)(*AUX_MU_IO); | ||
88 | /* convert carrige return to newline */ | ||
89 | return r=='\r'?'\n':r; | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * Display a string | ||
94 | */ | ||
95 | void uart_puts(char *s) { | ||
96 | while(*s) { | ||
97 | /* convert newline to carrige return + newline */ | ||
98 | if(*s=='\n') | ||
99 | uart_send('\r'); | ||
100 | uart_send(*s++); | ||
101 | } | ||
102 | } | ||
@@ -1,3 +1,13 @@ | |||
1 | #include "common.h" | ||
2 | |||
1 | void main(void) { | 3 | void main(void) { |
2 | while(1); | 4 | // Initialize uart. |
5 | uart_init(); | ||
6 | |||
7 | uart_puts("Hello World!\n"); | ||
8 | |||
9 | // Echo input to standard output. | ||
10 | while(1) { | ||
11 | uart_send(uart_getc()); | ||
12 | } | ||
3 | } | 13 | } |
diff --git a/src/shorthand.h b/src/shorthand.h new file mode 100644 index 0000000..0897824 --- /dev/null +++ b/src/shorthand.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | Copyright (c) 2021 Bad Diode | ||
3 | |||
4 | Permission to use, copy, modify, and distribute this software for any | ||
5 | purpose with or without fee is hereby granted, provided that the above | ||
6 | copyright notice and this permission notice appear in all copies. | ||
7 | |||
8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | WITH REGARD TO THIS SOFTWARE. | ||
10 | */ | ||
11 | |||
12 | #ifndef UTILS_SHORTHAND_H | ||
13 | #define UTILS_SHORTHAND_H | ||
14 | |||
15 | #include <stdbool.h> | ||
16 | #include <stddef.h> | ||
17 | #include <stdint.h> | ||
18 | |||
19 | // | ||
20 | // This simple header just typedefs the basic C define types to a shorter name, | ||
21 | // loads the quality of life bool macro for _Bool and defines shorthand macros | ||
22 | // for byte sizes. | ||
23 | |||
24 | typedef uint8_t u8; | ||
25 | typedef uint16_t u16; | ||
26 | typedef uint32_t u32; | ||
27 | typedef uint64_t u64; | ||
28 | typedef int8_t s8; | ||
29 | typedef int16_t s16; | ||
30 | typedef int32_t s32; | ||
31 | typedef int64_t s64; | ||
32 | typedef volatile u8 vu8; | ||
33 | typedef volatile u16 vu16; | ||
34 | typedef volatile u32 vu32; | ||
35 | typedef volatile u64 vu64; | ||
36 | typedef volatile s8 vs8; | ||
37 | typedef volatile s16 vs16; | ||
38 | typedef volatile s32 vs32; | ||
39 | typedef volatile s64 vs64; | ||
40 | |||
41 | #define KB(N) ((u64)(N) * 1024) | ||
42 | #define MB(N) ((u64)KB(N) * 1024) | ||
43 | #define GB(N) ((u64)MB(N) * 1024) | ||
44 | #define TB(N) ((u64)GB(N) * 1024) | ||
45 | |||
46 | #endif // UTILS_SHORTHAND_H | ||
diff --git a/src/start.s b/src/start.s index 0fd2a5f..b142397 100644 --- a/src/start.s +++ b/src/start.s | |||
@@ -3,8 +3,33 @@ | |||
3 | .global _start | 3 | .global _start |
4 | 4 | ||
5 | _start: | 5 | _start: |
6 | ldr r3, =main | 6 | // Stop all cores except one. |
7 | blx r3 | 7 | mrs x0, mpidr_el1 |
8 | and x0, x0, #0xFF | ||
9 | cbz x0, master | ||
10 | b halt | ||
11 | |||
12 | // Helper function to clear x1 bytes starting at the x0 memory address. | ||
13 | memzero: | ||
14 | str xzr, [x0], #8 | ||
15 | subs x1, x1, #8 | ||
16 | b.gt memzero | ||
17 | ret | ||
18 | |||
19 | master: | ||
20 | // Clear bss. | ||
21 | ldr x0, =__bss_start | ||
22 | ldr x1, =__bss_size | ||
23 | sub x1, x1, x0 | ||
24 | bl memzero | ||
25 | |||
26 | // Set stack before our code. | ||
27 | ldr x0, =_start | ||
28 | mov sp, x0 | ||
29 | |||
30 | // Start C code, should not return. | ||
31 | bl main | ||
32 | b halt | ||
8 | 33 | ||
9 | halt: | 34 | halt: |
10 | wfe | 35 | wfe |