diff --git a/.gitignore b/.gitignore index 4ef5e43..49f3d50 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,7 @@ libspikedevices.so +*.log +*.bin +*.debug +*.out +*.elf +.vscode diff --git a/src/iceblk.cc b/src/iceblk.cc index b1eb3f3..8b9bafc 100644 --- a/src/iceblk.cc +++ b/src/iceblk.cc @@ -1,11 +1,18 @@ #include #include -#include +#include #include #include -#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include #include "iceblk.h" #define BLKDEV_ADDR 0 @@ -46,33 +53,125 @@ iceblk_t::iceblk_t( for (auto arg : sargs) { size_t eq_idx = arg.find('='); if (eq_idx != std::string::npos) { - argmap.insert(std::pair(arg.substr(0, eq_idx), arg.substr(eq_idx+1))); + argmap.emplace(arg.substr(0, eq_idx), arg.substr(eq_idx + 1)); + } else { + argmap.emplace(arg, ""); } } + auto persistent = argmap.find("iceblk-persistent-modification"); + if (persistent != argmap.end()) { + std::string val = persistent->second; + std::transform(val.begin(), val.end(), val.begin(), [](unsigned char c) { + return static_cast(std::tolower(c)); + }); + persistent_modification = val.empty() || val == "1" || val == "true" || + val == "yes" || val == "on"; + fprintf(stderr, "ICEBLK: Persistent modification is %s\n", + persistent_modification ? "enabled" : "disabled"); + } - auto it = argmap.find("img"); - if (it == argmap.end()) { - blockdevice_size = (sizeof(uint64_t)/sizeof(uint8_t)) * BLKDEV_SECTOR_SIZE * 8; - blockdevice = (uint64_t*)malloc(sizeof(uint64_t) * blockdevice_size); - } else { - std::string img_path = it->second; - FILE* fp = fopen(img_path.c_str(), "r"); - if (fp == nullptr) { - printf("Error opening file %s\n", img_path); - exit(1); + auto img_it = argmap.find("img"); + if (persistent_modification && img_it == argmap.end()) { + fprintf(stderr, "ICEBLK: Persistent modification requested without image; disabling persistence.\n"); + persistent_modification = false; + } + + if (img_it == argmap.end()) { + blockdevice_size = BLKDEV_SECTOR_SIZE * 8; + blockdevice = static_cast(std::malloc(blockdevice_size)); + if (!blockdevice) { + perror("iceblk malloc"); + std::exit(1); } + std::memset(blockdevice, 0, blockdevice_size); + } else { + const std::string& img_path = img_it->second; + if (persistent_modification) { + fprintf(stderr, "ICEBLK: Persistent modification enabled; using mmap on %s\n", img_path.c_str()); + int fd = ::open(img_path.c_str(), O_RDWR); + if (fd == -1) { + perror("iceblk open"); + std::exit(1); + } + + off_t img_sz = ::lseek(fd, 0, SEEK_END); + if (img_sz == -1) { + perror("iceblk lseek"); + ::close(fd); + std::exit(1); + } + + if (img_sz == 0) { + img_sz = BLKDEV_SECTOR_SIZE * 8; + if (::ftruncate(fd, img_sz) != 0) { + perror("iceblk ftruncate"); + ::close(fd); + std::exit(1); + } + } + + if (::lseek(fd, 0, SEEK_SET) == -1) { + perror("iceblk lseek"); + ::close(fd); + std::exit(1); + } + + blockdevice_size = static_cast(img_sz); + void* mapped = ::mmap(nullptr, blockdevice_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mapped == MAP_FAILED) { + perror("iceblk mmap"); + ::close(fd); + std::exit(1); + } + blockdevice = static_cast(mapped); + ::close(fd); + } else { + FILE* fp = std::fopen(img_path.c_str(), "rb"); + if (fp == nullptr) { + std::fprintf(stderr, "Error opening file %s\n", img_path.c_str()); + std::exit(1); + } - fseek(fp, 0, SEEK_END); - uint64_t img_sz = ftell(fp); - fseek(fp, 0, SEEK_SET); + if (std::fseek(fp, 0, SEEK_END) != 0) { + std::fprintf(stderr, "ICEBLK: Failed to seek %s\n", img_path.c_str()); + std::fclose(fp); + std::exit(1); + } + long img_sz = std::ftell(fp); + if (img_sz < 0) { + std::fprintf(stderr, "ICEBLK: Failed to determine size of %s\n", img_path.c_str()); + std::fclose(fp); + std::exit(1); + } + if (std::fseek(fp, 0, SEEK_SET) != 0) { + std::fprintf(stderr, "ICEBLK: Failed to rewind %s\n", img_path.c_str()); + std::fclose(fp); + std::exit(1); + } - uint64_t sectors_in_img = (img_sz + BLKDEV_SECTOR_SIZE) / BLKDEV_SECTOR_SIZE; - blockdevice_size = sectors_in_img * BLKDEV_SECTOR_SIZE; - blockdevice = (uint64_t*)malloc(blockdevice_size); + uint64_t sectors_in_img = (static_cast(img_sz) + BLKDEV_SECTOR_SIZE - 1) / BLKDEV_SECTOR_SIZE; + blockdevice_size = sectors_in_img * BLKDEV_SECTOR_SIZE; + blockdevice = static_cast(std::malloc(blockdevice_size)); + if (!blockdevice) { + perror("iceblk malloc"); + std::fclose(fp); + std::exit(1); + } - fread((void*)blockdevice, sizeof(uint64_t), img_sz/sizeof(uint64_t), fp); - fclose(fp); + size_t read_bytes = std::fread(reinterpret_cast(blockdevice), 1, static_cast(img_sz), fp); + if (read_bytes != static_cast(img_sz)) { + std::fprintf(stderr, "ICEBLK: Short read when loading %s\n", img_path.c_str()); + std::fclose(fp); + std::free(blockdevice); + std::exit(1); + } + if (blockdevice_size > static_cast(img_sz)) { + std::memset(reinterpret_cast(blockdevice) + img_sz, 0, + blockdevice_size - static_cast(img_sz)); + } + std::fclose(fp); + } } for (int i = 0; i < trackers; i++) { @@ -81,7 +180,19 @@ iceblk_t::iceblk_t( } iceblk_t::~iceblk_t() { - free(blockdevice); + if (persistent_modification) { + void* mapping = reinterpret_cast(blockdevice); + if (mapping && mapping != MAP_FAILED) { + if (::msync(mapping, blockdevice_size, MS_SYNC) != 0) { + perror("iceblk msync"); + } + if (::munmap(mapping, blockdevice_size) != 0) { + perror("iceblk munmap"); + } + } + } else if (blockdevice) { + std::free(blockdevice); + } } void iceblk_t::handle_request() { @@ -117,7 +228,7 @@ void iceblk_t::handle_write_request() { for (reg_t sidx = 0; sidx < req_len; sidx++) { for (reg_t i = 0; i < BLKDEV_SECTOR_SIZE; i+= 8) { uint64_t data = simdram->load(req_addr + sidx * BLKDEV_SECTOR_SIZE + i); - write_blockdevice_u64(data, sidx, i); + write_blockdevice_u64(data, sidx + req_offset, i); } } } diff --git a/src/iceblk.h b/src/iceblk.h index 5feed21..f893cf0 100644 --- a/src/iceblk.h +++ b/src/iceblk.h @@ -29,6 +29,7 @@ class iceblk_t : public abstract_device_t { ~iceblk_t(); bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override { return BLKDEV_SIZE; } void tick(reg_t rtc_ticks) override; private: @@ -46,6 +47,8 @@ class iceblk_t : public abstract_device_t { uint64_t* blockdevice; uint64_t blockdevice_size; + bool persistent_modification = false; + const simif_t* sim; abstract_interrupt_controller_t *intctrl; uint32_t interrupt_id; diff --git a/src/sifive_uart.h b/src/sifive_uart.h index 60d047e..32936a8 100644 --- a/src/sifive_uart.h +++ b/src/sifive_uart.h @@ -21,6 +21,8 @@ #define UART_WIRE4 (0x20) #define UART_EITHER8OR9 (0x24) +#define UART_SIZE 0x100 + #define UART_GET_TXCNT(txctrl) ((txctrl >> 16) & 0x7) #define UART_GET_RXCNT(rxctrl) ((rxctrl >> 16) & 0x7) #define UART_RX_FIFO_SIZE (8) @@ -38,6 +40,7 @@ class sifive_uart_t : public abstract_device_t { bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override { return UART_SIZE; } void tick(reg_t UNUSED rtc_ticks) override; private: diff --git a/src/trace_encoder_ctrl.cc b/src/trace_encoder_ctrl.cc new file mode 100644 index 0000000..fdb9de2 --- /dev/null +++ b/src/trace_encoder_ctrl.cc @@ -0,0 +1,86 @@ +#include "trace_encoder_ctrl.h" + +trace_encoder_ctrl_t::trace_encoder_ctrl_t(abstract_trace_encoder_t* encoder) { + this->encoder = encoder; +} + +bool trace_encoder_ctrl_t::load(reg_t addr, size_t len, uint8_t* bytes) { + switch (addr) { + case TR_TE_CTRL: + bytes[0] = this->encoder->get_enable() << 1; + return true; + default: + return false; + } +} + +bool trace_encoder_ctrl_t::store(reg_t addr, size_t len, const uint8_t* bytes) { + printf("[TRACE_ENCODER_CTRL]: Storing %d bytes with value %lx to 0x%lx\n", len, bytes[0], addr); + switch (addr) { + case TR_TE_CTRL: + printf("[TRACE_ENCODER_CTRL]: Setting enable to %d\n", (bytes[0] >> 1) & 0x1); + this->encoder->set_enable((bytes[0] >> 1) & 0x1); // Set enable to the second bit + return true; + case TR_TE_SINK: + printf("[TRACE_ENCODER_CTRL]: IGNORING sink setting to %d\n", (bytes[0] >> 1) & 0x1); + return true; + case TR_TE_BR_MODE: + printf("[TRACE_ENCODER_CTRL]: Setting br_mode to %d\n", bytes[0]); + this->encoder->set_br_mode(static_cast(bytes[0])); + return true; + // case TR_TE_CTX_MODE: + // printf("[TRACE_ENCODER_CTRL]: Setting ctx_mode to %d\n", bytes[0]); + // this->encoder->set_ctx_mode(static_cast(bytes[0])); + // return true; + // case TR_TE_CTX_ASID: + // uint32_t ctx_id = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0]; + // printf("[TRACE_ENCODER_CTRL]: Setting ctx_id to %d\n", ctx_id); + // this->encoder->set_ctx_id(ctx_id); + // return true; + default: + return false; + } +} + +int trace_encoder_ctrl_parseFDT(const void *fdt, reg_t *address, + const char *compatible) { + int nodeoffset, len, rc; + const fdt32_t *reg_p; + + nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible); + if (nodeoffset < 0) + return nodeoffset; + + rc = fdt_get_node_addr_size(fdt, nodeoffset, address, NULL, "reg"); + if (rc < 0 || !address) + return -ENODEV; + + return 0; +} + +// This function parses an instance of this device from the FDT +// An FDT node for a device should encode, at minimum, the base address for the device +trace_encoder_ctrl_t* trace_encoder_ctrl_parseFromFDT(const void* fdt, const sim_t* sim, reg_t* base, std::vector sargs) { + if (trace_encoder_ctrl_parseFDT(fdt, base, "ucbbar,trace") == 0) { + printf("Found trace_encoder_ctrl at 0x%lx\n", *base); + return new trace_encoder_ctrl_t((const_cast(sim)->get_core(0)->trace_encoder)); + } else { + return nullptr; + } +} + +std::string trace_encoder_ctrl_generateDTS(const sim_t* sim, const std::vector& args) { + std::stringstream s; + reg_t base = TRACE_ENCODER_CTRL_BASE; + reg_t size = TRACE_ENCODER_CTRL_SIZE; + + s << " trace_encoder_ctrl: trace_encoder_ctrl@" << std::hex << base << " {\n" + << " compatible = \"ucbbar,trace\";\n" + << " reg = <0x" << (base >> 32) << " 0x" << (base & 0xffffffff) + << " 0x" << (size >> 32) << " 0x" << (size & 0xffffffff) << ">;\n" + << " };\n"; + + return s.str(); +} + +REGISTER_DEVICE(trace_encoder_ctrl, trace_encoder_ctrl_parseFromFDT, trace_encoder_ctrl_generateDTS); diff --git a/src/trace_encoder_ctrl.h b/src/trace_encoder_ctrl.h new file mode 100644 index 0000000..38521f2 --- /dev/null +++ b/src/trace_encoder_ctrl.h @@ -0,0 +1,30 @@ +#ifndef _TRACE_ENCODER_CTRL_H +#define _TRACE_ENCODER_CTRL_H + +#include +#include +#include +#include +#include + +#define TRACE_ENCODER_CTRL_BASE 0x3000000 +#define TRACE_ENCODER_CTRL_SIZE 0x1000 + +#define TR_TE_CTRL 0x000 +#define TR_TE_IMPL 0x004 +#define TR_TE_SINK 0x020 +#define TR_TE_BR_MODE 0x024 +#define TR_TE_CTX_MODE 0x040 +#define TR_TE_CTX_ASID 0x044 + +class trace_encoder_ctrl_t : public abstract_device_t { +public: + trace_encoder_ctrl_t(abstract_trace_encoder_t* encoder); + bool load(reg_t addr, size_t len, uint8_t* bytes) override; + bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override { return TRACE_ENCODER_CTRL_SIZE; } +private: + abstract_trace_encoder_t* encoder; +}; + +#endif diff --git a/test.dts b/test.dts deleted file mode 100644 index 36e629d..0000000 --- a/test.dts +++ /dev/null @@ -1,69 +0,0 @@ -/dts-v1/; - -/ { - #address-cells = <2>; - #size-cells = <2>; - compatible = "ucbbar,spike-bare-dev"; - model = "ucbbar,spike-bare"; - chosen { - stdout-path = &SERIAL0; - bootargs = "console=ttyS0 earlycon"; - }; - cpus { - #address-cells = <1>; - #size-cells = <0>; - timebase-frequency = <10000000>; - CPU0: cpu@0 { - device_type = "cpu"; - reg = <0>; - status = "okay"; - compatible = "riscv"; - riscv,isa = "rv64imafdc_zicntr_zihpm"; - mmu-type = "riscv,sv57"; - riscv,pmpregions = <16>; - riscv,pmpgranularity = <4>; - clock-frequency = <1000000000>; - CPU0_intc: interrupt-controller { - #address-cells = <2>; - #interrupt-cells = <1>; - interrupt-controller; - compatible = "riscv,cpu-intc"; - }; - }; - }; - memory@80000000 { - device_type = "memory"; - reg = <0x0 0x80000000 0x0 0x80000000>; - }; - soc { - #address-cells = <2>; - #size-cells = <2>; - compatible = "ucbbar,spike-bare-soc", "simple-bus"; - ranges; - clint@2000000 { - compatible = "riscv,clint0"; - interrupts-extended = <&CPU0_intc 3 &CPU0_intc 7 >; - reg = <0x0 0x2000000 0x0 0xc0000>; - }; - PLIC: plic@c000000 { - compatible = "riscv,plic0"; - #address-cells = <2>; - interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9 >; - reg = <0x0 0xc000000 0x0 0x1000000>; - riscv,ndev = <0x1f>; - riscv,max-priority = <0xf>; - #interrupt-cells = <1>; - interrupt-controller; - }; - SERIAL0: sifive-uart@10000000 { - compatible = "sifive,uart0"; - clock-frequency = <10000000>; - interrupt-parent = <&PLIC>; - interrupts = <1>; - reg = <0x0 0x10000000 0x0 0x1000>; - }; - }; - htif { - compatible = "ucb,htif0"; - }; -};