sifive / freedom-u-sdk

Freedom U Software Development Kit (FUSDK)
271 stars 123 forks source link

U-boot support? #33

Closed xfguo closed 6 years ago

xfguo commented 6 years ago

Hi Does sifive have a plan to port uboot for freedom u540 or riscv-qemu ?

AndesTech summit thier patch for their n{x}25 cpus. U-boot link

Thanks.

terpstra commented 6 years ago

We have not been working on this internally, but we'd of course be thrilled to have a more fully featured boot loader for the board. Initially the HiFive/U board will ship with the Berkeley boot loader on an SD card.

xfguo commented 6 years ago

Thanks for your reply @terpstra

Maybe I will port one when I get our hifive/u board.

BTW, how do you pass the bootargs to the kernel right now, due to vmlinux have to be attached as a payload with bbl, it seems ignore the bootcmd arguments.

terpstra commented 6 years ago

The SBI defines a0 is Hart id and a1 is a pointer to a DTB. Device tree can include boot arguments, though I've never tried using them.

michaeljclark commented 6 years ago

We have bootargs working in riscv-qemu. Below is output from the virt machine. Notice instead of -machine virt we have -machine virt,dumpdtb=virt.dtb which causes qemu to dump the flattened device tree binary to a file.

I need to bump riscv-qemu in freedom-u-sdk as the -append option might not be supported in the version of riscv-qemu in freedom-u-sdk. However I want to get freedom-u-sdk building before I make a pull request.

$ ./riscv64-softmmu/qemu-system-riscv64 -smp cpus=4 -nographic -machine virt,dumpdtb=virt.dtb -kernel qemu-images/bbl-1.10-virtio-16550a-smp -append "root=/dev/vda ro" -drive file=qemu-images/busybear.bin,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 -netdev type=tap,script=./qemu-images/ifup.macos,downscript=./qemu-images/ifdown.macos,id=net0 -device virtio-net-device,netdev=net0
$ fdtdump virt.dtb 
/ {
    #address-cells = <0x00000002>;
    #size-cells = <0x00000002>;
    compatible = "riscv-virtio";
    model = "riscv-virtio,qemu";
    chosen {
        bootargs = "root=/dev/vda ro";
        stdout-path = "/uart@10000000";
    };
    uart@10000000 {
        interrupts = <0x0000000a>;
        interrupt-parent = <0x00000005>;
        clock-frequency = <0x00384000>;
        reg = <0x00000000 0x10000000 0x00000000 0x00000100>;
        compatible = "ns16550a";
    };
...
michaeljclark commented 6 years ago

BTW @palmer-dabbelt @sorear and myself have been discussing a way to put the load address of the boot image in device tree so that we can split bbl and linux or any other kernel/boot payload (much like other systems). See PR https://github.com/riscv/riscv-qemu/pull/109

In qemu we could potentially be able to do this:

-bios bbl -kernel vmlinux -initrd initramfs

BBL is rightfully the M-mode monitor as it stays resident to handle trap and emulate. It just happens that the qemu command line for this in qemu is -bios. I'm working on a patch for bbl and qemu similarly to the -initrd patch. On other systems they tend to be separate files/images.

This could also be compatible with U-boot if the loaded image could be addressed in memory somewhere instead of embedded in bbl.

Of course more sophisticated boot loaders may be able to load the kernel image and initrd from secondary storage (vs RAM/Flash/ROM). e.g. I believe lowrisc-chip has a FAT driver in its version of bbl

michaeljclark commented 6 years ago

It would be nice that qemu follows hardware, so it will be interesting to think about how we might split bbl and linux on the hardware side.

My patch (untested) looks like this. Basically if there is "riscv,kernel-entry" in device-tree, it will jump to that address instead of to the embedded payload (which in this case would just be the default dummy payload).

diff --git a/bbl/bbl.c b/bbl/bbl.c
index 1b96a9d..7f26429 100644
--- a/bbl/bbl.c
+++ b/bbl/bbl.c
@@ -54,6 +54,7 @@ void boot_other_hart(uintptr_t unused __attribute__((unused)))
 void boot_loader(uintptr_t dtb)
 {
   extern char _payload_start;
+  entry_point = &_payload_start;
   filter_dtb(dtb);
 #ifdef PK_ENABLE_LOGO
   print_logo();
@@ -62,6 +63,8 @@ void boot_loader(uintptr_t dtb)
   fdt_print(dtb_output());
 #endif
   mb();
-  entry_point = &_payload_start;
+  if (kernel_entry) {
+    entry_point = kernel_entry;
+  }
   boot_other_hart(0);
 }
diff --git a/machine/fdt.c b/machine/fdt.c
index 061b19e..ea0c07d 100644
--- a/machine/fdt.c
+++ b/machine/fdt.c
@@ -548,6 +548,47 @@ void filter_compat(uintptr_t fdt, const char *compat)
   fdt_scan(fdt, &cb);
 }

