diff --git a/.gitignore b/.gitignore index 647c8dec..2bcecbb5 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ build/linux-x86-softfp/ build/riscv32/ build/sail_cSim/ build/sha1sum-* +build/bin2c +build/minimal.dtb *.a *.o *.o.d @@ -29,3 +31,4 @@ tests/arch-test-target/sail_cSim/riscv_sim_RV32 tests/scimark2/ __pycache__/ src/rv32_jit.c +src/minimal_dtb.h diff --git a/.gitmodules b/.gitmodules index 24acaf30..f9ee9a19 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,3 +31,7 @@ path = tests/quake url = https://github.com/sysprog21/quake-embedded shallow = true +[submodule "src/dtc"] + path = src/dtc + url = https://git.kernel.org/pub/scm/utils/dtc/dtc.git + shallow = true diff --git a/Makefile b/Makefile index 799c9e7e..9669b0c4 100644 --- a/Makefile +++ b/Makefile @@ -241,7 +241,7 @@ include mk/artifact.mk include mk/wasm.mk include mk/system.mk -all: config $(BUILD_DTB) $(BIN) +all: config $(BUILD_DTB) $(BUILD_DTB2C) $(BIN) OBJS := \ map.o \ @@ -269,6 +269,7 @@ $(OBJS): $(GDBSTUB_LIB) endif $(OUT)/%.o: src/%.c $(deps_emcc) + $(Q)mkdir -p $(shell dirname $@) $(VECHO) " CC\t$@\n" $(Q)$(CC) -o $@ $(CFLAGS) $(CFLAGS_emcc) -c -MMD -MF $@.d $< @@ -369,7 +370,7 @@ endif endif clean: - $(RM) $(BIN) $(OBJS) $(DEV_OBJS) $(BUILD_DTB) $(HIST_BIN) $(HIST_OBJS) $(deps) $(WEB_FILES) $(CACHE_OUT) src/rv32_jit.c + $(RM) $(BIN) $(OBJS) $(DEV_OBJS) $(BUILD_DTB) $(BUILD_DTB2C) $(HIST_BIN) $(HIST_OBJS) $(deps) $(WEB_FILES) $(CACHE_OUT) src/rv32_jit.c distclean: clean -$(RM) $(DOOM_DATA) $(QUAKE_DATA) $(BUILDROOT_DATA) $(LINUX_DATA) $(RM) -r $(OUT)/linux-image diff --git a/README.md b/README.md index 9d66a5c8..1eb08b28 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ $ make ENABLE_SYSTEM=1 system Build using run using specified images: ```shell $ make ENABLE_SYSTEM=1 -$ build/rv32emu -k -i -b +$ build/rv32emu -k -i ``` #### Build Linux image diff --git a/mk/system.mk b/mk/system.mk index 4f696064..8df44823 100644 --- a/mk/system.mk +++ b/mk/system.mk @@ -1,13 +1,24 @@ # Peripherals for system emulation ifeq ($(call has, SYSTEM), 1) +CFLAGS += -Isrc/dtc/libfdt +LIBFDT_HACK := $(shell git submodule update --init src/dtc) + DEV_SRC := src/devices DTC ?= dtc -$(OUT)/minimal.dtb: $(DEV_SRC)/minimal.dts +BUILD_DTB := $(OUT)/minimal.dtb +$(BUILD_DTB): $(DEV_SRC)/minimal.dts $(VECHO) " DTC\t$@\n" $(Q)$(DTC) $^ -o $@ -BUILD_DTB := $(OUT)/minimal.dtb + +BIN_TO_C := $(OUT)/bin2c +$(BIN_TO_C): tools/bin2c.c + $(Q)$(CC) -Wall -o $@ $^ + +BUILD_DTB2C := src/minimal_dtb.h +$(BUILD_DTB2C): $(BIN_TO_C) $(BUILD_DTB) + $(BIN_TO_C) $(BUILD_DTB) > $(BUILD_DTB2C) $(DEV_OUT)/%.o: $(DEV_SRC)/%.c $(deps_emcc) $(Q)mkdir -p $(DEV_OUT) @@ -17,11 +28,12 @@ DEV_OBJS := $(patsubst $(DEV_SRC)/%.c, $(DEV_OUT)/%.o, $(wildcard $(DEV_SRC)/*.c deps := $(DEV_OBJS:%.o=%.o.d) OBJS_EXT += system.o +OBJS_EXT += dtc/libfdt/fdt.o dtc/libfdt/fdt_ro.o dtc/libfdt/fdt_rw.o # system target execution by using default dependencies LINUX_IMAGE_DIR := linux-image -system_action := ($(BIN) -k $(OUT)/$(LINUX_IMAGE_DIR)/Image -i $(OUT)/$(LINUX_IMAGE_DIR)/rootfs.cpio -b $(OUT)/minimal.dtb) -system_deps += artifact $(BUILD_DTB) $(BIN) +system_action := ($(BIN) -k $(OUT)/$(LINUX_IMAGE_DIR)/Image -i $(OUT)/$(LINUX_IMAGE_DIR)/rootfs.cpio) +system_deps += artifact $(BUILD_DTB) $(BUILD_DTB2C) $(BIN) system: $(system_deps) $(system_action) diff --git a/src/dtc b/src/dtc new file mode 160000 index 00000000..18f4f305 --- /dev/null +++ b/src/dtc @@ -0,0 +1 @@ +Subproject commit 18f4f305fdd7e14c8941658a29c7b85c27d41de4 diff --git a/src/main.c b/src/main.c index bf1c5fbb..80d3d5ee 100644 --- a/src/main.c +++ b/src/main.c @@ -55,7 +55,7 @@ static char *prof_out_file; /* Linux kernel data */ static char *opt_kernel_img; static char *opt_rootfs_img; -static char *opt_dtb; +static char *opt_bootargs; #endif static void print_usage(const char *filename) @@ -73,7 +73,7 @@ static void print_usage(const char *filename) #if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER) " -k : use as kernel image\n" " -i : use as rootfs\n" - " -b : use as device tree blob\n" + " -b : use customized for the kernel\n" #endif " -d [filename]: dump registers as JSON to the " "given file or `-` (STDOUT)\n" @@ -115,7 +115,7 @@ static bool parse_args(int argc, char **args) emu_argc++; break; case 'b': - opt_dtb = optarg; + opt_bootargs = optarg; emu_argc++; break; #endif @@ -263,7 +263,7 @@ int main(int argc, char **args) #if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER) attr.data.system.kernel = opt_kernel_img; attr.data.system.initrd = opt_rootfs_img; - attr.data.system.dtb = opt_dtb; + attr.data.system.bootargs = opt_bootargs; #else attr.data.user.elf_program = opt_prog_name; #endif diff --git a/src/riscv.c b/src/riscv.c index 1dc05b0c..fdc63b3f 100644 --- a/src/riscv.c +++ b/src/riscv.c @@ -14,6 +14,7 @@ #if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER) #include +#include "dtc/libfdt/libfdt.h" #endif #if !defined(_WIN32) && !defined(_WIN64) @@ -259,6 +260,64 @@ static void map_file(char **ram_loc, const char *name) exit(EXIT_FAILURE); } +#define ALIGN_FDT(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1)) +static char *realloc_property(char *fdt, + int nodeoffset, + const char *name, + int newlen) +{ + int delta = 0; + int oldlen = 0; + + if (!fdt_get_property(fdt, nodeoffset, name, &oldlen)) + /* strings + property header */ + delta = sizeof(struct fdt_property) + strlen(name) + 1; + + if (newlen > oldlen) + /* actual value in off_struct */ + delta += ALIGN_FDT(newlen) - ALIGN_FDT(oldlen); + + int new_sz = fdt_totalsize(fdt) + delta; + /* Assume the pre-allocated RAM is enough here, so we + * don't realloc any memory for fdt */ + fdt_open_into(fdt, fdt, new_sz); + return fdt; +} + +static void load_dtb(char **ram_loc, char *bootargs) +{ +#include "minimal_dtb.h" + char *blob = *ram_loc; + char *buf; + size_t len; + int node, err; + int totalsize; + + memcpy(blob, minimal, sizeof(minimal)); + + if (bootargs) { + node = fdt_path_offset(blob, "/chosen"); + assert(node > 0); + + len = strlen(bootargs) + 1; + buf = malloc(len); + assert(buf); + memcpy(buf, bootargs, len - 1); + buf[len] = 0; + err = fdt_setprop(blob, node, "bootargs", buf, len + 1); + if (err == -FDT_ERR_NOSPACE) { + blob = realloc_property(blob, node, "bootargs", len); + err = fdt_setprop(blob, node, "bootargs", buf, len); + } + free(buf); + assert(!err); + } + + totalsize = fdt_totalsize(blob); + *ram_loc += totalsize; + return; +} + /* * The control mode flag for keyboard. * @@ -294,6 +353,7 @@ static void capture_keyboard_input() term.c_lflag &= ~TERMIOS_C_CFLAG; tcsetattr(0, TCSANOW, &term); } + #endif /* @@ -409,7 +469,7 @@ riscv_t *rv_create(riscv_user_t rv_attr) uint32_t dtb_addr = attr->mem->mem_size - (1 * 1024 * 1024); ram_loc = ((char *) attr->mem->mem_base) + dtb_addr; - map_file(&ram_loc, attr->data.system.dtb); + load_dtb(&ram_loc, attr->data.system.bootargs); /* * Load optional initrd image at last 8 MiB before the dtb region to * prevent kernel from overwritting it @@ -517,8 +577,7 @@ void rv_run(riscv_t *rv) vm_attr_t *attr = PRIV(rv); assert(attr && #if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER) - attr->data.system.kernel && attr->data.system.initrd && - attr->data.system.dtb + attr->data.system.kernel && attr->data.system.initrd #else attr->data.user.elf_program #endif diff --git a/src/riscv.h b/src/riscv.h index 500ade3a..1ed7ba65 100644 --- a/src/riscv.h +++ b/src/riscv.h @@ -551,7 +551,7 @@ typedef struct { typedef struct { char *kernel; char *initrd; - char *dtb; + char *bootargs; } vm_system_t; #endif /* RV32_HAS(SYSTEM) */ diff --git a/tools/bin2c.c b/tools/bin2c.c new file mode 100644 index 00000000..8954e10b --- /dev/null +++ b/tools/bin2c.c @@ -0,0 +1,161 @@ +/* + * bin_to_c - convert binary data into c-compatible data tables + * Written by Larry Bank + * Copyright (c) 2009 BitBank Software, Inc. + * + * The MIT License (MIT) + * + * Copyright (c) 2015 bitbank2 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +FILE *ihandle; +void MakeC(unsigned char *, int, int); +void GetLeafName(char *fname, char *leaf); +void FixName(char *name); + +int main(int argc, char *argv[]) +{ + int iSize, iData; + unsigned char *p; + char szLeaf[256]; + + if (argc != 2) { + printf("bin_to_c Copyright (c) 2013 BitBank Software, Inc.\n"); + printf("Usage: bin_to_c \n"); + printf("output is written to stdout\n"); + return 0; // no filename passed + } + ihandle = fopen(argv[1], "rb"); // open input file + if (ihandle == NULL) { + printf("Unable to open file: %s\n", argv[1]); + return -1; // bad filename passed + } + + fseek(ihandle, 0L, SEEK_END); // get the file size + iSize = (int) ftell(ihandle); + fseek(ihandle, 0, SEEK_SET); + p = (unsigned char *) malloc(0x10000); // allocate 64k to play with + GetLeafName(argv[1], szLeaf); + printf("//\n// %s\n//\n", szLeaf); // comment header with filename + FixName(szLeaf); // remove unusable characters + printf("const uint8_t %s[] = {", szLeaf); // start of data array + while (iSize) { + iData = fread(p, 1, 0x10000, ihandle); // try to read 64k + MakeC(p, iData, iSize == iData); // create the output data + iSize -= iData; + } + free(p); + fclose(ihandle); + printf("};\n"); // final closing brace + return 0; +} /* main() */ +/* + * Generate C hex characters from each byte of file data + */ +void MakeC(unsigned char *p, int iLen, int bLast) +{ + int i, j, iCount; + char szTemp[256], szOut[256]; + + iCount = 0; + for (i = 0; i < iLen >> 4; i++) // do lines of 16 bytes + { + strcpy(szOut, "\t"); + for (j = 0; j < 16; j++) { + if (iCount == iLen - 1 && bLast) // last one, skip the comma + sprintf(szTemp, "0x%02x", p[(i * 16) + j]); + else + sprintf(szTemp, "0x%02x,", p[(i * 16) + j]); + strcat(szOut, szTemp); + iCount++; + } + if (!bLast || iCount != iLen) + strcat(szOut, "\n"); + printf("%s", szOut); + } + p += (iLen & 0xfff0); // point to last section + if (iLen & 0xf) // any remaining characters? + { + strcpy(szOut, "\t"); + for (j = 0; j < (iLen & 0xf); j++) { + if (iCount == iLen - 1 && bLast) + sprintf(szTemp, "0x%02x", p[j]); + else + sprintf(szTemp, "0x%02x,", p[j]); + strcat(szOut, szTemp); + iCount++; + } + if (!bLast) + strcat(szOut, "\n"); + printf("%s", szOut); + } +} /* MakeC() */ +/* + * Make sure the name can be used in C/C++ as a variable + * replace invalid characters and make sure it starts with a letter + */ +void FixName(char *name) +{ + char c, *d, *s, szTemp[256]; + int i, iLen; + + iLen = strlen(name); + d = szTemp; + s = name; + if (s[0] >= '0' && s[0] <= '9') // starts with a digit + *d++ = '_'; // Insert an underscore + for (i = 0; i < iLen; i++) { + c = *s++; + // these characters can't be in a variable name + if (c < ' ' || (c >= '!' && c < '0') || (c > 'Z' && c < 'a')) + c = '_'; // convert all to an underscore + *d++ = c; + } + *d++ = 0; + strcpy(name, szTemp); +} /* FixName() */ +/* + * Trim off the leaf name from a fully + * formed file pathname + */ +void GetLeafName(char *fname, char *leaf) +{ + int i, iLen; + + iLen = strlen(fname); + for (i = iLen - 1; i >= 0; i--) { + if (fname[i] == '\\' || fname[i] == '/') // Windows or Linux + break; + } + strcpy(leaf, &fname[i + 1]); + // remove the filename extension + iLen = strlen(leaf); + for (i = iLen - 1; i >= 0; i--) { + if (leaf[i] == '.') { + leaf[i] = 0; + break; + } + } +} /* GetLeafName() */