Browse Source

Merge pull request #107 from michaeljclark/fdt-firmware-only

RISC-V: Support separate firmware and kernel payload
pull/108/head
Palmer Dabbelt 8 years ago
committed by GitHub
parent
commit
10bf403ba8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      bbl/bbl.ac
  2. 16
      bbl/bbl.c
  3. 8
      bbl/payload.S
  4. 3
      config.h.in
  5. 15
      configure
  6. 10
      dummy_payload/dummy_entry.S
  7. 57
      machine/fdt.c
  8. 5
      machine/fdt.h
  9. 3
      machine/minit.c

9
bbl/bbl.ac

@ -4,8 +4,13 @@ AS_IF([test "x$enable_logo" == "xyes"], [
])
AC_ARG_WITH([payload], AS_HELP_STRING([--with-payload], [Set ELF payload for bbl]),
[AC_SUBST([BBL_PAYLOAD], $with_payload, [Kernel payload for bbl])],
[AC_SUBST([BBL_PAYLOAD], [dummy_payload], [Kernel payload for bbl])])
[
AC_SUBST([BBL_PAYLOAD], $with_payload, [Kernel payload for bbl])
AC_DEFINE(RELAXED_ALIGNMENT,[0],[Use relaxed payload alignment])
], [
AC_SUBST([BBL_PAYLOAD], [dummy_payload], [Kernel payload for bbl])
AC_DEFINE(RELAXED_ALIGNMENT,[1],[Use relaxed payload alignment])
])
AC_ARG_WITH([logo], AS_HELP_STRING([--with-logo], [Specify a better logo]),
[AC_SUBST([BBL_LOGO_FILE], $with_logo, [Logo for bbl])],

16
bbl/bbl.c

@ -7,13 +7,21 @@
#include "fdt.h"
#include <string.h>
extern char _payload_start, _payload_end; /* internal payload */
static const void* entry_point;
long disabled_hart_mask;
static uintptr_t dtb_output()
{
extern char _payload_end;
uintptr_t end = (uintptr_t) &_payload_end;
/*
* Place DTB after the payload, either the internal payload or a
* preloaded external payload specified in device-tree, if present.
*
* Note: linux kernel calls __va(dtb) to get the device-tree virtual
* address. The kernel's virtual mapping begins at its load address,
* thus mandating device-tree is in physical memory after the kernel.
*/
uintptr_t end = kernel_end ? (uintptr_t)kernel_end : (uintptr_t)&_payload_end;
return (end + MEGAPAGE_SIZE - 1) / MEGAPAGE_SIZE * MEGAPAGE_SIZE;
}
@ -53,7 +61,6 @@ void boot_other_hart(uintptr_t unused __attribute__((unused)))
void boot_loader(uintptr_t dtb)
{
extern char _payload_start;
filter_dtb(dtb);
#ifdef PK_ENABLE_LOGO
print_logo();
@ -62,6 +69,7 @@ void boot_loader(uintptr_t dtb)
fdt_print(dtb_output());
#endif
mb();
entry_point = &_payload_start;
/* Use optional FDT preloaded external payload if present */
entry_point = kernel_start ? kernel_start : &_payload_start;
boot_other_hart(0);
}

8
bbl/payload.S

@ -1,7 +1,15 @@
#include "config.h"
#include "encoding.h"
.section ".payload","a",@progbits
#if RELAXED_ALIGNMENT
/* align payload minimally */
.align 3
#else
/* align payload to megapage */
.align RISCV_PGSHIFT + RISCV_PGLEVEL_BITS
#endif
.globl _payload_start, _payload_end
_payload_start:

3
config.h.in

@ -42,6 +42,9 @@
/* Define if the DTS is to be displayed */
#undef PK_PRINT_DEVICE_TREE
/* Use relaxed payload alignment */
#undef RELAXED_ALIGNMENT
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef SOFTFLOAT_ENABLED

15
configure

@ -4092,7 +4092,6 @@ case "${BUILD_32BIT}" in
CFLAGS="$default_CFLAGS"
LDFLAGS=
install_subdir=$host_alias
;;
esac
@ -4251,10 +4250,20 @@ fi
# Check whether --with-payload was given.
if test "${with_payload+set}" = set; then :
withval=$with_payload; BBL_PAYLOAD=$with_payload
withval=$with_payload;
BBL_PAYLOAD=$with_payload
$as_echo "#define RELAXED_ALIGNMENT 0" >>confdefs.h
else
BBL_PAYLOAD=dummy_payload
BBL_PAYLOAD=dummy_payload
$as_echo "#define RELAXED_ALIGNMENT 1" >>confdefs.h
fi

10
dummy_payload/dummy_entry.S

@ -18,5 +18,11 @@ _start:
.data
str:
.asciz "This is bbl's dummy_payload. To boot a real kernel, reconfigure\n\
bbl with the flag --with-payload=PATH, then rebuild bbl.\n"
.asciz "This is bbl's dummy_payload. To boot a real kernel, reconfigure bbl
with the flag --with-payload=PATH, then rebuild bbl. Alternatively,
bbl can be used in firmware-only mode by adding device-tree nodes
for an external payload and use QEMU's -bios and -kernel options.\n
chosen {
riscv,kernel-start = <payload_start>;
riscv,kernel-end = <payload_end>;
};\n\n"

57
machine/fdt.c

@ -548,6 +548,63 @@ void filter_compat(uintptr_t fdt, const char *compat)
fdt_scan(fdt, &cb);
}
//////////////////////////////////////////// CHOSEN SCAN ////////////////////////////////////////
struct chosen_scan {
const struct fdt_scan_node *chosen;
void* kernel_start;
void* kernel_end;
};
static void chosen_open(const struct fdt_scan_node *node, void *extra)
{
struct chosen_scan *scan = (struct chosen_scan *)extra;
if (!strcmp(node->name, "chosen")) {
scan->chosen = node;
}
}
static int chosen_close(const struct fdt_scan_node *node, void *extra)
{
struct chosen_scan *scan = (struct chosen_scan *)extra;
if (scan->chosen && scan->chosen == node) {
scan->chosen = NULL;
}
return 0;
}
static void chosen_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct chosen_scan *scan = (struct chosen_scan *)extra;
uint64_t val;
if (!scan->chosen) return;
if (!strcmp(prop->name, "riscv,kernel-start")) {
fdt_get_address(prop->node->parent, prop->value, &val);
scan->kernel_start = (void*)val;
} else if (!strcmp(prop->name, "riscv,kernel-end")) {
fdt_get_address(prop->node->parent, prop->value, &val);
scan->kernel_end = (void*)val;
}
}
void query_chosen(uintptr_t fdt)
{
struct fdt_cb cb;
struct chosen_scan chosen;
memset(&cb, 0, sizeof(cb));
cb.open = chosen_open;
cb.close = chosen_close;
cb.prop = chosen_prop;
memset(&chosen, 0, sizeof(chosen));
cb.extra = &chosen;
fdt_scan(fdt, &cb);
kernel_start = chosen.kernel_start;
kernel_end = chosen.kernel_end;
}
//////////////////////////////////////////// HART FILTER ////////////////////////////////////////
struct hart_filter {

5
machine/fdt.h

@ -59,6 +59,7 @@ void query_mem(uintptr_t fdt);
void query_harts(uintptr_t fdt);
void query_plic(uintptr_t fdt);
void query_clint(uintptr_t fdt);
void query_chosen(uintptr_t fdt);
// Remove information from FDT
void filter_harts(uintptr_t fdt, long *disabled_hart_mask);
@ -68,6 +69,10 @@ void filter_compat(uintptr_t fdt, const char *compat);
// The hartids of available harts
extern uint64_t hart_mask;
// Optional FDT preloaded external payload
extern void* kernel_start;
extern void* kernel_end;
#ifdef PK_PRINT_DEVICE_TREE
// Prints the device tree to the console as a DTS
void fdt_print(uintptr_t fdt);

3
machine/minit.c

@ -16,6 +16,8 @@ uintptr_t mem_size;
volatile uint64_t* mtime;
volatile uint32_t* plic_priorities;
size_t plic_ndevs;
void* kernel_start;
void* kernel_end;
static void mstatus_init()
{
@ -162,6 +164,7 @@ void init_first_hart(uintptr_t hartid, uintptr_t dtb)
query_harts(dtb);
query_clint(dtb);
query_plic(dtb);
query_chosen(dtb);
wake_harts();

Loading…
Cancel
Save