+//////////////////////////////////////////// PAYLOAD SCAN ////////////////////////////////////////
+
+struct kernel_scan
+{
+  uint64_t reg;
+};
+
+static void kernel_open(const struct fdt_scan_node *node, void *extra)
+{
+  struct kernel_scan *scan = (struct kernel_scan *)extra;
+  memset(scan, 0, sizeof(*scan));
+}
+
+static void kernel_prop(const struct fdt_scan_prop *prop, void *extra)
+{
+  struct kernel_scan *scan = (struct kernel_scan *)extra;
+  if (!strcmp(prop->name, "riscv,kernel-entry")) {
+    fdt_get_address(prop->node->parent, prop->value, &scan->reg);
+  }
+}
+
+static void kernel_done(const struct fdt_scan_node *node, void *extra)
+{
+  struct kernel_scan *scan = (struct kernel_scan *)extra;
+  kernel_entry = (char*)scan->reg;
+}
+
+void query_kernel(uintptr_t fdt)
+{
+  struct fdt_cb cb;
+  struct kernel_scan scan;
+
+  memset(&cb, 0, sizeof(cb));
+  cb.open = kernel_open;
+  cb.prop = kernel_prop;
+  cb.done = kernel_done;
+  cb.extra = &scan;
+
+  fdt_scan(fdt, &cb);
+}
+
 //////////////////////////////////////////// HART FILTER ////////////////////////////////////////

 struct hart_filter {
diff --git a/machine/fdt.h b/machine/fdt.h
index d436778..fd9814c 100644
--- a/machine/fdt.h
+++ b/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_kernel(uintptr_t fdt);

 // Remove information from FDT
 void filter_harts(uintptr_t fdt, long *disabled_hart_mask);
@@ -68,6 +69,9 @@ void filter_compat(uintptr_t fdt, const char *compat);
 // The hartids of available harts
 extern uint64_t hart_mask;

+// The fdt kernel entry address
+extern char* kernel_entry;
+
 #ifdef PK_PRINT_DEVICE_TREE
 // Prints the device tree to the console as a DTS
 void fdt_print(uintptr_t fdt);
diff --git a/machine/minit.c b/machine/minit.c
index 47433d1..6857716 100644
--- a/machine/minit.c
+++ b/machine/minit.c
@@ -16,6 +16,7 @@ uintptr_t mem_size;
 volatile uint64_t* mtime;
 volatile uint32_t* plic_priorities;
 size_t plic_ndevs;
+char* kernel_entry;

 static void mstatus_init()
 {
@@ -154,6 +155,7 @@ void init_first_hart(uintptr_t hartid, uintptr_t dtb)
   query_harts(dtb);
   query_clint(dtb);
   query_plic(dtb);
+  query_kernel(dtb);

   wake_harts();
michaeljclark commented 6 years ago

@terpstra it would be best if qemu follows hardware i.e. freedom U FPGA... something to think about...

terpstra commented 6 years ago

The Hifive/Unleashed boot ROM loader grabs data from GPT partitions. There are mode select pins tied to DIP switches to select where to find the first stage. Roughly the ROM can find the first stage on an SD card or SPI flash. The first stage configures PLLs and DDR then looks for a second stage in GPT based on the mode select. We've picked unique guids for the first and second stage in GPT. At that point the second stage starts running in DDR with a DTB pointer and from the hardware point of view boot is complete. At the moment the second stage is just bbl+kernel. We imagine the open source community can add a fancier bootloader like uboot or grub or what not in the second stage. Note that PCIe is only brought up later by Linux so using SATA or something else would require a hefty software payload in the second stage. Fortunately there is not size restriction on the second stage.

On Feb 24, 2018 1:19 PM, "Michael Clark" notifications@github.com wrote:

@terpstra https://github.com/terpstra it would be best if qemu follows hardware i.e. freedom U FPGA... something to think about...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sifive/freedom-u-sdk/issues/33#issuecomment-368261090, or mute the thread https://github.com/notifications/unsubscribe-auth/ABDPir2o9ucnbfTgckSd37dfYggDZ4BAks5tYHzfgaJpZM4SOsYm .

michaeljclark commented 6 years ago

It sounds like it would be possible to support split the monitor ROM and the kernel without too much effort, even under the current model. This would be an incredibly sensible change for a variety of reasons.

I can do some experiments with changes to bbl in QEMU and on the VC707...

I believe lowrisc may have modified bbl to support SD card and FAT. I believe they have some BSD licensed SPI and FAT filesystem code that we could borrow (see spi.c and ff.c). I was previously running their chip on a KC705.

It seems sensible (actually necessary) to separate the bootloader from the kernel (actually monitor rom as more correct as bbl stays resident to handle M-mode trap-and-emulate and the SBI ecall interface)

michaeljclark commented 6 years ago

The main reason to make the monitor independent is so that when we recompile a kernel we don't need to recompile the monitor. It seems not so difficult if we agree on a protocol between boot loader and kernel. The current model doesn't work from a packaging perspective.

Adding ff.c would allow the fsbl to load a bbl.bin and vmlinux.bin from either SPI flash or the SDcard. Perhaps then we'd only have vmlinux or vmlinux.gz on the SDcard (if for example we add miniz, a single file replacement for zlib):

terpstra commented 6 years ago

The protocol between all stages should just be the SBI: a0 hartid a1 dtb pointer.

Bbl expects to receive this as does the kernel. Any extra information should go into the dtb.

On Feb 24, 2018 2:45 PM, "Michael Clark" notifications@github.com wrote:

The main reason to make the monitor independent is so that when we recompile a kernel we don't need to recompile the monitor. It seems not so difficult if we agree on a protocol between boot loader and kernel. The current model doesn't work from a packaging perspective.

Adding ff.c would allow the fsbl to load a bbl.bin and vmlinux.bin from either SPI flash or the SDcard. Perhaps then we'd only have vmlinux or vmlinux.gz on the SDcard (if for example we add miniz, a single file replacement for zlib):

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sifive/freedom-u-sdk/issues/33#issuecomment-368266259, or mute the thread https://github.com/notifications/unsubscribe-auth/ABDPih0_vrnlmlp_nVJsX4MLhUoHfk4gks5tYJD7gaJpZM4SOsYm .