Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
libspikedevices.so
*.log
*.bin
*.debug
*.out
*.elf
.vscode
157 changes: 134 additions & 23 deletions src/iceblk.cc
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
#include <cstdint>
#include <cstdio>
#include <stdlib.h>
#include <cstdlib>
#include <sys/time.h>
#include <sstream>
#include <stddef.h>
#include <cstddef>
#include <vector>
#include <map>
#include <algorithm>
#include <cctype>
#include <cerrno>
#include <cstring>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include "iceblk.h"

#define BLKDEV_ADDR 0
Expand Down Expand Up @@ -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<std::string, std::string>(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<char>(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<uint64_t*>(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<uint64_t>(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<uint64_t*>(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<uint64_t>(img_sz) + BLKDEV_SECTOR_SIZE - 1) / BLKDEV_SECTOR_SIZE;
blockdevice_size = sectors_in_img * BLKDEV_SECTOR_SIZE;
blockdevice = static_cast<uint64_t*>(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<uint8_t*>(blockdevice), 1, static_cast<size_t>(img_sz), fp);
if (read_bytes != static_cast<size_t>(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<uint64_t>(img_sz)) {
std::memset(reinterpret_cast<uint8_t*>(blockdevice) + img_sz, 0,
blockdevice_size - static_cast<uint64_t>(img_sz));
}
std::fclose(fp);
}
}

for (int i = 0; i < trackers; i++) {
Expand All @@ -81,7 +180,19 @@ iceblk_t::iceblk_t(
}

iceblk_t::~iceblk_t() {
free(blockdevice);
if (persistent_modification) {
void* mapping = reinterpret_cast<void*>(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() {
Expand Down Expand Up @@ -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<uint64_t>(req_addr + sidx * BLKDEV_SECTOR_SIZE + i);
write_blockdevice_u64(data, sidx, i);
write_blockdevice_u64(data, sidx + req_offset, i);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/iceblk.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/sifive_uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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:
Expand Down
86 changes: 86 additions & 0 deletions src/trace_encoder_ctrl.cc
Original file line number Diff line number Diff line change
@@ -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<br_mode_t>(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<ctx_mode_t>(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<std::string> 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_t*>(sim)->get_core(0)->trace_encoder));
} else {
return nullptr;
}
}

std::string trace_encoder_ctrl_generateDTS(const sim_t* sim, const std::vector<std::string>& 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);
30 changes: 30 additions & 0 deletions src/trace_encoder_ctrl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef _TRACE_ENCODER_CTRL_H
#define _TRACE_ENCODER_CTRL_H

#include <riscv/abstract_device.h>
#include <riscv/abstract_trace_encoder.h>
#include <riscv/dts.h>
#include <riscv/sim.h>
#include <fdt/libfdt.h>

#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
Loading