-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
uart from scratch? ok, shit gonna get serious
- Loading branch information
Showing
8 changed files
with
247 additions
and
57 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 |
---|---|---|
@@ -1,11 +1,11 @@ | ||
compile: | ||
riscv64-unknown-elf-c++ -g -ffreestanding -O0 -Wl,--gc-sections \ | ||
riscv64-unknown-linux-gnu-g++ -g -ffreestanding -O0 -mcmodel=medany -Wl,--gc-sections \ | ||
-nostartfiles -nostdlib -nodefaultlibs -Wl,-T,virt.lds\ | ||
boot.S trap.S main.cc | ||
boot.S trap.S mem.S main.cc uart.h | ||
debug: | ||
qemu-system-riscv64 -machine virt -m 128M -gdb tcp::1234 -kernel a.out -S -bios none & \ | ||
xterm -e riscv64-unknown-elf-gdb \ | ||
qemu-system-riscv64 -machine virt -m 128M -serial mon:stdio -serial null -nographic -gdb tcp::1234 -kernel a.out -S & \ | ||
xterm -e riscv64-unknown-linux-gnu-gdb \ | ||
-ex "target remote:1234" -ex "set confirm off" \ | ||
-ex "add-symbol-file ./a.out 0x80000000" | ||
run: | ||
qemu-system-riscv64 -machine virt -m 128M -kernel a.out -bios none | ||
qemu-system-riscv64 -machine virt -m 128M -serial mon:stdio -serial null -nographic -kernel a.out -bios none |
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 |
---|---|---|
@@ -1,68 +1,123 @@ | ||
# boot.s | ||
# bootloader | ||
# boot.S | ||
# bootloader for SoS | ||
# Stephen Marz | ||
# 8 February 2019 | ||
|
||
# Disable generation of compressed instructions. | ||
.option norvc | ||
|
||
# Define a .data section. | ||
.section .data | ||
.global TOTAL_NUM_HARTS | ||
TOTAL_NUM_HARTS: .byte 1 | ||
|
||
# Define a .text.init section. | ||
.section .text.init | ||
|
||
# Execution starts here. | ||
.global _start | ||
_start: | ||
csrr t0, mhartid #reading CSR mhartid | ||
bnez t0, 3f | ||
csrw satp, zero # seta supervisor address translation and protection register to 0. MMU related | ||
# Any hardware threads (hart) that are not bootstrapping | ||
# need to wait for an IPI | ||
csrr t0, mhartid | ||
bnez t0, 3f | ||
# SATP should be zero, but let's make sure | ||
csrw satp, zero | ||
|
||
# Disable linker instruction relaxation for the `la` instruction below. | ||
# This disallows the assembler from assuming that `gp` is already initialized. | ||
# This causes the value stored in `gp` to be calculated from `pc`. | ||
.option push | ||
.option norelax | ||
la gp, _global_pointer | ||
la gp, _global_pointer | ||
.option pop | ||
la a0, _bss_start | ||
la a1, _bss_end | ||
bgeu a0, a1, 2f | ||
# Set all bytes in the BSS section to zero. | ||
la a0, _bss_start | ||
la a1, _bss_end | ||
bgeu a0, a1, 2f | ||
1: | ||
sd zero, (a0) # store doubleword - guarda "duas palavras 32bits = 64" | ||
addi a0, a0, 8 # incrementa 64 bits até chegar no fim da bss | ||
bltu a0, a1, 1b | ||
sd zero, (a0) | ||
addi a0, a0, 8 | ||
bltu a0, a1, 1b | ||
2: | ||
# Control registers, set the stack, mstatus, mepc, | ||
# and mtvec to return to the main function. | ||
# li t5, 0xffff; | ||
# csrw medeleg t5 | ||
# csrw medeleg, t5 | ||
# csrw mideleg, t5 | ||
# The stack grows from bottom to top, so we put the stack pointer | ||
# to the very end of the stack range. | ||
la sp, _stack_end | ||
li t0, (0b11 << 11) | (1 << 7) | (1 << 3) | ||
# [11,12] = mpp = 11 => MACHINE PRIVILEDGE | ||
# 7 = MPIE = 1 => bit do interrupt ativo | ||
# 3 = MIE = 1 => ativo interrupcao nivel maquina | ||
csrw mstatus, t0 # load in mstatus (machine status register) (o atual estado da thread) os op | ||
# Setting `mstatus` register: | ||
# 0b11 << 11: Machine's previous protection mode is 3 (MPP=3). | ||
li t0, 0b11 << 11 | ||
csrw mstatus, t0 | ||
# Machine's exception program counter (MEPC) is set to `kinit`. | ||
la t1, kmain | ||
csrw mepc, t1 | ||
# Machine's trap vector base address is set to `asm_trap_vector`. | ||
la t2, asm_trap_vector | ||
csrw mtvec, t2 | ||
# Set the return address to get us into supervisor mode | ||
la ra, 2f | ||
# We use mret here so that the mstatus register is properly updated. | ||
mret | ||
2: | ||
# We set the return address (ra above) to this label. When kinit() is finished | ||
# in Rust, it will return here. | ||
|
||
# Setting `sstatus` (supervisor status) register: | ||
# 1 << 8 : Supervisor's previous protection mode is 1 (SPP=1 [Supervisor]). | ||
# 1 << 5 : Supervisor's previous interrupt-enable bit is 1 (SPIE=1 [Enabled]). | ||
# 1 << 1 : Supervisor's interrupt-enable bit will be set to 1 after sret. | ||
# We set the "previous" bits because the sret will write the current bits | ||
# with the previous bits. | ||
li t0, (1 << 8) | (1 << 5) | ||
csrw sstatus, t0 | ||
la t1, kmain | ||
csrw mepc, t1 # carrega no registrador de pc_exception endereco da kmain | ||
la t2, m_trap_vector | ||
csrw mtvec, t2 #carrega em no reg trap_handler o endereco do trap_handler | ||
li t3, (1 << 3) | (1 << 7) | (1 << 11) | ||
csrw mie, t3 #carrega no registrador machine interrupt enable o padrao | ||
# msie = 1 => habilita interrupcao maquina | ||
# mtie = 1 => timer modo maquina habilitado | ||
# meie = 1 => habilita interrupcoes externas | ||
la ra, 4f | ||
mret | ||
csrw sepc, t1 | ||
# Setting `mideleg` (machine interrupt delegate) register: | ||
# 1 << 1 : Software interrupt delegated to supervisor mode | ||
# 1 << 5 : Timer interrupt delegated to supervisor mode | ||
# 1 << 9 : External interrupt delegated to supervisor mode | ||
# By default all traps (interrupts or exceptions) automatically | ||
# cause an elevation to the machine privilege mode (mode 3). | ||
# When we delegate, we're telling the CPU to only elevate to | ||
# the supervisor privilege mode (mode 1) | ||
li t2, (1 << 1) | (1 << 5) | (1 << 9) | ||
csrw mideleg, t2 | ||
# Setting `sie` (supervisor interrupt enable) register: | ||
# This register takes the same bits as mideleg | ||
# 1 << 1 : Supervisor software interrupt enable (SSIE=1 [Enabled]) | ||
# 1 << 5 : Supervisor timer interrupt enable (STIE=1 [Enabled]) | ||
# 1 << 9 : Supervisor external interrupt enable (SEIE=1 [Enabled]) | ||
csrw sie, t2 | ||
# Setting `stvec` (supervisor trap vector) register: | ||
# Essentially this is a function pointer, but the last two bits can be 00 or 01 | ||
# 00 : All exceptions set pc to BASE | ||
# 01 : Asynchronous interrupts set pc to BASE + 4 x scause | ||
la t3, asm_trap_vector | ||
csrw stvec, t3 | ||
# kinit() is required to return back the SATP value (including MODE) via a0 | ||
csrw satp, a0 | ||
# Force the CPU to take our SATP register. | ||
# To be efficient, if the address space identifier (ASID) portion of SATP is already | ||
# in cache, it will just grab whatever's in cache. However, that means if we've updated | ||
# it in memory, it will be the old table. So, sfence.vma will ensure that the MMU always | ||
# grabs a fresh copy of the SATP register and associated tables. | ||
sfence.vma | ||
# sret will put us in supervisor mode and re-enable interrupts | ||
sret | ||
3: | ||
|
||
# Parked harts go here. We need to set these | ||
# to only awaken if it receives a software interrupt, | ||
# which we're going to call the SIPI (Software Intra-Processor Interrupt). | ||
# We only use these to run user-space programs, although this may | ||
# We call the SIPI by writing the software interrupt into the Core Local Interruptor (CLINT) | ||
# Which is calculated by: base_address + hart * 4 | ||
# where base address is 0x0200_0000 (MMIO CLINT base address) | ||
# We only use additional harts to run user-space programs, although this may | ||
# change. | ||
la t0, TOTAL_NUM_HARTS | ||
lb t1, 0(t0) | ||
addi t1, t1, 1 | ||
sb t1, 0(t0) | ||
|
||
li t0, 1 << 3 | ||
csrw mstatus, t0 | ||
li t1, 1 << 3 | ||
csrw mie, t1 | ||
la t2, kmain | ||
csrw mtvec, t2 | ||
# Waiting loop. An IPI will cause the other harts to | ||
# wake up and start executing. | ||
4: | ||
wfi | ||
j 4b | ||
j 4b | ||
|
||
|
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
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,43 @@ | ||
// mem.S | ||
// Importation of linker symbols | ||
|
||
.section .rodata | ||
.global HEAP_START | ||
HEAP_START: .dword _heap_start | ||
|
||
.global HEAP_SIZE | ||
HEAP_SIZE: .dword _heap_size | ||
|
||
.global TEXT_START | ||
TEXT_START: .dword _text_start | ||
|
||
.global TEXT_END | ||
TEXT_END: .dword _text_end | ||
|
||
.global DATA_START | ||
DATA_START: .dword _data_start | ||
|
||
.global DATA_END | ||
DATA_END: .dword _data_end | ||
|
||
.global RODATA_START | ||
RODATA_START: .dword _rodata_start | ||
|
||
.global RODATA_END | ||
RODATA_END: .dword _rodata_end | ||
|
||
.global BSS_START | ||
BSS_START: .dword _bss_start | ||
|
||
.global BSS_END | ||
BSS_END: .dword _bss_end | ||
|
||
.global KERNEL_STACK_START | ||
KERNEL_STACK_START: .dword _stack_start | ||
|
||
.global KERNEL_STACK_END | ||
KERNEL_STACK_END: .dword _stack_end | ||
|
||
.section .data | ||
.global KERNEL_TABLE | ||
KERNEL_TABLE: .dword 0 |
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
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,61 @@ | ||
|
||
typedef unsigned long long uint64; | ||
|
||
class UART { | ||
private: | ||
uint64 _base_addr = 0x100000000; | ||
public: | ||
UART(uint64 base_addr):_base_addr(base_addr) { | ||
this->_init(_base_addr); | ||
} | ||
private: | ||
void _init(uint64 base_addr) | ||
{ | ||
char* ptr = reinterpret_cast<char*>(base_addr); | ||
|
||
// lcr register - word size | ||
char lcr = (1<<0) | (1<<1); | ||
*(ptr + 3) = lcr; | ||
|
||
// enable fifo and enable buffer interrupt | ||
*(ptr + 2) = (1 << 0); | ||
*(ptr + 1 ) = (0 << 0); | ||
|
||
unsigned int divisor = 592; | ||
char divisor_least = divisor & 0xff; | ||
char divisor_most = divisor >> 8; | ||
|
||
*(ptr + 3) = (lcr | 1 << 7); | ||
|
||
*(ptr + 0) = divisor_least; | ||
*(ptr + 1) = divisor_most; | ||
*(ptr + 3) = lcr; | ||
} | ||
public: | ||
|
||
void write(char* str){ | ||
int i=0; | ||
while(str[i] != '\0'){ | ||
this->put(*(str+ i)); | ||
i++; | ||
} | ||
} | ||
|
||
char get() { | ||
char* ptr = reinterpret_cast<char*>(this->_base_addr); | ||
if(*(ptr+5) & 1 == 0){ | ||
return 0; | ||
}else{ | ||
return *ptr; | ||
} | ||
} | ||
|
||
void put(char character) | ||
{ | ||
char* ptr = reinterpret_cast<char*>(this->_base_addr); | ||
*ptr = character; | ||
} | ||
|
||
|
||
}; | ||
|
Binary file not shown.