From f29d14a877d4873c12fa80c9df5b265474a85b05 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Sat, 4 Jun 2016 13:19:45 -0700 Subject: WIP on debug testing. ./gdbserver.py --m2gl_m2s --openocd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl" -- RegsTest.test_write_gprs doesn't fail in a completely crazy way. --- debug/programs/checksum.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ debug/programs/debug.c | 27 +++++++++++++++++++++++++++ debug/programs/init.c | 14 ++++++++++++++ debug/programs/mprv.S | 38 ++++++++++++++++++++++++++++++++++++++ debug/programs/regs.S | 43 +++++++++++++++++++++++++++++++++++++++++++ debug/programs/start.S | 12 ++++++++++++ 6 files changed, 181 insertions(+) create mode 100644 debug/programs/checksum.c create mode 100644 debug/programs/debug.c create mode 100644 debug/programs/init.c create mode 100644 debug/programs/mprv.S create mode 100644 debug/programs/regs.S create mode 100644 debug/programs/start.S (limited to 'debug/programs') diff --git a/debug/programs/checksum.c b/debug/programs/checksum.c new file mode 100644 index 0000000..36152fc --- /dev/null +++ b/debug/programs/checksum.c @@ -0,0 +1,47 @@ +#include + +// CRC code from http://www.hackersdelight.org/hdcodetxt/crc.c.txt + +// Reverses (reflects) bits in a 32-bit word. +unsigned reverse(unsigned x) { + x = ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555); + x = ((x & 0x33333333) << 2) | ((x >> 2) & 0x33333333); + x = ((x & 0x0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F); + x = (x << 24) | ((x & 0xFF00) << 8) | + ((x >> 8) & 0xFF00) | (x >> 24); + return x; +} + +// ----------------------------- crc32a -------------------------------- + +/* This is the basic CRC algorithm with no optimizations. It follows the +logic circuit as closely as possible. */ + +unsigned int crc32a(uint8_t *message, unsigned int size) { + int i, j; + unsigned int byte, crc; + + i = 0; + crc = 0xFFFFFFFF; + while (i < size) { + byte = message[i]; // Get next byte. + byte = reverse(byte); // 32-bit reversal. + for (j = 0; j <= 7; j++) { // Do eight times. + if ((int)(crc ^ byte) < 0) + crc = (crc << 1) ^ 0x04C11DB7; + else crc = crc << 1; + byte = byte << 1; // Ready next msg bit. + } + i = i + 1; + } + return reverse(~crc); +} + +extern uint8_t *data; +extern uint32_t length; + +uint32_t main() +{ + /* Compute a simple checksum. */ + return crc32a(data, length); +} diff --git a/debug/programs/debug.c b/debug/programs/debug.c new file mode 100644 index 0000000..2cad88f --- /dev/null +++ b/debug/programs/debug.c @@ -0,0 +1,27 @@ +#include + +char c = 'x'; + +void print_row(int length) +{ + for (int x=0; x> 2) | PTE_V | PTE_TYPE_URWX_SRWX) + .word 0 diff --git a/debug/programs/regs.S b/debug/programs/regs.S new file mode 100644 index 0000000..e6456e1 --- /dev/null +++ b/debug/programs/regs.S @@ -0,0 +1,43 @@ + .global main +main: + j main + +write_regs: + sd x1, 0(a0) + sd x2, 8(a0) + sd x3, 16(a0) + sd x4, 24(a0) + sd x5, 32(a0) + sd x6, 40(a0) + sd x7, 48(a0) + sd x8, 56(a0) + sd x9, 64(a0) + sd x11, 72(a0) + sd x12, 80(a0) + sd x13, 88(a0) + sd x14, 96(a0) + sd x15, 104(a0) + sd x16, 112(a0) + sd x17, 120(a0) + sd x18, 128(a0) + sd x19, 136(a0) + sd x20, 144(a0) + sd x21, 152(a0) + sd x22, 160(a0) + sd x23, 168(a0) + sd x24, 176(a0) + sd x25, 184(a0) + sd x26, 192(a0) + sd x27, 200(a0) + sd x28, 208(a0) + sd x29, 216(a0) + sd x30, 224(a0) + sd x31, 232(a0) + + csrr x1, 1 # fflags + +all_done: + j all_done + +data: + .fill 64, 8, 0 diff --git a/debug/programs/start.S b/debug/programs/start.S new file mode 100644 index 0000000..76c37bb --- /dev/null +++ b/debug/programs/start.S @@ -0,0 +1,12 @@ + .global _start + +_start: + la sp, stack_end + jal main +done: + j done + + .data +stack: + .fill 4096, 1, 0 +stack_end: -- cgit v1.1 From 6990284b8eab8d4e4f57f82ac8918913c5c63e97 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 7 Jun 2016 16:59:26 -0700 Subject: Made some progress towards working with spike. I'm writing all the tests so they should just work on real hardware, too. --- debug/programs/checksum.c | 9 ------ debug/programs/debug.c | 47 +++++++++++++++++++++---------- debug/programs/init.c | 14 ++++++++-- debug/programs/regs.S | 70 +++++++++++++++++++++++++++-------------------- 4 files changed, 85 insertions(+), 55 deletions(-) (limited to 'debug/programs') diff --git a/debug/programs/checksum.c b/debug/programs/checksum.c index 36152fc..e076f8a 100644 --- a/debug/programs/checksum.c +++ b/debug/programs/checksum.c @@ -36,12 +36,3 @@ unsigned int crc32a(uint8_t *message, unsigned int size) { } return reverse(~crc); } - -extern uint8_t *data; -extern uint32_t length; - -uint32_t main() -{ - /* Compute a simple checksum. */ - return crc32a(data, length); -} diff --git a/debug/programs/debug.c b/debug/programs/debug.c index 2cad88f..afca484 100644 --- a/debug/programs/debug.c +++ b/debug/programs/debug.c @@ -1,27 +1,46 @@ #include +#include +#include -char c = 'x'; +unsigned int crc32a(uint8_t *message, unsigned int size); -void print_row(int length) +void rot13(char *buf) { - for (int x=0; x= 'a' && *buf <= 'm') || + (*buf >= 'A' && *buf <= 'M')) { + *buf += 13; + } else if ((*buf >= 'n' && *buf <= 'z') || + (*buf >= 'N' && *buf <= 'Z')) { + *buf -= 13; + } + buf++; } - printf("\n"); +} + +size_t strlen(const char *buf) +{ + int len = 0; + while (buf[len]) + len++; + return len; } int main() { - volatile int i = 42; - const char *text = "constant\n"; - int threshold = 7; + volatile int i = 0; + int j = 0; + char *fox = "The quick brown fox jumps of the lazy dog."; + unsigned int checksum = 0; - // Wait for the debugger to get us out of this loop. +start: while (i) - ; + j++; - printf("%s", text); - for (int y=0; y < 10; y++) { - print_row(y); - } + rot13(fox); + checksum ^= crc32a(fox, strlen(fox)); + rot13(fox); + checksum ^= crc32a(fox, strlen(fox)); + + return checksum; } diff --git a/debug/programs/init.c b/debug/programs/init.c index 074bc21..a2b41b0 100644 --- a/debug/programs/init.c +++ b/debug/programs/init.c @@ -6,9 +6,19 @@ void handle_trap(unsigned int mcause, unsigned int mepc, unsigned int sp) ; } -void _init() +void _exit(int status) { - main(); + // Make sure gcc doesn't inline _exit, so we can actually set a breakpoint + // on it. + volatile int i = 42; + while (i) + ; + // _exit isn't supposed to return. while (1) ; } + +void _init() +{ + _exit(main()); +} diff --git a/debug/programs/regs.S b/debug/programs/regs.S index e6456e1..54b3961 100644 --- a/debug/programs/regs.S +++ b/debug/programs/regs.S @@ -1,38 +1,48 @@ +#ifdef __riscv64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + .global main main: j main write_regs: - sd x1, 0(a0) - sd x2, 8(a0) - sd x3, 16(a0) - sd x4, 24(a0) - sd x5, 32(a0) - sd x6, 40(a0) - sd x7, 48(a0) - sd x8, 56(a0) - sd x9, 64(a0) - sd x11, 72(a0) - sd x12, 80(a0) - sd x13, 88(a0) - sd x14, 96(a0) - sd x15, 104(a0) - sd x16, 112(a0) - sd x17, 120(a0) - sd x18, 128(a0) - sd x19, 136(a0) - sd x20, 144(a0) - sd x21, 152(a0) - sd x22, 160(a0) - sd x23, 168(a0) - sd x24, 176(a0) - sd x25, 184(a0) - sd x26, 192(a0) - sd x27, 200(a0) - sd x28, 208(a0) - sd x29, 216(a0) - sd x30, 224(a0) - sd x31, 232(a0) + SREG x1, 0(a0) + SREG x2, 8(a0) + SREG x3, 16(a0) + SREG x4, 24(a0) + SREG x5, 32(a0) + SREG x6, 40(a0) + SREG x7, 48(a0) + SREG x8, 56(a0) + SREG x9, 64(a0) + SREG x11, 72(a0) + SREG x12, 80(a0) + SREG x13, 88(a0) + SREG x14, 96(a0) + SREG x15, 104(a0) + SREG x16, 112(a0) + SREG x17, 120(a0) + SREG x18, 128(a0) + SREG x19, 136(a0) + SREG x20, 144(a0) + SREG x21, 152(a0) + SREG x22, 160(a0) + SREG x23, 168(a0) + SREG x24, 176(a0) + SREG x25, 184(a0) + SREG x26, 192(a0) + SREG x27, 200(a0) + SREG x28, 208(a0) + SREG x29, 216(a0) + SREG x30, 224(a0) + SREG x31, 232(a0) csrr x1, 1 # fflags -- cgit v1.1 From e291177a1cbeb6cef46aa5f8f019346c3202c3ef Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 8 Jun 2016 19:53:57 -0700 Subject: All tests pass with spike now. I did comment out a couple. --- debug/programs/entry.S | 132 +++++++++++++++++++++++++++++++++++++++++++++++++ debug/programs/mprv.S | 6 +-- debug/programs/regs.S | 5 +- 3 files changed, 139 insertions(+), 4 deletions(-) create mode 100755 debug/programs/entry.S (limited to 'debug/programs') diff --git a/debug/programs/entry.S b/debug/programs/entry.S new file mode 100755 index 0000000..e17b236 --- /dev/null +++ b/debug/programs/entry.S @@ -0,0 +1,132 @@ +#ifndef ENTRY_S +#define ENTRY_S + +#include "encoding.h" + +#define STACK_SIZE ((1 << 12) - 128) + +#ifdef __riscv64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + + .section .text.entry + .globl _start +_start: + j handle_reset + +nmi_vector: + j nmi_vector + +trap_vector: + j trap_entry + +handle_reset: + la t0, trap_entry + csrw mtvec, t0 + csrwi mstatus, 0 + csrwi mideleg, 0 + csrwi medeleg, 0 + csrwi mie, 0 + + # initialize global pointer + la gp, _gp + + # initialize stack pointer + la sp, stack_top + + # perform the rest of initialization in C + j _init + + +trap_entry: + addi sp, sp, -32*REGBYTES + + SREG x1, 1*REGBYTES(sp) + SREG x2, 2*REGBYTES(sp) + SREG x3, 3*REGBYTES(sp) + SREG x4, 4*REGBYTES(sp) + SREG x5, 5*REGBYTES(sp) + SREG x6, 6*REGBYTES(sp) + SREG x7, 7*REGBYTES(sp) + SREG x8, 8*REGBYTES(sp) + SREG x9, 9*REGBYTES(sp) + SREG x10, 10*REGBYTES(sp) + SREG x11, 11*REGBYTES(sp) + SREG x12, 12*REGBYTES(sp) + SREG x13, 13*REGBYTES(sp) + SREG x14, 14*REGBYTES(sp) + SREG x15, 15*REGBYTES(sp) + SREG x16, 16*REGBYTES(sp) + SREG x17, 17*REGBYTES(sp) + SREG x18, 18*REGBYTES(sp) + SREG x19, 19*REGBYTES(sp) + SREG x20, 20*REGBYTES(sp) + SREG x21, 21*REGBYTES(sp) + SREG x22, 22*REGBYTES(sp) + SREG x23, 23*REGBYTES(sp) + SREG x24, 24*REGBYTES(sp) + SREG x25, 25*REGBYTES(sp) + SREG x26, 26*REGBYTES(sp) + SREG x27, 27*REGBYTES(sp) + SREG x28, 28*REGBYTES(sp) + SREG x29, 29*REGBYTES(sp) + SREG x30, 30*REGBYTES(sp) + SREG x31, 31*REGBYTES(sp) + + csrr a0, mcause + csrr a1, mepc + mv a2, sp + jal handle_trap + csrw mepc, a0 + + # Remain in M-mode after mret + li t0, MSTATUS_MPP + csrs mstatus, t0 + + LREG x1, 1*REGBYTES(sp) + LREG x2, 2*REGBYTES(sp) + LREG x3, 3*REGBYTES(sp) + LREG x4, 4*REGBYTES(sp) + LREG x5, 5*REGBYTES(sp) + LREG x6, 6*REGBYTES(sp) + LREG x7, 7*REGBYTES(sp) + LREG x8, 8*REGBYTES(sp) + LREG x9, 9*REGBYTES(sp) + LREG x10, 10*REGBYTES(sp) + LREG x11, 11*REGBYTES(sp) + LREG x12, 12*REGBYTES(sp) + LREG x13, 13*REGBYTES(sp) + LREG x14, 14*REGBYTES(sp) + LREG x15, 15*REGBYTES(sp) + LREG x16, 16*REGBYTES(sp) + LREG x17, 17*REGBYTES(sp) + LREG x18, 18*REGBYTES(sp) + LREG x19, 19*REGBYTES(sp) + LREG x20, 20*REGBYTES(sp) + LREG x21, 21*REGBYTES(sp) + LREG x22, 22*REGBYTES(sp) + LREG x23, 23*REGBYTES(sp) + LREG x24, 24*REGBYTES(sp) + LREG x25, 25*REGBYTES(sp) + LREG x26, 26*REGBYTES(sp) + LREG x27, 27*REGBYTES(sp) + LREG x28, 28*REGBYTES(sp) + LREG x29, 29*REGBYTES(sp) + LREG x30, 30*REGBYTES(sp) + LREG x31, 31*REGBYTES(sp) + + addi sp, sp, 32*REGBYTES + mret + + .bss + .align 4 +stack_bottom: + .skip STACK_SIZE +stack_top: +#endif diff --git a/debug/programs/mprv.S b/debug/programs/mprv.S index df346b3..2725b67 100644 --- a/debug/programs/mprv.S +++ b/debug/programs/mprv.S @@ -1,10 +1,10 @@ -#include "../riscv/encoding.h" +#include "../../env/encoding.h" #define PGSHIFT 12 - .global _start + .global main .section .text -_start: +main: # Set up a page table entry that maps 0x0... to 0x8... la t0, page_table srli t0, t0, PGSHIFT diff --git a/debug/programs/regs.S b/debug/programs/regs.S index 54b3961..65b62ec 100644 --- a/debug/programs/regs.S +++ b/debug/programs/regs.S @@ -8,6 +8,8 @@ # define REGBYTES 4 #endif +#include "../../env/encoding.h" + .global main main: j main @@ -44,10 +46,11 @@ write_regs: SREG x30, 224(a0) SREG x31, 232(a0) - csrr x1, 1 # fflags + csrr x1, CSR_MSCRATCH all_done: j all_done + .align 16 data: .fill 64, 8, 0 -- cgit v1.1 From 2088d1bce6558a101c42861dc578f4c7d7f4f6b4 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 9 Jun 2016 14:39:30 -0700 Subject: Add block test. --- debug/programs/entry.S | 2 +- debug/programs/regs.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'debug/programs') diff --git a/debug/programs/entry.S b/debug/programs/entry.S index e17b236..480b404 100755 --- a/debug/programs/entry.S +++ b/debug/programs/entry.S @@ -3,7 +3,7 @@ #include "encoding.h" -#define STACK_SIZE ((1 << 12) - 128) +#define STACK_SIZE 128 #ifdef __riscv64 # define LREG ld diff --git a/debug/programs/regs.S b/debug/programs/regs.S index 65b62ec..989d037 100644 --- a/debug/programs/regs.S +++ b/debug/programs/regs.S @@ -51,6 +51,6 @@ write_regs: all_done: j all_done - .align 16 + .balign 16 data: .fill 64, 8, 0 -- cgit v1.1 From 6ccc0bdde5eea898e88961f49e755bd2b4577792 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 10 Jun 2016 10:45:27 -0700 Subject: Add simple register tests. Make the RegsTest case a bit more comprehensible. --- debug/programs/regs.S | 61 ++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 30 deletions(-) (limited to 'debug/programs') diff --git a/debug/programs/regs.S b/debug/programs/regs.S index 989d037..2cacd4f 100644 --- a/debug/programs/regs.S +++ b/debug/programs/regs.S @@ -12,39 +12,40 @@ .global main main: + nop j main write_regs: - SREG x1, 0(a0) - SREG x2, 8(a0) - SREG x3, 16(a0) - SREG x4, 24(a0) - SREG x5, 32(a0) - SREG x6, 40(a0) - SREG x7, 48(a0) - SREG x8, 56(a0) - SREG x9, 64(a0) - SREG x11, 72(a0) - SREG x12, 80(a0) - SREG x13, 88(a0) - SREG x14, 96(a0) - SREG x15, 104(a0) - SREG x16, 112(a0) - SREG x17, 120(a0) - SREG x18, 128(a0) - SREG x19, 136(a0) - SREG x20, 144(a0) - SREG x21, 152(a0) - SREG x22, 160(a0) - SREG x23, 168(a0) - SREG x24, 176(a0) - SREG x25, 184(a0) - SREG x26, 192(a0) - SREG x27, 200(a0) - SREG x28, 208(a0) - SREG x29, 216(a0) - SREG x30, 224(a0) - SREG x31, 232(a0) + SREG x2, 0(x1) + SREG x3, 8(x1) + SREG x4, 16(x1) + SREG x5, 24(x1) + SREG x6, 32(x1) + SREG x7, 40(x1) + SREG x8, 48(x1) + SREG x9, 56(x1) + SREG x10, 64(x1) + SREG x11, 72(x1) + SREG x12, 80(x1) + SREG x13, 88(x1) + SREG x14, 96(x1) + SREG x15, 104(x1) + SREG x16, 112(x1) + SREG x17, 120(x1) + SREG x18, 128(x1) + SREG x19, 136(x1) + SREG x20, 144(x1) + SREG x21, 152(x1) + SREG x22, 160(x1) + SREG x23, 168(x1) + SREG x24, 176(x1) + SREG x25, 184(x1) + SREG x26, 192(x1) + SREG x27, 200(x1) + SREG x28, 208(x1) + SREG x29, 216(x1) + SREG x30, 224(x1) + SREG x31, 232(x1) csrr x1, CSR_MSCRATCH -- cgit v1.1 From c11808e013c7c34161d9f343cd97d5f2440c4c2e Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 10 Jun 2016 14:06:13 -0700 Subject: Make tests work with broken 32-bit compiler. Apparently the 32-bit compiler doesn't generate good enough debug info for gdb to know what function we're in, which also means it doesn't know where the local variables in those functions are stored. --- debug/programs/debug.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'debug/programs') diff --git a/debug/programs/debug.c b/debug/programs/debug.c index afca484..c7c23a6 100644 --- a/debug/programs/debug.c +++ b/debug/programs/debug.c @@ -26,10 +26,14 @@ size_t strlen(const char *buf) return len; } +// TODO: These should be local to main, but if I make them global then gdb can +// find them. +static volatile int i; +static int j; int main() { - volatile int i = 0; - int j = 0; + i = 0; + j = 0; char *fox = "The quick brown fox jumps of the lazy dog."; unsigned int checksum = 0; -- cgit v1.1 From 34341c9500c0a0a2520826b6eaf0095c3f9ce9fc Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 16 Jun 2016 13:03:19 -0700 Subject: Add explicit test for stepping over branches/jumps. --- debug/programs/step.S | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 debug/programs/step.S (limited to 'debug/programs') diff --git a/debug/programs/step.S b/debug/programs/step.S new file mode 100644 index 0000000..49f82d6 --- /dev/null +++ b/debug/programs/step.S @@ -0,0 +1,17 @@ +// Test stepping over a variety of instructions. + + .global main + +main: + li t0, 5 // 0 + beq zero, zero, one // 0x4 + nop // 0x8 +one: + beq zero, t0, one // 0xc + jal two // 0x10 + +three: + j three // 0x14 + +two: + ret // 0x18 -- cgit v1.1 From 7c9510e7a7e224ee3d51ebe736a58f81017a71a0 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 21 Jun 2016 19:20:27 -0700 Subject: Test step over invalid instruction. --- debug/programs/step.S | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'debug/programs') diff --git a/debug/programs/step.S b/debug/programs/step.S index 49f82d6..6601548 100644 --- a/debug/programs/step.S +++ b/debug/programs/step.S @@ -3,15 +3,22 @@ .global main main: - li t0, 5 // 0 - beq zero, zero, one // 0x4 - nop // 0x8 + la t0, trap_entry // 0, 4 + csrw mtvec, t0 // 0x8 + + li t0, 5 // 0xc + beq zero, zero, one // 0x10 + nop // 0x14 one: - beq zero, t0, one // 0xc - jal two // 0x10 + beq zero, t0, one // 0x18 + jal two // 0x1c three: - j three // 0x14 + .word 0 // 0x20 + nop // 0x24 two: - ret // 0x18 + ret // 0x28 + +trap_entry: + j trap_entry // 0x2c -- cgit v1.1 From bc2dac07529b05e438ab93d8fcbc495741675d32 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 27 Jun 2016 17:10:09 -0700 Subject: Add test for gdb function calls. --- debug/programs/debug.c | 2 + debug/programs/tiny-malloc.c | 600 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 602 insertions(+) create mode 100644 debug/programs/tiny-malloc.c (limited to 'debug/programs') diff --git a/debug/programs/debug.c b/debug/programs/debug.c index c7c23a6..7d0b876 100644 --- a/debug/programs/debug.c +++ b/debug/programs/debug.c @@ -4,6 +4,8 @@ unsigned int crc32a(uint8_t *message, unsigned int size); +char __malloc_start[512]; + void rot13(char *buf) { while (*buf) { diff --git a/debug/programs/tiny-malloc.c b/debug/programs/tiny-malloc.c new file mode 100644 index 0000000..699660c --- /dev/null +++ b/debug/programs/tiny-malloc.c @@ -0,0 +1,600 @@ +// https://github.com/32bitmicro/newlib-nano-1.0/blob/master/newlib/libc/machine/xstormy16/tiny-malloc.c + +/* A replacement malloc with: + - Much reduced code size; + - Smaller RAM footprint; + - The ability to handle downward-growing heaps; + but + - Slower; + - Probably higher memory fragmentation; + - Doesn't support threads (but, if it did support threads, + it wouldn't need a global lock, only a compare-and-swap instruction); + - Assumes the maximum alignment required is the alignment of a pointer; + - Assumes that memory is already there and doesn't need to be allocated. + +* Synopsis of public routines + + malloc(size_t n); + Return a pointer to a newly allocated chunk of at least n bytes, or null + if no space is available. + free(void* p); + Release the chunk of memory pointed to by p, or no effect if p is null. + realloc(void* p, size_t n); + Return a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. The returned pointer may or may not be + the same as p. If p is null, equivalent to malloc. Unless the + #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a + size argument of zero (re)allocates a minimum-sized chunk. + memalign(size_t alignment, size_t n); + Return a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument, which must be a power of + two. Will fail if 'alignment' is too large. + calloc(size_t unit, size_t quantity); + Returns a pointer to quantity * unit bytes, with all locations + set to zero. + cfree(void* p); + Equivalent to free(p). + malloc_trim(size_t pad); + Release all but pad bytes of freed top-most memory back + to the system. Return 1 if successful, else 0. + malloc_usable_size(void* p); + Report the number usable allocated bytes associated with allocated + chunk p. This may or may not report more bytes than were requested, + due to alignment and minimum size constraints. + malloc_stats(); + Prints brief summary statistics on stderr. + mallinfo() + Returns (by copy) a struct containing various summary statistics. + mallopt(int parameter_number, int parameter_value) + Changes one of the tunable parameters described below. Returns + 1 if successful in changing the parameter, else 0. Actually, returns 0 + always, as no parameter can be changed. +*/ + +#ifdef __xstormy16__ +#define MALLOC_DIRECTION -1 +#endif + +#ifndef MALLOC_DIRECTION +#define MALLOC_DIRECTION 1 +#endif + +#include + +void* malloc(size_t); +void free(void*); +void* realloc(void*, size_t); +void* memalign(size_t, size_t); +void* valloc(size_t); +void* pvalloc(size_t); +void* calloc(size_t, size_t); +void cfree(void*); +int malloc_trim(size_t); +size_t malloc_usable_size(void*); +void malloc_stats(void); +int mallopt(int, int); +struct mallinfo mallinfo(void); + +typedef struct freelist_entry { + size_t size; + struct freelist_entry *next; +} *fle; + +extern void * __malloc_end; +extern fle __malloc_freelist; + +/* Return the number of bytes that need to be added to X to make it + aligned to an ALIGN boundary. ALIGN must be a power of 2. */ +#define M_ALIGN(x, align) (-(size_t)(x) & ((align) - 1)) + +/* Return the number of bytes that need to be subtracted from X to make it + aligned to an ALIGN boundary. ALIGN must be a power of 2. */ +#define M_ALIGN_SUB(x, align) ((size_t)(x) & ((align) - 1)) + +extern char *__malloc_start; + +/* This is the minimum gap allowed between __malloc_end and the top of + the stack. This is only checked for when __malloc_end is + decreased; if instead the stack grows into the heap, silent data + corruption will result. */ +#define MALLOC_MINIMUM_GAP 32 + +#ifdef __xstormy16__ +register void * stack_pointer asm ("r15"); +#define MALLOC_LIMIT stack_pointer +#else +#define MALLOC_LIMIT __builtin_frame_address (0) +#endif + +#if MALLOC_DIRECTION < 0 +#define CAN_ALLOC_P(required) \ + (((size_t) __malloc_end - (size_t)MALLOC_LIMIT \ + - MALLOC_MINIMUM_GAP) >= (required)) +#else +#define CAN_ALLOC_P(required) \ + (((size_t)MALLOC_LIMIT - (size_t) __malloc_end \ + - MALLOC_MINIMUM_GAP) >= (required)) +#endif + +/* real_size is the size we actually have to allocate, allowing for + overhead and alignment. */ +#define REAL_SIZE(sz) \ + ((sz) < sizeof (struct freelist_entry) - sizeof (size_t) \ + ? sizeof (struct freelist_entry) \ + : sz + sizeof (size_t) + M_ALIGN(sz, sizeof (size_t))) + +#ifdef DEFINE_MALLOC + +void * __malloc_end = &__malloc_start; +fle __malloc_freelist; + +void * +malloc (size_t sz) +{ + fle *nextfree; + fle block; + + /* real_size is the size we actually have to allocate, allowing for + overhead and alignment. */ + size_t real_size = REAL_SIZE (sz); + + /* Look for the first block on the freelist that is large enough. */ + for (nextfree = &__malloc_freelist; + *nextfree; + nextfree = &(*nextfree)->next) + { + block = *nextfree; + + if (block->size >= real_size) + { + /* If the block found is just the right size, remove it from + the free list. Otherwise, split it. */ + if (block->size < real_size + sizeof (struct freelist_entry)) + { + *nextfree = block->next; + return (void *)&block->next; + } + else + { + size_t newsize = block->size - real_size; + fle newnext = block->next; + *nextfree = (fle)((size_t)block + real_size); + (*nextfree)->size = newsize; + (*nextfree)->next = newnext; + goto done; + } + } + + /* If this is the last block on the freelist, and it was too small, + enlarge it. */ + if (! block->next + && __malloc_end == (void *)((size_t)block + block->size)) + { + size_t moresize = real_size - block->size; + if (! CAN_ALLOC_P (moresize)) + return NULL; + + *nextfree = NULL; + if (MALLOC_DIRECTION < 0) + { + block = __malloc_end = (void *)((size_t)block - moresize); + } + else + { + __malloc_end = (void *)((size_t)block + real_size); + } + + goto done; + } + } + + /* No free space at the end of the free list. Allocate new space + and use that. */ + + if (! CAN_ALLOC_P (real_size)) + return NULL; + + if (MALLOC_DIRECTION > 0) + { + block = __malloc_end; + __malloc_end = (void *)((size_t)__malloc_end + real_size); + } + else + { + block = __malloc_end = (void *)((size_t)__malloc_end - real_size); + } + done: + block->size = real_size; + return (void *)&block->next; +} + +#endif + +#ifdef DEFINE_FREE + +void +free (void *block_p) +{ + fle *nextfree; + fle block = (fle)((size_t) block_p - offsetof (struct freelist_entry, next)); + + if (block_p == NULL) + return; + + /* Look on the freelist to see if there's a free block just before + or just after this block. */ + for (nextfree = &__malloc_freelist; + *nextfree; + nextfree = &(*nextfree)->next) + { + fle thisblock = *nextfree; + if ((size_t)thisblock + thisblock->size == (size_t) block) + { + thisblock->size += block->size; + if (MALLOC_DIRECTION > 0 + && thisblock->next + && (size_t) block + block->size == (size_t) thisblock->next) + { + thisblock->size += thisblock->next->size; + thisblock->next = thisblock->next->next; + } + return; + } + else if ((size_t) thisblock == (size_t) block + block->size) + { + if (MALLOC_DIRECTION < 0 + && thisblock->next + && (size_t) block == ((size_t) thisblock->next + + thisblock->next->size)) + { + *nextfree = thisblock->next; + thisblock->next->size += block->size + thisblock->size; + } + else + { + block->size += thisblock->size; + block->next = thisblock->next; + *nextfree = block; + } + return; + } + else if ((MALLOC_DIRECTION > 0 + && (size_t) thisblock > (size_t) block) + || (MALLOC_DIRECTION < 0 + && (size_t) thisblock < (size_t) block)) + break; + } + + block->next = *nextfree; + *nextfree = block; + return; +} +#endif + +#ifdef DEFINE_REALLOC +void * +realloc (void *block_p, size_t sz) +{ + fle block = (fle)((size_t) block_p - offsetof (struct freelist_entry, next)); + size_t real_size = REAL_SIZE (sz); + size_t old_real_size; + + if (block_p == NULL) + return malloc (sz); + + old_real_size = block->size; + + /* Perhaps we need to allocate more space. */ + if (old_real_size < real_size) + { + void *result; + size_t old_size = old_real_size - sizeof (size_t); + + /* Need to allocate, copy, and free. */ + result = malloc (sz); + if (result == NULL) + return NULL; + memcpy (result, block_p, old_size < sz ? old_size : sz); + free (block_p); + return result; + } + /* Perhaps we can free some space. */ + if (old_real_size - real_size >= sizeof (struct freelist_entry)) + { + fle newblock = (fle)((size_t)block + real_size); + block->size = real_size; + newblock->size = old_real_size - real_size; + free (&newblock->next); + } + return block_p; +} +#endif + +#ifdef DEFINE_CALLOC +void * +calloc (size_t n, size_t elem_size) +{ + void *result; + size_t sz = n * elem_size; + result = malloc (sz); + if (result != NULL) + memset (result, 0, sz); + return result; +} +#endif + +#ifdef DEFINE_CFREE +void +cfree (void *p) +{ + free (p); +} +#endif + +#ifdef DEFINE_MEMALIGN +void * +memalign (size_t align, size_t sz) +{ + fle *nextfree; + fle block; + + /* real_size is the size we actually have to allocate, allowing for + overhead and alignment. */ + size_t real_size = REAL_SIZE (sz); + + /* Some sanity checking on 'align'. */ + if ((align & (align - 1)) != 0 + || align <= 0) + return NULL; + + /* Look for the first block on the freelist that is large enough. */ + /* One tricky part is this: We want the result to be a valid pointer + to free. That means that there has to be room for a size_t + before the block. If there's additional space before the block, + it should go on the freelist, or it'll be lost---we could add it + to the size of the block before it in memory, but finding the + previous block is expensive. */ + for (nextfree = &__malloc_freelist; + ; + nextfree = &(*nextfree)->next) + { + size_t before_size; + size_t old_size; + + /* If we've run out of free blocks, allocate more space. */ + if (! *nextfree) + { + old_size = real_size; + if (MALLOC_DIRECTION < 0) + { + old_size += M_ALIGN_SUB (((size_t)__malloc_end + - old_size + sizeof (size_t)), + align); + if (! CAN_ALLOC_P (old_size)) + return NULL; + block = __malloc_end = (void *)((size_t)__malloc_end - old_size); + } + else + { + block = __malloc_end; + old_size += M_ALIGN ((size_t)__malloc_end + sizeof (size_t), + align); + if (! CAN_ALLOC_P (old_size)) + return NULL; + __malloc_end = (void *)((size_t)__malloc_end + old_size); + } + *nextfree = block; + block->size = old_size; + block->next = NULL; + } + else + { + block = *nextfree; + old_size = block->size; + } + + + before_size = M_ALIGN (&block->next, align); + if (before_size != 0) + before_size = sizeof (*block) + M_ALIGN (&(block+1)->next, align); + + /* If this is the last block on the freelist, and it is too small, + enlarge it. */ + if (! block->next + && old_size < real_size + before_size + && __malloc_end == (void *)((size_t)block + block->size)) + { + if (MALLOC_DIRECTION < 0) + { + size_t moresize = real_size - block->size; + moresize += M_ALIGN_SUB ((size_t)&block->next - moresize, align); + if (! CAN_ALLOC_P (moresize)) + return NULL; + block = __malloc_end = (void *)((size_t)block - moresize); + block->next = NULL; + block->size = old_size = old_size + moresize; + before_size = 0; + } + else + { + if (! CAN_ALLOC_P (before_size + real_size - block->size)) + return NULL; + __malloc_end = (void *)((size_t)block + before_size + real_size); + block->size = old_size = before_size + real_size; + } + + /* Two out of the four cases below will now be possible; which + two depends on MALLOC_DIRECTION. */ + } + + if (old_size >= real_size + before_size) + { + /* This block will do. If there needs to be space before it, + split the block. */ + if (before_size != 0) + { + fle old_block = block; + + old_block->size = before_size; + block = (fle)((size_t)block + before_size); + + /* If there's no space after the block, we're now nearly + done; just make a note of the size required. + Otherwise, we need to create a new free space block. */ + if (old_size - before_size + <= real_size + sizeof (struct freelist_entry)) + { + block->size = old_size - before_size; + return (void *)&block->next; + } + else + { + fle new_block; + new_block = (fle)((size_t)block + real_size); + new_block->size = old_size - before_size - real_size; + if (MALLOC_DIRECTION > 0) + { + new_block->next = old_block->next; + old_block->next = new_block; + } + else + { + new_block->next = old_block; + *nextfree = new_block; + } + goto done; + } + } + else + { + /* If the block found is just the right size, remove it from + the free list. Otherwise, split it. */ + if (old_size <= real_size + sizeof (struct freelist_entry)) + { + *nextfree = block->next; + return (void *)&block->next; + } + else + { + size_t newsize = old_size - real_size; + fle newnext = block->next; + *nextfree = (fle)((size_t)block + real_size); + (*nextfree)->size = newsize; + (*nextfree)->next = newnext; + goto done; + } + } + } + } + + done: + block->size = real_size; + return (void *)&block->next; +} +#endif + +#ifdef DEFINE_VALLOC +void * +valloc (size_t sz) +{ + return memalign (128, sz); +} +#endif +#ifdef DEFINE_PVALLOC +void * +pvalloc (size_t sz) +{ + return memalign (128, sz + M_ALIGN (sz, 128)); +} +#endif + +#ifdef DEFINE_MALLINFO +#include "malloc.h" + +struct mallinfo +mallinfo (void) +{ + struct mallinfo r; + fle fr; + size_t free_size; + size_t total_size; + size_t free_blocks; + + memset (&r, 0, sizeof (r)); + + free_size = 0; + free_blocks = 0; + for (fr = __malloc_freelist; fr; fr = fr->next) + { + free_size += fr->size; + free_blocks++; + if (! fr->next) + { + int atend; + if (MALLOC_DIRECTION > 0) + atend = (void *)((size_t)fr + fr->size) == __malloc_end; + else + atend = (void *)fr == __malloc_end; + if (atend) + r.keepcost = fr->size; + } + } + + if (MALLOC_DIRECTION > 0) + total_size = (char *)__malloc_end - (char *)&__malloc_start; + else + total_size = (char *)&__malloc_start - (char *)__malloc_end; + +#ifdef DEBUG + /* Fixme: should walk through all the in-use blocks and see if + they're valid. */ +#endif + + r.arena = total_size; + r.fordblks = free_size; + r.uordblks = total_size - free_size; + r.ordblks = free_blocks; + return r; +} +#endif + +#ifdef DEFINE_MALLOC_STATS +#include "malloc.h" +#include + +void +malloc_stats(void) +{ + struct mallinfo i; + FILE *fp; + + fp = stderr; + i = mallinfo(); + fprintf (fp, "malloc has reserved %u bytes between %p and %p\n", + i.arena, &__malloc_start, __malloc_end); + fprintf (fp, "there are %u bytes free in %u chunks\n", + i.fordblks, i.ordblks); + fprintf (fp, "of which %u bytes are at the end of the reserved space\n", + i.keepcost); + fprintf (fp, "and %u bytes are in use.\n", i.uordblks); +} +#endif + +#ifdef DEFINE_MALLOC_USABLE_SIZE +size_t +malloc_usable_size (void *block_p) +{ + fle block = (fle)((size_t) block_p - offsetof (struct freelist_entry, next)); + return block->size - sizeof (size_t); +} +#endif + +#ifdef DEFINE_MALLOPT +int +mallopt (int n, int v) +{ + (void)n; (void)v; + return 0; +} +#endif -- cgit v1.1 From a8f4c20794b4eff8089f7fedb2d1bb4eff0a08d4 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 30 Jun 2016 13:11:20 -0700 Subject: Make variables local again, now that gdb is "fixed." --- debug/programs/debug.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'debug/programs') diff --git a/debug/programs/debug.c b/debug/programs/debug.c index 7d0b876..2010eaa 100644 --- a/debug/programs/debug.c +++ b/debug/programs/debug.c @@ -28,14 +28,10 @@ size_t strlen(const char *buf) return len; } -// TODO: These should be local to main, but if I make them global then gdb can -// find them. -static volatile int i; -static int j; int main() { - i = 0; - j = 0; + volatile int i = 0; + int j = 0; char *fox = "The quick brown fox jumps of the lazy dog."; unsigned int checksum = 0; -- cgit v1.1 From 3ed5afdc5b7e2c32bc6facf410c8fa091dd55470 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 30 Jun 2016 18:57:24 -0700 Subject: I think I've finally got malloc working right. Now gdb can call functions and change strings. --- debug/programs/debug.c | 7 +++++-- debug/programs/entry.S | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'debug/programs') diff --git a/debug/programs/debug.c b/debug/programs/debug.c index 2010eaa..20b1cdc 100644 --- a/debug/programs/debug.c +++ b/debug/programs/debug.c @@ -1,11 +1,10 @@ #include #include #include +#include unsigned int crc32a(uint8_t *message, unsigned int size); -char __malloc_start[512]; - void rot13(char *buf) { while (*buf) { @@ -28,8 +27,12 @@ size_t strlen(const char *buf) return len; } +extern void *__malloc_freelist; + int main() { + __malloc_freelist = 0; + volatile int i = 0; int j = 0; char *fox = "The quick brown fox jumps of the lazy dog."; diff --git a/debug/programs/entry.S b/debug/programs/entry.S index 480b404..80904cd 100755 --- a/debug/programs/entry.S +++ b/debug/programs/entry.S @@ -3,7 +3,7 @@ #include "encoding.h" -#define STACK_SIZE 128 +#define STACK_SIZE 512 #ifdef __riscv64 # define LREG ld @@ -124,9 +124,9 @@ trap_entry: addi sp, sp, 32*REGBYTES mret - .bss + // Fill the stack with data so we can see if it was overrun. .align 4 stack_bottom: - .skip STACK_SIZE + .fill STACK_SIZE/4, 4, 0x22446688 stack_top: #endif -- cgit v1.1 From 519794c8e91d1362dca8add5077277cc9bdc1611 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 18 Jul 2016 18:33:10 -0700 Subject: Add 32-bit support. --- debug/programs/mprv.S | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'debug/programs') diff --git a/debug/programs/mprv.S b/debug/programs/mprv.S index 2725b67..115ccb5 100644 --- a/debug/programs/mprv.S +++ b/debug/programs/mprv.S @@ -12,7 +12,11 @@ main: # update mstatus csrr t1, CSR_MSTATUS +#ifdef __riscv32 + li t0, (MSTATUS_MPRV | (VM_SV32 << 24)) +#else li t0, (MSTATUS_MPRV | (VM_SV39 << 24)) +#endif #li t0, ((VM_SV39 << 24)) or t1, t0, t1 csrw CSR_MSTATUS, t1 @@ -34,5 +38,9 @@ data: .balign 0x1000 page_table: - .word ((0x80000000 >> 2) | PTE_V | PTE_TYPE_URWX_SRWX) +#ifdef __riscv32 + .word ((0x80000000 >> 2) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_G | PTE_U) +#else + .word ((0x80000000 >> 2) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_G | PTE_U) .word 0 +#endif -- cgit v1.1