aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-09-07 11:54:53 +0200
committerBad Diode <bd@badd10de.dev>2021-09-07 11:54:53 +0200
commitd1e735682640c4f8ddedb0c699da33aa7f399426 (patch)
tree5f321d66fe74cb59378f880b2665f12f249a3ef2
parent4b86e6272166236c9283004f6a060d5174165796 (diff)
downloaduxnrpi-d1e735682640c4f8ddedb0c699da33aa7f399426.tar.gz
uxnrpi-d1e735682640c4f8ddedb0c699da33aa7f399426.zip
Add initial support for UART I/O
Resources: - https://github.com/bztsrc/raspi3-tutorial/tree/master/03_uart1 - https://www.youtube.com/watch?v=r3Ye08ktcMo
-rw-r--r--.gitignore1
-rw-r--r--Makefile16
-rw-r--r--src/common.h102
-rw-r--r--src/main.c12
-rw-r--r--src/shorthand.h46
-rw-r--r--src/start.s29
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
diff --git a/Makefile b/Makefile
index 475c160..f531a02 100644
--- a/Makefile
+++ b/Makefile
@@ -3,17 +3,18 @@
3.PHONY: clean run 3.PHONY: clean run
4 4
5# Compiler. 5# Compiler.
6AS := arm-none-eabi-as 6AS := aarch64-elf-as
7CC := arm-none-eabi-gcc 7CC := aarch64-elf-gcc
8OBJCOPY := arm-none-eabi-objcopy 8LD := aarch64-elf-ld
9OBJCOPY := aarch64-elf-objcopy
9 10
10# Paths. 11# Paths.
11SRC_DIR := src 12SRC_DIR := src
12BUILD_DIR := build 13BUILD_DIR := build
13 14
14# Output files. 15# Output files.
15ELF := $(BUILD_DIR)/kernel7.elf 16ELF := $(BUILD_DIR)/kernel8.elf
16IMG := $(BUILD_DIR)/kernel7.img 17IMG := $(BUILD_DIR)/kernel8.img
17 18
18# Bootstrapping files. 19# Bootstrapping files.
19OBJ_START = $(BUILD_DIR)/start.o 20OBJ_START = $(BUILD_DIR)/start.o
@@ -22,6 +23,7 @@ SRC_LINK = $(SRC_DIR)/linker.ld
22 23
23CFLAGS := -Wall -ffreestanding -O2 -nostdlib -lgcc -mgeneral-regs-only 24CFLAGS := -Wall -ffreestanding -O2 -nostdlib -lgcc -mgeneral-regs-only
24AFLAGS := 25AFLAGS :=
26LDFLAGS :=
25 27
26default: $(IMG) 28default: $(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
40clean: 42clean:
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
46run: $(IMG) 48run: $(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 */
44void 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 */
72void 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 */
82char 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 */
95void 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}
diff --git a/src/main.c b/src/main.c
index 1ce2dd1..da354c1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,3 +1,13 @@
1#include "common.h"
2
1void main(void) { 3void 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/*
2Copyright (c) 2021 Bad Diode
3
4Permission to use, copy, modify, and distribute this software for any
5purpose with or without fee is hereby granted, provided that the above
6copyright notice and this permission notice appear in all copies.
7
8THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9WITH 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
24typedef uint8_t u8;
25typedef uint16_t u16;
26typedef uint32_t u32;
27typedef uint64_t u64;
28typedef int8_t s8;
29typedef int16_t s16;
30typedef int32_t s32;
31typedef int64_t s64;
32typedef volatile u8 vu8;
33typedef volatile u16 vu16;
34typedef volatile u32 vu32;
35typedef volatile u64 vu64;
36typedef volatile s8 vs8;
37typedef volatile s16 vs16;
38typedef volatile s32 vs32;
39typedef 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.
13memzero:
14 str xzr, [x0], #8
15 subs x1, x1, #8
16 b.gt memzero
17 ret
18
19master:
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
9halt: 34halt:
10 wfe 35 wfe