Skip to content

Instantly share code, notes, and snippets.

@levex
Created September 10, 2018 16:46
Show Gist options
  • Save levex/57d4dcffa984a566d47d61bdb488aebc to your computer and use it in GitHub Desktop.
Save levex/57d4dcffa984a566d47d61bdb488aebc to your computer and use it in GitHub Desktop.
HiFive1 barebones OSdev
OUTPUT_ARCH("riscv")
ENTRY(_start)
MEMORY
{
flash (rxai!w) : ORIGIN = 0x20400000, LENGTH = 512M
ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 16K
}
PHDRS
{
flash PT_LOAD;
ram_init PT_LOAD;
ram PT_NULL;
}
SECTIONS
{
__stack_size = DEFINED(__stack_size) ? __stack_size : 2K;
.init :
{
KEEP (*(SORT_NONE(.init)))
} >flash AT>flash :flash
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >flash AT>flash :flash
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} >flash AT>flash :flash
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} >flash AT>flash :flash
. = ALIGN(4);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >flash AT>flash :flash
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >flash AT>flash :flash
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >flash AT>flash :flash
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >flash AT>flash :flash
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >flash AT>flash :flash
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} >flash AT>flash :flash
.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} >ram AT>flash :ram_init
.data :
{
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >ram AT>flash :ram_init
. = ALIGN(4);
PROVIDE( _edata = . );
PROVIDE( edata = . );
PROVIDE( _fbss = . );
PROVIDE( __bss_start = . );
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >ram AT>ram :ram
. = ALIGN(8);
PROVIDE( _end = . );
PROVIDE( end = . );
.stack ORIGIN(ram) + LENGTH(ram) - __stack_size :
{
PROVIDE( _heap_end = . );
. = __stack_size;
PROVIDE( _sp = . );
} >ram AT>ram :ram
}
#include <stdint.h>
#include <stddef.h>
/* GPIO */
#define GPIO_CTRL_ADDR 0x10012000UL
#define GPIO_IOF_EN 0x38
#define GPIO_IOF_SEL 0x3C
#define IOF0_UART0_MASK 0x00030000UL
/* UART */
#define UART0_CTRL_ADDR 0x10013000UL
#define UART_REG_TXFIFO 0x00
#define UART_REG_RXFIFO 0x04
#define UART_REG_TXCTRL 0x08
#define UART_REG_RXCTRL 0x0c
#define UART_REG_IE 0x10
#define UART_REG_IP 0x14
#define UART_REG_DIV 0x18
#define UART_TXEN 0x1
/* PRCI */
#define PRCI_CTRL_ADDR 0x10008000UL
#define PRCI_HFROSCCFG (0x0000)
#define PRCI_PLLCFG (0x0008)
#define ROSC_EN(x) (((x) & 0x1) << 30)
#define PLL_REFSEL(x) (((x) & 0x1) << 17)
#define PLL_BYPASS(x) (((x) & 0x1) << 18)
#define PLL_SEL(x) (((x) & 0x1) << 16)
static inline uint32_t
mmio_read_u32(unsigned long reg, unsigned int offset)
{
return (*(volatile uint32_t *) ((reg) + (offset)));
}
static inline void
mmio_write_u8(unsigned long reg, unsigned int offset, uint8_t val)
{
(*(volatile uint32_t *) ((reg) + (offset))) = val;
}
static inline void
mmio_write_u32(unsigned long reg, unsigned int offset, uint32_t val)
{
(*(volatile uint32_t *) ((reg) + (offset))) = val;
}
static void uart_init(size_t baud_rate)
{
mmio_write_u32(GPIO_CTRL_ADDR,
GPIO_IOF_SEL,
mmio_read_u32(GPIO_CTRL_ADDR, GPIO_IOF_SEL)
& ~IOF0_UART0_MASK);
mmio_write_u32(GPIO_CTRL_ADDR,
GPIO_IOF_EN,
mmio_read_u32(GPIO_CTRL_ADDR, GPIO_IOF_EN)
| IOF0_UART0_MASK);
mmio_write_u32(UART0_CTRL_ADDR, UART_REG_DIV, 138);
mmio_write_u32(UART0_CTRL_ADDR,
UART_REG_TXCTRL,
mmio_read_u32(UART0_CTRL_ADDR, UART_REG_TXCTRL)
| UART_TXEN);
/* busy loop until the line is asserted... */
volatile int i = 0;
while(i++ < 1000000);
}
static void
__uart_write(uint8_t byte)
{
/* wait for the UART to become ready */
while (mmio_read_u32(UART0_CTRL_ADDR, UART_REG_TXFIFO) & 0x80000000)
;
/* write to the UART transmit FIFO */
mmio_write_u8(UART0_CTRL_ADDR, UART_REG_TXFIFO, byte);
}
static void
uart_write(uint8_t *buf, size_t len)
{
int i;
for (i = 0; i < len; i ++) {
__uart_write(buf[i]);
/* If an LF was written, also write a CR */
if (buf[i] == '\n') {
__uart_write('\r');
}
}
}
static size_t
strlen(char *str)
{
int len = 0;
int i;
for (i = 0; str[i] != 0; i ++)
{
len ++;
}
return len;
}
static void
uart_write_string(uint8_t *buf)
{
uart_write(buf, strlen((char *) buf));
}
static void
prci_init(void)
{
// Make sure the HFROSC is on before the next line:
mmio_write_u32(PRCI_CTRL_ADDR, PRCI_HFROSCCFG,
mmio_read_u32(PRCI_CTRL_ADDR, PRCI_HFROSCCFG)
| ROSC_EN(1));
// Run off 16 MHz Crystal for accuracy. Note that the
// first line is
mmio_write_u32(PRCI_CTRL_ADDR, PRCI_PLLCFG,
mmio_read_u32(PRCI_CTRL_ADDR, PRCI_PLLCFG)
| (PLL_REFSEL(1) | PLL_BYPASS(1)));
mmio_write_u32(PRCI_CTRL_ADDR, PRCI_PLLCFG,
mmio_read_u32(PRCI_CTRL_ADDR, PRCI_PLLCFG)
| (PLL_SEL(1)));
// Turn off HFROSC to save power
mmio_write_u32(PRCI_CTRL_ADDR, PRCI_HFROSCCFG,
mmio_read_u32(PRCI_CTRL_ADDR, PRCI_HFROSCCFG)
& ~(ROSC_EN(1)));
}
void
main(void)
{
prci_init();
uart_init(115200);
uart_write_string("Hello, world, this is myOS on the HiFive-1 Board!\n");
/* For now, just halt */
for (;;);
}
__attribute__((section(".init")))
void
_start(void)
{
main();
}
SDK=/home/lkurusa/dev/freedom-e-sdk
SDK_PREFIX=$(SDK)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/bin
CROSS=$(SDK_PREFIX)/riscv64-unknown-elf-
CFLAGS=-g \
-march=rv32imac \
-mabi=ilp32 \
-mcmodel=medany
LINKER_SCRIPT=hifive1.lds
LDFLAGS=-T $(LINKER_SCRIPT) \
-nostartfiles
main.img: main.c
$(CROSS)gcc $< $(CFLAGS) -o $@ $(LDFLAGS)
.PHONY: clean
clean:
rm -rf main.img
rm -rf main.o
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment