12 changed files with 804 additions and 558 deletions
@ -0,0 +1,95 @@ |
|||
#include "devicetree.h" |
|||
#include "encoding.h" |
|||
#include "pk.h" |
|||
#include "mtrap.h" |
|||
#include <arpa/inet.h> |
|||
#include <stdbool.h> |
|||
|
|||
static uintptr_t max_hart_id; |
|||
|
|||
static uint64_t fdt_read_uint64(uint32_t* addr) { |
|||
return ((uint64_t)ntohl(addr[0]) << 32) | ntohl(addr[1]); |
|||
} |
|||
|
|||
static void fdt_handle_cpu(const char* isa, uint32_t* reg_addr, uint32_t reg_len) |
|||
{ |
|||
int xlen = sizeof(long) * 8; |
|||
kassert(reg_len == 8); |
|||
kassert(isa && isa[0]=='r' && isa[1]=='v' && isa[2]=='0'+(xlen/10)); |
|||
|
|||
uintptr_t* base_addr = (uintptr_t*)(uintptr_t)fdt_read_uint64(reg_addr); |
|||
debug_printk("at %p, ", base_addr); |
|||
uintptr_t hart_id = *(uintptr_t*)(base_addr + CSR_MHARTID); |
|||
debug_printk("found hart %ld\n", hart_id); |
|||
hls_init(hart_id, base_addr); |
|||
num_harts++; |
|||
max_hart_id = MAX(max_hart_id, hart_id); |
|||
} |
|||
|
|||
static void fdt_handle_mem(uint32_t* reg_addr, uint32_t reg_len) |
|||
{ |
|||
kassert(reg_len == 16); |
|||
uint64_t base = fdt_read_uint64(reg_addr); |
|||
uint64_t size = fdt_read_uint64(reg_addr+2); |
|||
debug_printk("at %p, found %d MiB of memory\n", base, (int)(size >> 20)); |
|||
kassert(base == 0); |
|||
mem_size = size; |
|||
} |
|||
|
|||
// This code makes the following assumptions about FDTs:
|
|||
// - They are trusted and don't need to be sanitized
|
|||
// - All addresses and sizes are 64 bits (we don't parse #address-cells etc)
|
|||
|
|||
static uint32_t* parse_node(uint32_t* token, char* strings) |
|||
{ |
|||
const char* nodename = (const char*)token, *s, *dev_type = 0, *isa = 0; |
|||
uint32_t reg_len = 0, *reg_addr = 0; |
|||
token = (uint32_t*)nodename + strlen(nodename)/4+1; |
|||
|
|||
while (1) switch (ntohl(*token)) { |
|||
case FDT_PROP: { |
|||
token++; |
|||
uint32_t len = ntohl(*token++); |
|||
const char* name = strings + ntohl(*token++); |
|||
if (strcmp(name, "device_type") == 0) { |
|||
dev_type = (char*)token; |
|||
} else if (strcmp(name, "isa") == 0) { |
|||
isa = (char*)token; |
|||
} else if (strcmp(name, "reg") == 0) { |
|||
reg_len = len; |
|||
reg_addr = token; |
|||
} |
|||
token += (len+3)/4; |
|||
continue; |
|||
} |
|||
case FDT_BEGIN_NODE: |
|||
token = parse_node(token+1, strings); |
|||
continue; |
|||
case FDT_END_NODE: |
|||
goto out; |
|||
case FDT_NOP: |
|||
continue; |
|||
default: |
|||
kassert(0); |
|||
} |
|||
|
|||
out: |
|||
if (dev_type && strcmp(dev_type, "cpu") == 0) |
|||
fdt_handle_cpu(isa, reg_addr, reg_len); |
|||
else if (dev_type && strcmp(dev_type, "memory") == 0) |
|||
fdt_handle_mem(reg_addr, reg_len); |
|||
|
|||
return token+1; |
|||
} |
|||
|
|||
void parse_device_tree() |
|||
{ |
|||
struct fdt_header* hdr = (struct fdt_header*)read_csr(miobase); |
|||
debug_printk("reading device tree at %p\n", hdr); |
|||
kassert(ntohl(hdr->magic) == FDT_MAGIC); |
|||
char* strings = (char*)hdr + ntohl(hdr->off_dt_strings); |
|||
uint32_t* root = (uint32_t*)((char*)hdr + ntohl(hdr->off_dt_struct)); |
|||
while (ntohl(*root++) != FDT_BEGIN_NODE); |
|||
parse_node(root, strings); |
|||
kassert(max_hart_id == num_harts-1); |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
// See LICENSE for license details.
|
|||
|
|||
#ifndef _PK_DEVICETREE_H |
|||
#define _PK_DEVICETREE_H |
|||
|
|||
#include <stdint.h> |
|||
|
|||
#define FDT_MAGIC 0xd00dfeedU |
|||
#define FDT_VERSION 17 |
|||
#define FDT_COMP_VERSION 16 |
|||
#define FDT_BEGIN_NODE 1 |
|||
#define FDT_END_NODE 2 |
|||
#define FDT_PROP 3 |
|||
#define FDT_NOP 4 |
|||
#define FDT_END 9 |
|||
|
|||
struct fdt_header { |
|||
uint32_t magic; |
|||
uint32_t totalsize; |
|||
uint32_t off_dt_struct; |
|||
uint32_t off_dt_strings; |
|||
uint32_t off_rsvmap; |
|||
uint32_t version; |
|||
uint32_t last_comp_version; |
|||
uint32_t boot_cpuid_phys; |
|||
uint32_t size_dt_strings; |
|||
uint32_t size_dt_struct; |
|||
}; |
|||
|
|||
struct fdt_reserve_entry { |
|||
uint64_t address; |
|||
uint64_t size; |
|||
}; |
|||
|
|||
void parse_device_tree(); |
|||
|
|||
#endif |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue