Skip to content

Commit

Permalink
uart from scratch? ok, shit gonna get serious
Browse files Browse the repository at this point in the history
  • Loading branch information
lrdass committed Oct 17, 2020
1 parent acc185d commit b99e0a5
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 57 deletions.
10 changes: 5 additions & 5 deletions Makefile
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
Binary file modified a.out
Binary file not shown.
145 changes: 100 additions & 45 deletions boot.S
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


41 changes: 36 additions & 5 deletions main.cc
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
typedef unsigned long long uint64;
typedef char uint8;

#include "uart.h"


struct trap_frame{
uint64 regs[32]; // 0 - 255 bytes
uint64 fregs[32]; // 256 - 511 bytes
uint64 satp; // 512 - 519 bytes
uint64* trap_stack; // 520 byte
uint64 fregs[32]; // 256 - 511 bytes
uint64 satp; // 512 - 519 bytes
uint64* trap_stack; // 520 byte
uint64 hartid; // 528 byte
};

Expand All @@ -29,12 +33,39 @@ void add_timer(int seconds) {
*mtimecmp = *mtime + (seconds * 10000000);
}

void mmio_write(unsigned long address, int offset, char value)
{
volatile char* reg = (char*) address;
*(reg+offset) = value;
}

char mmio_read(unsigned long address, int offset)
{
volatile char* reg = (char*) address;
return *(reg+offset);
}
extern "C" {
static unsigned int TEXT_START;
static unsigned int TEXT_END;
static unsigned int DATA_START;
static unsigned int DATA_END;
static unsigned int RODATA_START;
static unsigned int RODATA_END;
static unsigned int BSS_START;
static unsigned int BSS_END;
static unsigned int KERNEL_STACK_START;
static unsigned int KERNEL_STACK_END;
static unsigned int HEAP_START;
static unsigned int HEAP_SIZE;
static unsigned int KERNEL_TABLE;
}

extern "C" int kmain(){
UART uart(0x10000000);
uart.write("fasdf ad f");
// disparar interrupcao de timer
add_timer(1);

return 0;

}

extern "C" void m_trap(uint64 epc, uint64 tval,uint64 cause,uint64 hart, uint64 status, trap_frame* trap_frame)
Expand Down
43 changes: 43 additions & 0 deletions mem.S
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
4 changes: 2 additions & 2 deletions trap.S
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

.section .text
.global m_trap_vector
.global asm_trap_vector
.align 4
m_trap_vector:
asm_trap_vector:
# Save registers
addi sp, sp, -128 # Make some space in the stack
sd ra, 0(sp) # Return address
Expand Down
61 changes: 61 additions & 0 deletions uart.h
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 added uart.h.gch
Binary file not shown.

0 comments on commit b99e0a5

Please sign in to comment.