commit 63904ea09f75249760b45fea6bdd349feb2fb2d3 Author: Bryan McShea Date: Tue Oct 11 17:54:20 2022 -0400 initial commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1180811 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +CC = riscv64-linux-gnu-gcc +GCC_ARGS = -static -g -nostdlib +SOURCES = $(wildcard src/*.s src/**/*.s) + +build/main: $(SOURCES) + $(CC) $(GCC_ARGS) -o build/main $(SOURCES) + +clean: + rm -r build/* diff --git a/build/main b/build/main new file mode 100755 index 0000000..82aaee1 Binary files /dev/null and b/build/main differ diff --git a/build/test.txt b/build/test.txt new file mode 100644 index 0000000..4c5e6c4 Binary files /dev/null and b/build/test.txt differ diff --git a/run b/run new file mode 100755 index 0000000..8231ec4 --- /dev/null +++ b/run @@ -0,0 +1,13 @@ +#!/bin/sh +make -s || exit +cd build + +if [ "$1" = "d" ]; then + qemu-riscv64 -g 1234 main & + riscv64-linux-gnu-gdb -q \ + -ex "target remote :1234" \ + main +else + qemu-riscv64 main +fi + diff --git a/src/lib/format.s b/src/lib/format.s new file mode 100644 index 0000000..c975b6e --- /dev/null +++ b/src/lib/format.s @@ -0,0 +1,62 @@ +.align 2 +.section .text + + + +# args: +# a0 - number +# +# returns: +# a0,a1 - hex string +.global format_hex +format_hex: + addi sp, sp, -(3*8) + sd ra, 0(sp) + sd s0, 8(sp) + sd s1, 16(sp) + + move s0, a0 + jal format_hex_lower + move s1, a0 + + srli a0, s0, 32 + jal format_hex_lower + + move a1, s1 + + ld ra, 0(sp) + ld s0, 8(sp) + ld s1, 16(sp) + addi sp, sp, +(3*8) + ret + +# args: +# a0 - number +# +# returns: +# a0 - lower hex string +.global format_hex_lower +format_hex_lower: + move t0, a0 + li t1, 0xffffffff + and t0, t0, t1 + li a0, 0 + li t1, 8*7 + li t4, 16*4 +0: + bltz t1, 0f + + andi t2, t0, 0xf + addi t2, t2, 0x30 + li t3, 0x30+9 + ble t2, t3, 1f + addi t2, t2, 0x61-0x30-10 +1: + sll t2, t2, t1 + addi t1, t1, -8 + srli t0, t0, 4 + or a0, a0, t2 + j 0b +0: + ret + diff --git a/src/lib/heap.s b/src/lib/heap.s new file mode 100644 index 0000000..8ae1e5c --- /dev/null +++ b/src/lib/heap.s @@ -0,0 +1,225 @@ +# This is a heap implemented with brk. +# It's slow / unoptimized, and only for +# learning how to set up a basic heap + +# mask and imask are used to floor & ceil +# to get correct bounds +.equ align_imask, 0b111 +.equ align_mask, ~align_imask + +.equ used_mask, 0b001 +.equ size_mask, align_mask + +# block node + +.equ bsize, 0 +.equ fb_next, 8 # free only +# free also contains its address at the end + +# sizes of metadata + +.equ sizeof_fb, (8*3 + align_imask) & align_mask +.equ sizeof_ub, (8*1 + align_imask) & align_mask + +.equ PAGE_SIZE, 4096 + + + +.align 2 +.section .rodata + +.word 0f - heap_oom +heap_oom: + .string "Heap ran out of memory!\n" +0: + +.section .data + +.align 4 +.equ heap_start, 0 +.equ heap_first_free, 8 # matches fb_next +.equ heap_end, 16 +.global heap_info # for testing only +heap_info: + .dword __global_pointer$ + .dword 0 + .dword 0 + + + +.align 2 +.section .text + +.global heap_init +heap_init: + addi sp, sp, -8 + sd ra, 0(sp) + + # get heap info (t0) + + la t0, heap_info + + # set heap start (t1) + + ld t1, heap_start(t0) + addi t1, t1, align_imask + andi t1, t1, align_mask + sd t1, heap_start(t0) + + # set heap end (a0) + # also calculate heap size (t2) + + li a0, 0 + jal brk + andi a0, a0, align_mask + sub t2, a0, t1 # size = end - start (t2) + li t3, sizeof_fb + bgeu t2, t3, 0f # check if enough mem to start + + move a1, a0 + add a0, t1, t3 + jal brk_or_panic # if not, get more + sub t2, a0, t1 # recalc size (t2) +0: + sd a0, heap_end(t0) + + # create initial free block + + ori t2, t2, 0x1 # add prev used + sd t2, bsize(t1) # store size + sd t0, fb_next(t1) # store next + sd t1, -8(a0) # store addr at end + + sd t1, heap_first_free(t0) + + ld ra, 0(sp) + addi sp, sp, +8 + ret + +# args: +# a0 - size +# +# returns: +# a0 - address +.global heap_alloc +heap_alloc: + addi sp, sp, -8 + sd ra, 0(sp) + + # align size properly (t0) + + move t0, a0 + addi t0, t0, sizeof_ub + addi t0, t0, align_imask + andi t0, t0, align_mask + + # get a free block that will fit (t1) + # and its free space + + la t3, heap_info + ld t4, heap_first_free(t3) + ld a1, heap_end(t3) + + move t6, t3 # prev block (t6) + + bne t4, t3, 0f # if no free blocks + move t4, a1 # pretend end is start + j 3f +0: + + move t1, t4 # current block (t1) + +0: + ld t2, bsize(t1) # size of current block (t2) + andi t2, t2, size_mask + bgeu t2, t0, 0f # is it big enough + ld t5, fb_next(t1) # if not, get the next + beq t5, t3, 1f + move t6, t1 + move t1, t5 + j 0b +1: # if no blocks are big enough + add t5, t1, t2 # get end of last free block + beq t5, a1, 2f # if no free block at end of heap: + move t6, t1 +3: + move t1, a1 # immitate new free block at end +2: + add a0, t1, t0 # get needed heap end (a0) + jal brk_or_panic # set heap end (a0) + sd a0, heap_end(t3) # update end in info + sub t2, a0, t1 # new free space (t2) + andi t5, t2, 1 # prev used bit + sd t5, bsize(t1) # update size + sd t3, fb_next(t1) # update next (for case 3) + +0: + + # deal with extra free space + + sub t5, t2, t0 # unneeded free space (t5) + li t4, sizeof_fb + bltu t5, t4, 0f # check if enough for a free block + + add t3, t1, t0 # if so, get addr (t3) + sd t3, fb_next(t6) # set prev block next to new + add t6, t3, t5 # store addr at end + sd t3, -8(t6) + ori t6, t5, 1 # store size with prev in use + sd t6, bsize(t3) + ld t6, fb_next(t1) # copy next + sd t6, fb_next(t3) + j 1f +0: + move t0, t2 # if no space, fill in with used + ld t4, fb_next(t1) + sd t4, fb_next(t6) # set prev next to cur next + ld t4, heap_end(t3) + add t3, t1, t0 + beq t3, t4, 1f # if this is not at the end + ld t4, bsize(t3) # set next's prev used to 1 + ori t4, t4, 1 + sd t4, bsize(t3) +1: + + # create used block + + add t2, t0, t1 # end of block + ori t0, t0, 1 # prev used bit + sd t0, bsize(t1) # store size + sd zero, fb_next(t1) # remove free block stuff + sd zero, -8(t2) + + move a0, t1 + addi a0, a0, sizeof_ub + + ld ra, 0(sp) + addi sp, sp, +8 + ret + +# args: +# a0 - address +.global heap_free +heap_free: + ret + +# args: +# a0 - min address needed +# a1 - old address +# +# returns: +# a0 - new address, aligned +brk_or_panic: + addi sp, sp, -8 + sd ra, 0(sp) + + jal brk + andi a0, a0, align_mask + bgtu a0, a1, 0f # make sure brk worked + la a0, heap_oom # if not, panic + lw a1, -4(a0) + j panic +0: + ld ra, 0(sp) + addi sp, sp, +8 + ret diff --git a/src/lib/print.s b/src/lib/print.s new file mode 100644 index 0000000..888c158 --- /dev/null +++ b/src/lib/print.s @@ -0,0 +1,95 @@ +.section .rodata + +newline: + .half '\n' +space: + .half ' ' + + + +.align 2 +.section .text + +# only uses a regs for convenience +# +# args: +# a0 - string +# a1 - length +.global print +print: + addi sp, sp, -8 + sd ra, (sp) + + move a2, a1 + move a1, a0 + li a0, 1 # stdout + jal write + + ld ra, (sp) + addi sp, sp, +8 + ret + +# only uses a regs for convenience +.global printnl +printnl: + addi sp, sp, -8 + sd ra, (sp) + + la a0, newline + li a1, 1 + jal print + + ld ra, (sp) + addi sp, sp, +8 + ret + +# only uses a regs for convenience +# +# args: +# a0 - string +# a1 - length +.global println +println: + addi sp, sp, -8 + sd ra, (sp) + + jal print + jal printnl + + ld ra, (sp) + addi sp, sp, +8 + ret + +.global print_space +print_space: + addi sp, sp, -8 + sd ra, (sp) + + la a0, space + li a1, 1 + jal print + + ld ra, (sp) + addi sp, sp, +8 + ret + +# args: +# a0 - the hex value to print +.global print_hex +print_hex: + addi sp, sp, -(8+16) + sd ra, (sp) + + jal format_hex + addi t0, sp, 8 + sd a0, 0(t0) + sd a1, 8(t0) + + move a0, t0 + li a1, 16 + jal print + + ld ra, (sp) + addi sp, sp, +(8+16) + ret + diff --git a/src/lib/start.s b/src/lib/start.s new file mode 100644 index 0000000..11e61b1 --- /dev/null +++ b/src/lib/start.s @@ -0,0 +1,9 @@ +.align 2 +.section .text + +.global _start +_start: + jal heap_init + jal main + j exit + diff --git a/src/lib/str.s b/src/lib/str.s new file mode 100644 index 0000000..b412e10 --- /dev/null +++ b/src/lib/str.s @@ -0,0 +1,37 @@ +.align 2 +.section .text + +# args: +# a0 - string +# +# returns: +# a0 - length +.global strlen +strlen: + li t0, 0 +0: + beq t0, a1, 0f + lb t1, (a0) + beqz t1, 0f + addi a0, a0, 1 + addi t0, t0, 1 + j 0b +0: + move a0, t0 + ret + +# args: +# a0 - dest +# a1 - src +.global strcpy +strcpy: +0: + lb t0, (a1) + beqz t0, 0f + sb t0, (a0) + addi a0, a0, 1 + addi a1, a1, 1 + j 0b +0: + sb t0, (a0) + ret diff --git a/src/lib/sys.s b/src/lib/sys.s new file mode 100644 index 0000000..b8b5bd5 --- /dev/null +++ b/src/lib/sys.s @@ -0,0 +1,50 @@ +# This contains all syscalls used, +# as functions for convenience. +# These are guaranteed to not modify +# any registers other than the +# arguments needed for the syscalls + +.align 2 +.section .text + +# args: +# a0 - code +.global exit +exit: + li a7, 93 + ecall +0: j 0b # loop if failed for safety + +# args: +# a0 - relative dir fd; +# 0 for none, -100 for cwd +# a1 - path / name +# a2 - flags +# a3 - mode +# +# returns: +# a0 - fd +.global openat +openat: + li a7, 56 + ecall + ret + +# args: +# a0 - fd +# a1 - content buf +# a2 - size +.global write +write: + li a7, 64 + ecall + ret + +# args: +# a0 - address to end at +# returns current addr if 0 +.global brk +brk: + li a7, 214 + ecall + ret diff --git a/src/lib/util.s b/src/lib/util.s new file mode 100644 index 0000000..f111e7a --- /dev/null +++ b/src/lib/util.s @@ -0,0 +1,11 @@ +.align 2 +.section .text + +# args: +# a0 - message +# a1 - length +.global panic +panic: + jal print + li a0, 1 + j exit diff --git a/src/main.s b/src/main.s new file mode 100644 index 0000000..5680c92 --- /dev/null +++ b/src/main.s @@ -0,0 +1,20 @@ +.align 2 +.section .text + +.global main +main: + addi sp, sp, -8 + sd ra, 0(sp) + + # do stuff + + #jal write_test + jal heap_test + + # exit with code 0 + + ld ra, 0(sp) + addi sp, sp, +8 + + li a0, 0 + ret diff --git a/src/test/heap.s b/src/test/heap.s new file mode 100644 index 0000000..3b4ccc8 --- /dev/null +++ b/src/test/heap.s @@ -0,0 +1,125 @@ +.section .rodata + +.word 0f - print_msg +print_msg: + .string "Current heap:" +0: + +.word 0f - dots +dots: + .string "................" +0: + +.word 0f - hexstr +hexstr: + .string "0x" +0: + + + +.align 2 +.section .text + +.global heap_test +heap_test: + addi sp, sp, -(3*8) + sd ra, 0(sp) + sd s0, 8(sp) + sd s1, 16(sp) + + # empty heap + + jal print_heap + jal printnl + + # put stuff on heap + + li a0, 8*4 + jal heap_alloc + li t0, 0x1111111111111111 + sd t0, (a0) + sd t0, 8(a0) + sd t0, 24(a0) + + li s0, 0x0f +0: + bltz s0, 0f + + li a0, 8*3 + jal heap_alloc + sd s0, (a0) + li t0, 0xf000000000000000 + add t0, s0, t0 + sd t0, 16(a0) + + addi s0, s0, -1 + j 0b +0: + + li a0, 8*7 + jal heap_alloc + li t0, 0xffff + sd t0, 6*8(a0) + + li a0, 8*3 + jal heap_alloc + + jal print_heap + + ld ra, 0(sp) + ld s0, 8(sp) + ld s1, 16(sp) + addi sp, sp, +(3*8) + ret + +print_heap: + addi sp, sp, -(3*8) + sd ra, 0(sp) + sd s0, 8(sp) + sd s1, 16(sp) + + la a0, print_msg + lw a1, -4(a0) + jal println + + la t0, heap_info + ld s0, 0(t0) + ld s1, 16(t0) +0: + la a0, hexstr + lw a1, -4(a0) + jal print + move a0, s0 + jal print_hex + jal print_space + + ld a0, 0(s0) + jal print_hex + jal print_space + + ld a0, 8(s0) + jal print_hex + jal print_space + + la a0, dots + lw a1, -4(a0) + jal print + jal print_space + + ld t0, 0(s0) + andi t0, t0, ~0b11 + add t0, s0, t0 + ld a0, -8(t0) + move s0, t0 + jal print_hex + jal printnl + + beq s0, s1, 0f + j 0b +0: + + ld ra, 0(sp) + ld s0, 8(sp) + ld s1, 16(sp) + addi sp, sp, +(3*8) + ret diff --git a/src/test/write.s b/src/test/write.s new file mode 100644 index 0000000..5a13b07 --- /dev/null +++ b/src/test/write.s @@ -0,0 +1,55 @@ +.equ PATH_MAX, 255 + +.section .rodata + + .word 0f - start_msg +start_msg: + .string "Writing file..." +0: + + .word 0f - file_name +file_name: + .string "test.txt" +0: + + .word 0f - content +content: + .string "Hello world!\n" +0: + + + +.align 2 +.section .text + +.global write_test +write_test: + addi sp, sp, -8-PATH_MAX + sd ra, 0(sp) + + # print msg + + la a0, start_msg + lw a1, -4(a0) + jal println + + # open file + + li a0, -100 + la a1, file_name + li a2, 01102 # TRUNC | CREAT | RDWR + li a3, 0b110100100 # -rw-r--r-- + jal openat + + # write to file + + la a1, content + lw a2, -4(a1) + jal write + + # return + + ld ra, 0(sp) + addi sp, sp, +8+PATH_MAX + + ret