Problem with SBRK not returning from call on bare metal risk
Damien Towning
connolly.damien@gmail.com
Mon Mar 6 07:36:38 GMT 2023
So a bit of a background. I have the bonfire Risc-V 32 core running on a
T-35 FPGA board. The metal part of this is working great. The processor
runs. I've got it to turn around the segment display on the board. I've
also implemented my own _sbrk and got that to work I think consistently
with malloc. Now in my Risc-v 32 toolchain I have the newlib and I have
brought that in and with my own wrapped _sbrk I am able to use the system
defined malloc. But I am not entirely happy with this because I don't want
to be wrapping every function I encounter. So for example today I found
myself wrapping srand and rand. So I am pretty sure the reason my
nano_newlib isn't working is something to do with either not having the
correct variable names in my firmware.ld or something to do with disabling
the re-entrant behaviour of newlib. I've included in this email my
firmware.ld,platform.h,c code example. What happens is I call the _sbrk(0)
and ( in the simulator I am also running this in ) I never see a bad opcode
generated. It just seems like the processor goes away and never comes back.
Does anybody have any suggestions as to what might cause this sort of
problem ? I'd like to use the sbrk and other funcitons within the newlib
itself if possible without rolling my own.
------------- firmware.ld
MEMORY
{
RAM (rwx) : ORIGIN = 0x0C000000, LENGTH = 512K
}
ENTRY(_start)
SECTIONS
{
_rombase = 0x0C000000;
. = 0x0;
.text : {
*(.init)
*(.text.*)
} > RAM
.data ALIGN(4) : {
*(.rodata.*)
*(.rodata)
*(.eh_frame)
*(.sdata)
*(.data)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
end = .; _end = .; __end = .;
} > RAM
_heap_end = _end;
_heap_prev_end = _end;
}
PROVIDE(__heap_end = _end);
PROVIDE(__prev_heap_end = _end);
PROVIDE(__heap_start = _end+128K);
PROVIDE(__stack_top = ORIGIN(RAM) + LENGTH(RAM));
PROVIDE(__stack_start = ORIGIN(RAM) + LENGTH(RAM));
PROVIDE(__heap_size = 128K );
PROVIDE(__stack_size = 128K );
/*
0x0C000000 +-------------------+
| |
| ROM / Flash |
0x0C080000 +-------------------+
| |
| .data |
|-------------------|
| .bss / .sbss |
|-------------------|
| _end |
|-------------------|
| Heap |
|-------------------|
| Stack |
0xXXXXXXXX +-------------------+
*/
--------------------------------------------------------------------------------------
---------platform.h
----------------------------------------------------------------
#ifndef BASIC_PLATFORM_H
#define BASIC_PLATFORM_H
// New Defintions for new bonfire-soc-io core
#define IO_BASE 0x04000000
#define SOC_IO_OFFSET 0x10000 // Offset from one I/O Device to the next
(64K range)
#define UART0_BASE IO_BASE
#define SPIFLASH_BASE (IO_BASE+SOC_IO_OFFSET)
#define GPIO_BASE (IO_BASE+3*SOC_IO_OFFSET)
#define UART1_BASE (IO_BASE+2*SOC_IO_OFFSET)
#define UART_BASE UART0_BASE // Backwards compatiblity
#define MTIME_BASE 0x0FFFF0000
#define DRAM_BASE 0x0
#define DRAM_SIZE 0
#define DRAM_TOP (DRAM_BASE+DRAM_SIZE-1)
#define SRAM_BASE 0x0C000000
#define SRAM_SIZE 524288
#define SRAM_TOP (SRAM_BASE+SRAM_SIZE-1)
//#define SYSCLK 12000000
//#define SYSCLK 33333333
//#define SYSCLK 24997500
//#define SYSCLK 88786000
#define EXT_SYSCLK 89015000
#define SYSCLK 24997500
//#define EXT_SYSCLK 92370000 /* For reasons not clear to me when any
change is made to the interface */
/* configuration in Efinity and a new synthesis is done a clock time will
*/
/* be calculated so you must build your efinity project. Take that new
*/
/* time value. Update it here. Rebuild your hex file. Then rebuild your
*/
/* efinity project AGAIN
*/
#define TIME_UNIT 1e+9; // A billion
#ifndef SIMULATOR
#define SCALAR 1 // Relative Scalar division for efinity build
#define BAUD_SCALAR 1 // Relative Scalar division for efinity build
#else
#define SCALAR 10000 // Relative Scalar division for simulator. Use for
any of your own timing since
#define BAUD_SCALAR 20 // simulator runs slower than real hardware
#endif
#define CLK_PERIOD (TIME_UNIT / EXT_SYSCLK) // in ns...
//#define DCACHE_SIZE 0 // (2048*4) // DCache Size in Bytes
// Parameters for SPI Flash
#define FLASHSIZE (8192*1024)
#define MAX_FLASH_IMAGESIZE (2024*1024) // Max 2MB of flash used for boot
image
#define FLASH_IMAGEBASE (1024*3072) // Boot Image starts at 3MB in Flash
#define PLATFORM_BAUDRATE (115200*BAUD_SCALAR)
#define NO_RECURSION
#define NO_SYSCALL
#define NO_FLASH
#define NO_XMODEM
#define NO_DRAMTEST
//#define GPIO_TEST
#endif
---------------------------------------------------------------------------------------------
---- sim_hello.c
------------------------------------------------------------------------
// ==============================================
// T35 S100 Module Test Code
// Damien Towning - 2022
// ==============================================
#include <stdioSo a bit of a background. I have the bonfire Risc-V 32 core
running on a T-35 FPGA board. The metal part of this is working great. The
processor runs. I've got it to turn around the segment display on the
board. I've also implemented my own _sbrk and got that to work I think
consistently with malloc. Now in my Risc-v 32 toolchain I have the newlib
and I have brought that in and with my own wrapped _sbrk I am able to use
the system defined malloc. But I am not entirely happy with this because I
don't want to be wrapping every function I encounter. So for example today
I found myself wrapping srand and rand. So I am pretty sure the reason my
nano_newlib isn't working is something to do with either not having the
correct variable names in my firmware.ld or something to do with disabling
the re-entrant behaviour of newlib. I've included in this email my
firmware.ld,platform.h,c code example. What happens is I call the _sbrk(0)
and ( in the simulator I am also running this in ) I never see a bad opcode
generated. It just seems like the processor goes away and never comes back.
Does anybody have any suggestions as to what might cause this sort of
problem ? I'd like to use the sbrk and other funcitons within the newlib
itself if possible without rolling my own.
------------- firmware.ld
MEMORY
{
RAM (rwx) : ORIGIN = 0x0C000000, LENGTH = 512K
}
ENTRY(_start)
SECTIONS
{
_rombase = 0x0C000000;
. = 0x0;
.text : {
*(.init)
*(.text.*)
} > RAM
.data ALIGN(4) : {
*(.rodata.*)
*(.rodata)
*(.eh_frame)
*(.sdata)
*(.data)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
end = .; _end = .; __end = .;
} > RAM
_heap_end = _end;
_heap_prev_end = _end;
}
PROVIDE(__heap_end = _end);
PROVIDE(__prev_heap_end = _end);
PROVIDE(__heap_start = _end+128K);
PROVIDE(__stack_top = ORIGIN(RAM) + LENGTH(RAM));
PROVIDE(__stack_start = ORIGIN(RAM) + LENGTH(RAM));
PROVIDE(__heap_size = 128K );
PROVIDE(__stack_size = 128K );
/*
0x0C000000 +-------------------+
| |
| ROM / Flash |
0x0C080000 +-------------------+
| |
| .data |
|-------------------|
| .bss / .sbss |
|-------------------|
| _end |
|-------------------|
| Heap |
|-------------------|
| Stack |
0xXXXXXXXX +-------------------+
*/
--------------------------------------------------------------------------------------
---------platform.h
----------------------------------------------------------------
#ifndef BASIC_PLATFORM_H
#define BASIC_PLATFORM_H
// New Defintions for new bonfire-soc-io core
#define IO_BASE 0x04000000
#define SOC_IO_OFFSET 0x10000 // Offset from one I/O Device to the next
(64K range)
#define UART0_BASE IO_BASE
#define SPIFLASH_BASE (IO_BASE+SOC_IO_OFFSET)
#define GPIO_BASE (IO_BASE+3*SOC_IO_OFFSET)
#define UART1_BASE (IO_BASE+2*SOC_IO_OFFSET)
#define UART_BASE UART0_BASE // Backwards compatiblity
#define MTIME_BASE 0x0FFFF0000
#define DRAM_BASE 0x0
#define DRAM_SIZE 0
#define DRAM_TOP (DRAM_BASE+DRAM_SIZE-1)
#define SRAM_BASE 0x0C000000
#define SRAM_SIZE 524288
#define SRAM_TOP (SRAM_BASE+SRAM_SIZE-1)
//#define SYSCLK 12000000
//#define SYSCLK 33333333
//#define SYSCLK 24997500
//#define SYSCLK 88786000
#define EXT_SYSCLK 89015000
#define SYSCLK 24997500
//#define EXT_SYSCLK 92370000 /* For reasons not clear to me when any
change is made to the interface */
/* configuration in Efinity and a new synthesis is done a clock time will
*/
/* be calculated so you must build your efinity project. Take that new
*/
/* time value. Update it here. Rebuild your hex file. Then rebuild your
*/
/* efinity project AGAIN
*/
#define TIME_UNIT 1e+9; // A billion
#ifndef SIMULATOR
#define SCALAR 1 // Relative Scalar division for efinity build
#define BAUD_SCALAR 1 // Relative Scalar division for efinity build
#else
#define SCALAR 10000 // Relative Scalar division for simulator. Use for
any of your own timing since
#define BAUD_SCALAR 20 // simulator runs slower than real hardware
#endif
#define CLK_PERIOD (TIME_UNIT / EXT_SYSCLK) // in ns...
//#define DCACHE_SIZE 0 // (2048*4) // DCache Size in Bytes
// Parameters for SPI Flash
#define FLASHSIZE (8192*1024)
#define MAX_FLASH_IMAGESIZE (2024*1024) // Max 2MB of flash used for boot
image
#define FLASH_IMAGEBASE (1024*3072) // Boot Image starts at 3MB in Flash
#define PLATFORM_BAUDRATE (115200*BAUD_SCALAR)
#define NO_RECURSION
#define NO_SYSCALL
#define NO_FLASH
#define NO_XMODEM
#define NO_DRAMTEST
//#define GPIO_TEST
#endif
---------------------------------------------------------------------------------------------
---- sim_hello.c
------------------------------------------------------------------------
// ==============================================
// T35 S100 Module Test Code
// Damien Towning - 2022
// ==============================================
#include <stdio.h>
#include <stdlib.h>
//#include <newlib.h>
//#include <nano_malloc.h>
#include <errno.h>
#include <sys/types.h>
#include <string.h>
#include "bonfire.h"
#include "uart.h"
#include "bonfire_gpio.h"
#include "mem_rw.h"
#include "console.h"
extern void* sbrk(incr);
// ========================================
// Main function
// ========================================
int main() {
setBaudRate(PLATFORM_BAUDRATE);
caddr_t *ptr = sbrk(0);
// code never returns from sbrk
if (ptr == (void *)-1) {
printk("Failed to allocate memory\r\n");
}
else {
printk("Allocated memory at : %p\r\n", (void *) &ptr);
}
return 0;
}
------------------------------------------------------------------------------------
--- Makefile
--------------------------------------------------------------------
.PHONY: all clean
ARCH ?= rv32ia
ABI=ilp32
PLATFORM ?= S100_T35
#TARGET_PREFIX ?= riscv32-unknown-linux-gnu
TARGET_PREFIX ?= riscv32-unknown-elf
TARGET_CC := $(TARGET_PREFIX)-gcc
TARGET_LD := $(TARGET_PREFIX)-gcc
TARGET_SIZE := $(TARGET_PREFIX)-size
TARGET_OBJCOPY := $(TARGET_PREFIX)-objcopy
HEXDUMP ?= hexdump
DATA2MEM = /opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/data2mem
#PROJROOT = ../../..
#TOPLEVEL = ~/riscv/ise/bonfire/papilio_pro_dram_toplevel.bit
PLATFORMDIR=../platform
LINKDEF?=$(PLATFORMDIR)/$(PLATFORM)/firmware.ld
TARGET_CFLAGS += -march=$(ARCH) -mabi=$(ABI) -Wall -Os -g
-fomit-frame-pointer \
-ffreestanding -fno-builtin \
-Wall -Werror=implicit-function-declaration \
-D$(PLATFORM)
ifeq ($(SIMULATOR), 1)
TARGET_CFLAGS+=-DSIMULATOR
endif
TARGET_CFLAGS+=-I$(PLATFORMDIR) -I$(PLATFORMDIR)/$(PLATFORM) -I../riscv
# If we wish to build with no newlib
#TARGET_LDFLAGS += -march=$(ARCH) -mabi=$(ABI) -nostartfiles \
-Wl,-m,elf32lriscv,--wrap=malloc,--wrap=sbrk --specs=nosys.specs
-Wl,-T$(LINKDEF) \
-Wl,--gc-sections
TARGET_LDFLAGS += -march=$(ARCH) -mabi=$(ABI) -nostartfiles \
-Wl,-m,elf32lriscv,--wrap=_srand,--wrap=_rand --specs=nano.specs
-Wl,-Map=output.map,-T$(LINKDEF) \
-Wl,--gc-sections
all: sim_hello.hex memtest.hex nanotest.hex
%.o : %.S
$(TARGET_CC) $(TARGET_CFLAGS) -c $<
%.o : %.c
$(TARGET_CC) $(TARGET_CFLAGS) -c $<
%.hex : %.elf
$(TARGET_OBJCOPY) -S -O binary $< $(basename $@).bin
$(HEXDUMP) -v -e '1/4 "%08x\n"' $(basename $@).bin >$@
$(TARGET_PREFIX)-objdump -S -d $< >$(basename $@).lst
#$(TARGET_PREFIX)-objdump -D $< >$(basename $@).S
$(TARGET_PREFIX)-objdump -s $< >$(basename $@).dmp
$(TARGET_PREFIX)-size $<
#sbrk.o: libwrap/sbrk.c
# $(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c libwrap/sbrk.c
rand.o: libwrap/rand.c
$(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c libwrap/rand.c
uart.o: uart.c
$(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c uart.c
#sim_hello.o : sim_hello.c
# $(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c sim_hello.c
sim_hello.elf: start.o uart.o sim_hello.o snprintf.o console.o rand.o
$(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o sim_hello.o snprintf.o
console.o rand.o
#memtest.elf: start.o uart.o memtest.o snprintf.o console.o mempattern.o
sbrk.o
# $(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o memtest.o snprintf.o
console.o mempattern.o sbrk.o
#nanotest.elf: start.o uart.o nanotest.o snprintf.o console.o mempattern.o
sbrk.o
# $(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o nanotest.o snprintf.o
console.o mempattern.o sbrk.o
#jump0.elf : jump0.S
# $(TARGET_LD) -o $@ -march=RV32IM -nostartfiles -Wl,-T$(BOOTLINK) $<
clean:
rm -f *.o
---------------------------------------------------------------------------------------------.h>
#include <stdlib.h>
//#include <newlib.h>
//#include <nano_malloc.h>
#include <errno.h>
#include <sys/types.h>
#include <string.h>
#include "bonfire.h"
#include "uart.h"
#include "bonfire_gpio.h"
#include "mem_rw.h"
#include "console.h"
extern void* sbrk(incr);
// ========================================
// Main function
// ========================================
int main() {
setBaudRate(PLATFORM_BAUDRATE);
caddr_t *ptr = sbrk(0);
// code never returns from sbrk
if (ptr == (void *)-1) {
printk("Failed to allocate memory\r\n");
}
else {
printk("Allocated memory at : %p\r\n", (void *) &ptr);
}
return 0;
}
------------------------------------------------------------------------------------
--- Makefile
--------------------------------------------------------------------
.PHONY: all clean
ARCH ?= rv32ia
ABI=ilp32
PLATFORM ?= S100_T35
#TARGET_PREFIX ?= riscv32-unknown-linux-gnu
TARGET_PREFIX ?= riscv32-unknown-elf
TARGET_CC := $(TARGET_PREFIX)-gcc
TARGET_LD := $(TARGET_PREFIX)-gcc
TARGET_SIZE := $(TARGET_PREFIX)-size
TARGET_OBJCOPY := $(TARGET_PREFIX)-objcopy
HEXDUMP ?= hexdump
DATA2MEM = /opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/data2mem
#PROJROOT = ../../..
#TOPLEVEL = ~/riscv/ise/bonfire/papilio_pro_dram_toplevel.bit
PLATFORMDIR=../platform
LINKDEF?=$(PLATFORMDIR)/$(PLATFORM)/firmware.ld
TARGET_CFLAGS += -march=$(ARCH) -mabi=$(ABI) -Wall -Os -g
-fomit-frame-pointer \
-ffreestanding -fno-builtin \
-Wall -Werror=implicit-function-declaration \
-D$(PLATFORM)
ifeq ($(SIMULATOR), 1)
TARGET_CFLAGS+=-DSIMULATOR
endif
TARGET_CFLAGS+=-I$(PLATFORMDIR) -I$(PLATFORMDIR)/$(PLATFORM) -I../riscv
# If we wish to build with no newlib
#TARGET_LDFLAGS += -march=$(ARCH) -mabi=$(ABI) -nostartfiles \
-Wl,-m,elf32lriscv,--wrap=malloc,--wrap=sbrk --specs=nosys.specs
-Wl,-T$(LINKDEF) \
-Wl,--gc-sections
TARGET_LDFLAGS += -march=$(ARCH) -mabi=$(ABI) -nostartfiles \
-Wl,-m,elf32lriscv,--wrap=_srand,--wrap=_rand --specs=nano.specs
-Wl,-Map=output.map,-T$(LINKDEF) \
-Wl,--gc-sections
all: sim_hello.hex memtest.hex nanotest.hex
%.o : %.S
$(TARGET_CC) $(TARGET_CFLAGS) -c $<
%.o : %.c
$(TARGET_CC) $(TARGET_CFLAGS) -c $<
%.hex : %.elf
$(TARGET_OBJCOPY) -S -O binary $< $(basename $@).bin
$(HEXDUMP) -v -e '1/4 "%08x\n"' $(basename $@).bin >$@
$(TARGET_PREFIX)-objdump -S -d $< >$(basename $@).lst
#$(TARGET_PREFIX)-objdump -D $< >$(basename $@).S
$(TARGET_PREFIX)-objdump -s $< >$(basename $@).dmp
$(TARGET_PREFIX)-size $<
#sbrk.o: libwrap/sbrk.c
# $(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c libwrap/sbrk.c
rand.o: libwrap/rand.c
$(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c libwrap/rand.c
uart.o: uart.c
$(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c uart.c
#sim_hello.o : sim_hello.c
# $(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c sim_hello.c
sim_hello.elf: start.o uart.o sim_hello.o snprintf.o console.o rand.o
$(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o sim_hello.o snprintf.o
console.o rand.o
#memtest.elf: start.o uart.o memtest.o snprintf.o console.o mempattern.o
sbrk.o
# $(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o memtest.o snprintf.o
console.o mempattern.o sbrk.o
#nanotest.elf: start.o uart.o nanotest.o snprintf.o console.o mempattern.o
sbrk.o
# $(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o nanotest.o snprintf.o
console.o mempattern.o sbrk.o
#jump0.elf : jump0.S
# $(TARGET_LD) -o $@ -march=RV32IM -nostartfiles -Wl,-T$(BOOTLINK) $<
clean:
rm -f *.o
---------------------------------------------------------------------------------------------
--
Damien Towning
More information about the Newlib
mailing list