Skip to content

Commit

Permalink
monitor: support init mem with a gz file (OpenXiangShan#7)
Browse files Browse the repository at this point in the history
This commit adds support for initializing memory with a compressed
gzip file. When CONFIG_MEM_COMPRESS is enabled, files with names
ending with ".gz" will be seen as compressed gzip files and be
decompressed before loading into memory.

Only non-zero bytes are copied into pmem, to avoid using too much
memory (by copy-on-write).
  • Loading branch information
poemonsense committed Jul 23, 2021
1 parent 81f0296 commit eed97c7
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ LDFLAGS += $(CFLAGS_BUILD)

NAME = nemu-$(ENGINE)

ifdef CONFIG_MEM_COMPRESS
LDFLAGS += -lz
endif

ifndef CONFIG_SHARE
LDFLAGS += -lreadline -ldl -pie
else
Expand Down
7 changes: 7 additions & 0 deletions src/memory/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,11 @@ config MEM_RANDOM
help
This may help to find undefined behaviors.

config MEM_COMPRESS
depends on MODE_SYSTEM && !DIFFTEST
bool "Initialize the memory with a compressed gz file"
default n
help
Must have zlib installed.

endmenu #MEMORY
58 changes: 57 additions & 1 deletion src/monitor/monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,68 @@ static inline void welcome() {
}

#ifndef CONFIG_MODE_USER

#ifdef CONFIG_MEM_COMPRESS
#include <zlib.h>

static long load_gz_img(const char *filename) {
gzFile compressed_mem = gzopen(filename, "rb");
Assert(compressed_mem, "Can not open '%s'", filename);

const uint32_t chunk_size = 16384;
uint8_t *temp_page = (uint8_t *)calloc(chunk_size, sizeof(long));
uint8_t *pmem_start = (uint8_t *)guest_to_host(RESET_VECTOR);
uint8_t *pmem_current;

// load file byte by byte to pmem
uint64_t curr_size = 0;
while (curr_size < CONFIG_MSIZE) {
uint32_t bytes_read = gzread(compressed_mem, temp_page, chunk_size);
if (bytes_read == 0) {
break;
}
for (uint32_t x = 0; x < bytes_read; x++) {
pmem_current = pmem_start + curr_size + x;
uint8_t read_data = *(temp_page + x);
if (read_data != 0 || *pmem_current != 0) {
*pmem_current = read_data;
}
}
curr_size += bytes_read;
}

// check again to ensure the bin has been fully loaded
uint32_t left_bytes = gzread(compressed_mem, temp_page, chunk_size);
Assert(left_bytes == 0, "File size is larger than buf_size!\n");

free(temp_page);
Assert(!gzclose(compressed_mem), "Error closing '%s'\n", filename);
return curr_size;
}

// Return whether a file is a gz file, determined by its name.
// If the filename ends with ".gz", we treat it as a gz file.
bool is_gz_file(const char *filename) {
if (filename == NULL || strlen(filename) < 3) {
return false;
}
return !strcmp(filename + (strlen(filename) - 3), ".gz");
}
#endif // CONFIG_MEM_COMPRESS

static inline long load_img() {
if (img_file == NULL) {
Log("No image is given. Use the default build-in image.");
return 4096; // built-in image size
}

#ifdef CONFIG_MEM_COMPRESS
if (is_gz_file(img_file)) {
Log("The image is %s", img_file);
return load_gz_img(img_file);
}
#endif

FILE *fp = fopen(img_file, "rb");
Assert(fp, "Can not open '%s'", img_file);

Expand All @@ -52,7 +108,7 @@ static inline long load_img() {
fclose(fp);
return size;
}
#endif
#endif // CONFIG_MODE_USER

static inline int parse_args(int argc, char *argv[]) {
const struct option table[] = {
Expand Down

0 comments on commit eed97c7

Please sign in to comment.