am: add riscv64-rocket

This commit is contained in:
Zihao Yu 2017-07-04 19:01:51 +08:00
parent b458a3ad58
commit 73596f368c
14 changed files with 538 additions and 0 deletions

View File

@ -7,6 +7,10 @@ ifeq ($(ISA), mips32)
CROSS_COMPILE = mips-linux-gnu-
endif
ifeq ($(ISA), riscv64)
CROSS_COMPILE = riscv64-unknown-linux-gnu-
endif
AS = $(CROSS_COMPILE)gcc
CC = $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
@ -28,6 +32,12 @@ CXXFLAGS += $(CFLAGS_COMMON) -ffreestanding -fno-rtti -fno-exceptions
ASFLAGS += -march=mips32 -EL -mno-check-zero-division -O0 -mno-abicalls -fno-pic -fno-delayed-branch
endif
ifeq ($(ISA), riscv64)
CFLAGS_COMMON = -fno-pic -static -mcmodel=medany -fno-delete-null-pointer-checks -mabi=lp64 -march=rv64imac
CFLAGS += $(CFLAGS_COMMON)
CXXFLAGS += $(CFLAGS_COMMON) -ffreestanding -fno-rtti -fno-exceptions
endif
ifeq ($(ISA), x86)
CFLAGS += -m32 -fno-pic -fno-builtin -fno-stack-protector -fno-omit-frame-pointer -march=i386
CXXFLAGS += -m32 -fno-pic -fno-builtin -fno-stack-protector -fno-omit-frame-pointer -march=i386 -ffreestanding -fno-rtti -fno-exceptions

View File

@ -0,0 +1 @@
# RISCV64-rocket

View File

@ -0,0 +1,4 @@
start.o: start.S
riscv64-unknown-linux-gnu-gcc -mabi=lp64 -march=rv64imac -I$(AM_HOME)/am/arch/riscv64-rocket/include -fno-pic -ffunction-sections -MMD -c start.S -o start.o
-include start.d

View File

@ -0,0 +1,15 @@
.section entry, "ax"
.globl _start
.type _start, @function
.extern fdt
_start:
la sp, stack_end
la t0, fdt
sw x11, (t0)
tail _trm_init
stack:
.skip 0x4000
stack_end:

View File

@ -0,0 +1,10 @@
#!/bin/bash
DIR=${AM_HOME}/am/arch/riscv64-rocket/img
DEST=$1
shift
bash -c "cd $DIR/boot && make"
riscv64-unknown-linux-gnu-ld --gc-sections -T $DIR/loader.ld -e _start -o $DEST $DIR/boot/start.o --start-group $@ --end-group
riscv64-unknown-linux-gnu-objdump -d $DEST > $DEST.txt

View File

@ -0,0 +1,22 @@
SECTIONS {
. = 0x80000000;
entry : { *(entry) }
.text : {
*(.text*)
}
.rodata : {
*(.rodata*)
}
etext = .;
_etext = .;
.data : {
*(.data*)
}
edata = .;
_edata = .;
.bss : {
*(.bss*)
}
end = .;
_end = .;
}

3
am/arch/riscv64-rocket/img/run Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
echo "Run with rocketchip project"

View File

@ -0,0 +1,14 @@
#ifndef __ARCH_H__
#define __ARCH_H__
struct _RegSet {
};
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,6 @@
#ifndef __RISCV64_ROCKET__
#define __RISCV64_ROCKET__
#define MAX_HARTS 2
#endif

View File

@ -0,0 +1,123 @@
#include <klib.h>
#include "fdt.h"
#include "riscv64-rocket.h"
static inline uint32_t bswap(uint32_t x)
{
uint32_t y = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
uint32_t z = (y & 0x0000FFFF) << 16 | (y & 0xFFFF0000) >> 16;
return z;
}
static uint32_t *fdt_scan_helper(
uint32_t *lex,
const char *strings,
struct fdt_scan_node *node,
const struct fdt_cb *cb)
{
struct fdt_scan_node child;
struct fdt_scan_prop prop;
int last = 0;
child.parent = node;
// these are the default cell counts, as per the FDT spec
child.address_cells = 2;
child.size_cells = 1;
prop.node = node;
while (1) {
switch (bswap(lex[0])) {
case FDT_NOP: {
lex += 1;
break;
}
case FDT_PROP: {
assert (!last);
prop.name = strings + bswap(lex[2]);
prop.len = bswap(lex[1]);
prop.value = lex + 3;
if (node && !strcmp(prop.name, "#address-cells")) { node->address_cells = bswap(lex[3]); }
if (node && !strcmp(prop.name, "#size-cells")) { node->size_cells = bswap(lex[3]); }
lex += 3 + (prop.len+3)/4;
cb->prop(&prop, cb->extra);
break;
}
case FDT_BEGIN_NODE: {
uint32_t *lex_next;
if (!last && node && cb->done) cb->done(node, cb->extra);
last = 1;
child.name = (const char *)(lex+1);
if (cb->open) cb->open(&child, cb->extra);
lex_next = fdt_scan_helper(
lex + 2 + strlen(child.name)/4,
strings, &child, cb);
if (cb->close && cb->close(&child, cb->extra) == -1)
while (lex != lex_next) *lex++ = bswap(FDT_NOP);
lex = lex_next;
break;
}
case FDT_END_NODE: {
if (!last && node && cb->done) cb->done(node, cb->extra);
return lex + 1;
}
default: { // FDT_END
if (!last && node && cb->done) cb->done(node, cb->extra);
return lex;
}
}
}
}
void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb)
{
struct fdt_header *header = (struct fdt_header *)fdt;
// Only process FDT that we understand
if (bswap(header->magic) != FDT_MAGIC ||
bswap(header->last_comp_version) > FDT_VERSION) return;
const char *strings = (const char *)(fdt + bswap(header->off_dt_strings));
uint32_t *lex = (uint32_t *)(fdt + bswap(header->off_dt_struct));
fdt_scan_helper(lex, strings, 0, cb);
}
uint32_t fdt_size(uintptr_t fdt)
{
struct fdt_header *header = (struct fdt_header *)fdt;
// Only process FDT that we understand
if (bswap(header->magic) != FDT_MAGIC ||
bswap(header->last_comp_version) > FDT_VERSION) return 0;
return bswap(header->totalsize);
}
const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result)
{
*result = 0;
for (int cells = node->address_cells; cells > 0; --cells)
*result = (*result << 32) + bswap(*value++);
return value;
}
const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result)
{
*result = 0;
for (int cells = node->size_cells; cells > 0; --cells)
*result = (*result << 32) + bswap(*value++);
return value;
}
int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str)
{
const char *list = (const char *)prop->value;
const char *end = list + prop->len;
int index = 0;
while (end - list > 0) {
if (!strcmp(list, str)) return index;
++index;
list += strlen(list) + 1;
}
return -1;
}

View File

@ -0,0 +1,71 @@
#ifndef FDT_H
#define FDT_H
#define FDT_MAGIC 0xd00dfeed
#define FDT_VERSION 17
struct fdt_header {
uint32_t magic;
uint32_t totalsize;
uint32_t off_dt_struct;
uint32_t off_dt_strings;
uint32_t off_mem_rsvmap;
uint32_t version;
uint32_t last_comp_version; /* <= 17 */
uint32_t boot_cpuid_phys;
uint32_t size_dt_strings;
uint32_t size_dt_struct;
};
#define FDT_BEGIN_NODE 1
#define FDT_END_NODE 2
#define FDT_PROP 3
#define FDT_NOP 4
#define FDT_END 9
struct fdt_scan_node {
const struct fdt_scan_node *parent;
const char *name;
int address_cells;
int size_cells;
};
struct fdt_scan_prop {
const struct fdt_scan_node *node;
const char *name;
uint32_t *value;
int len; // in bytes of value
};
struct fdt_cb {
void (*open)(const struct fdt_scan_node *node, void *extra);
void (*prop)(const struct fdt_scan_prop *prop, void *extra);
void (*done)(const struct fdt_scan_node *node, void *extra); // last property was seen
int (*close)(const struct fdt_scan_node *node, void *extra); // -1 => delete the node + children
void *extra;
};
// Scan the contents of FDT
void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb);
uint32_t fdt_size(uintptr_t fdt);
// Extract fields
const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *base, uint64_t *value);
const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *base, uint64_t *value);
int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str); // -1 if not found
// Setup memory+clint+plic
void query_mem(uintptr_t fdt);
void query_harts(uintptr_t fdt);
void query_plic(uintptr_t fdt);
void query_clint(uintptr_t fdt);
// Remove information from FDT
void filter_harts(uintptr_t fdt, unsigned long hart_mask);
void filter_plic(uintptr_t fdt);
void filter_compat(uintptr_t fdt, const char *compat);
// The hartids of available harts
extern uint64_t hart_mask;
#endif

View File

@ -0,0 +1,36 @@
#include <am.h>
void _ioe_init() {
}
// -------------------- cycles and uptime --------------------
static unsigned long riscv64_time = 0;
unsigned long _uptime(){
return riscv64_time ++;
}
// -------------------- video --------------------
_Screen _screen = {
.width = 0,
.height = 0,
};
void _draw_p(int x, int y, uint32_t p) {
}
void _draw_sync() {
}
// -------------------- keyboard --------------------
static inline int upevent(int e) { return e; }
static inline int downevent(int e) { return e | 0x8000; }
int _read_key(){
return _KEY_NONE;
}

View File

@ -0,0 +1,110 @@
#include <am.h>
#include <klib.h>
#include "fdt.h"
uintptr_t fdt = 0;
static uintptr_t mem_size = 0;
extern char _end;
extern int main();
extern void uart_init(uintptr_t fdt);
extern void uart_send(uint8_t data);
_Area _heap = {
.start = &_end,
};
//////////////////////////////////////////// MEMORY SCAN /////////////////////////////////////////
struct mem_scan {
int memory;
const uint32_t *reg_value;
int reg_len;
};
static void mem_open(const struct fdt_scan_node *node, void *extra)
{
struct mem_scan *scan = (struct mem_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void mem_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct mem_scan *scan = (struct mem_scan *)extra;
if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "memory")) {
scan->memory = 1;
} else if (!strcmp(prop->name, "reg")) {
scan->reg_value = prop->value;
scan->reg_len = prop->len;
}
}
static void mem_done(const struct fdt_scan_node *node, void *extra)
{
struct mem_scan *scan = (struct mem_scan *)extra;
const uint32_t *value = scan->reg_value;
const uint32_t *end = value + scan->reg_len/4;
uintptr_t self = (uintptr_t)mem_done;
if (!scan->memory) return;
assert (scan->reg_value && scan->reg_len % 4 == 0);
while (end - value > 0) {
uint64_t base, size;
value = fdt_get_address(node->parent, value, &base);
value = fdt_get_size (node->parent, value, &size);
if (base <= self && self <= base + size) { mem_size = size; }
}
assert (end == value);
}
void query_mem(uintptr_t fdt)
{
struct fdt_cb cb;
struct mem_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = mem_open;
cb.prop = mem_prop;
cb.done = mem_done;
cb.extra = &scan;
mem_size = 0;
fdt_scan(fdt, &cb);
assert (mem_size > 0);
}
void _putc(char ch) {
uart_send(ch);
}
static void puts(const char *s) {
for (const char *p = s; *p; p ++) {
_putc(*p);
}
}
void _halt(int code) {
puts("Exited (");
if (code == 0) _putc('0');
else {
char buf[10], *p = buf + 9;
for (*p = 0; code; code /= 10) {
*(-- p) = '0' + code % 10;
}
puts(p);
}
puts(").\n");
while (1);
}
void _trm_init() {
uart_init(fdt);
query_mem(fdt);
_heap.end = (void *)0x80000000 + mem_size;
int ret = main();
_halt(ret);
}

View File

@ -0,0 +1,113 @@
#include <klib.h>
#include "fdt.h"
volatile uint8_t* uart_base_ptr;
#define UART_RX_FIFO_REG 0
#define UART_TX_FIFO_REG 0x4
#define UART_STAT_REG 0x8
#define UART_CTRL_REG 0xc
void uart_send(uint8_t data) {
// wait until THR empty
while((*(uart_base_ptr + UART_STAT_REG) & 0x08));
*(uart_base_ptr + UART_TX_FIFO_REG) = data;
}
void uart_send_string(const char *str) {
while(*str != 0) {
uart_send(*(str++));
}
}
void uart_send_buf(const char *buf, const int32_t len) {
int32_t i;
for(i=0; i<len; i++) {
uart_send(buf[i]);
}
}
int uart_recv() {
// check whether RBR has data
if(! (*(uart_base_ptr + UART_STAT_REG) & 0x01u)) {
return -1;
}
return *(uart_base_ptr + UART_RX_FIFO_REG);
}
// IRQ triggered read
uint8_t uart_read_irq() {
return *(uart_base_ptr + UART_RX_FIFO_REG);
}
// check uart IRQ for read
uint8_t uart_check_read_irq() {
return (*(uart_base_ptr + UART_STAT_REG) & 0x01u);
}
// enable uart read IRQ
void uart_enable_read_irq() {
*(uart_base_ptr + UART_CTRL_REG) = 0x0010u;
}
// disable uart read IRQ
void uart_disable_read_irq() {
*(uart_base_ptr + UART_CTRL_REG) = 0x0000u;
}
struct uart_scan
{
int compat;
uint64_t reg;
};
static void uart_open(const struct fdt_scan_node *node, void *extra)
{
struct uart_scan *scan = (struct uart_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void uart_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct uart_scan *scan = (struct uart_scan *)extra;
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "sifive,uart0")) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
}
}
static void uart_done(const struct fdt_scan_node *node, void *extra)
{
struct uart_scan *scan = (struct uart_scan *)extra;
if (!scan->compat || !scan->reg || uart_base_ptr) return;
// Enable Rx/Tx channels
uart_base_ptr = (void*)scan->reg;
}
void uart_init(uintptr_t fdt)
{
struct fdt_cb cb;
struct uart_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = uart_open;
cb.prop = uart_prop;
cb.done = uart_done;
cb.extra = &scan;
fdt_scan(fdt, &cb);
if(!uart_base_ptr) {
//uart_base_ptr = (void *)0x60000000;
return;
}
/*
uart_base_ptr += read_const_csr(mhartid) * 0x10000;
*/
// reset the receive FIFO and transmit FIFO
*(uart_base_ptr + UART_CTRL_REG) = 0x3;
}