diff --git a/platform/pc/Makefile b/platform/pc/Makefile index 882e80078..6cebc9035 100644 --- a/platform/pc/Makefile +++ b/platform/pc/Makefile @@ -22,6 +22,7 @@ SRCS-kernel.elf= \ $(SRCDIR)/drivers/gve.c \ $(SRCDIR)/drivers/nvme.c \ $(SRCDIR)/drivers/netconsole.c \ + $(SRCDIR)/drivers/ramdisk.c \ $(SRCDIR)/drivers/vga.c \ $(SRCDIR)/gdb/gdbstub.c \ $(SRCDIR)/gdb/gdbtcp.c \ diff --git a/platform/pc/service.c b/platform/pc/service.c index 2c052633e..759255d1e 100644 --- a/platform/pc/service.c +++ b/platform/pc/service.c @@ -18,12 +18,15 @@ #include #include #include +#include #include #include "serial.h" #define BOOT_PARAM_OFFSET_E820_ENTRIES 0x01E8 #define BOOT_PARAM_OFFSET_BOOT_FLAG 0x01FE #define BOOT_PARAM_OFFSET_HEADER 0x0202 +#define BOOT_PARAM_OFFSET_RAMDISK_IMAGE 0x0218 +#define BOOT_PARAM_OFFSET_RAMDISK_SIZE 0x021C #define BOOT_PARAM_OFFSET_CMD_LINE_PTR 0x0228 #define BOOT_PARAM_OFFSET_CMDLINE_SIZE 0x0238 #define BOOT_PARAM_OFFSET_E820_TABLE 0x02D0 @@ -64,8 +67,17 @@ typedef struct hvm_memmap_entry { u32 reserved; } *hvm_memmap_entry; +typedef struct hvm_modlist_entry { + u64 paddr; + u64 size; + u64 cmdline_paddr; + u64 reserved; +} *hvm_modlist_entry; + extern u8 START, END; +boolean cmdline_verbose_logging = false; + range kern_get_elf(void) { for_regions(e) { @@ -75,6 +87,15 @@ range kern_get_elf(void) return irange(INVALID_PHYSICAL, INVALID_PHYSICAL); } +range kern_get_ramdisk(void) +{ + for_regions(e) { + if (e->type == REGION_RAMDISK) + return irangel(e->base, e->length); + } + return irange(INVALID_PHYSICAL, INVALID_PHYSICAL); +} + BSS_RO_AFTER_INIT static boolean have_rdseed; BSS_RO_AFTER_INIT static boolean have_rdrand; @@ -292,20 +313,21 @@ void init_physical_heap(void) } boolean found = false; - early_init_debug("physical memory:"); + if (cmdline_verbose_logging) + early_debug("Physical memory: \n"); for_regions(e) { if (e->type == REGION_PHYSICAL) { u64 base = e->base; u64 length = e->length; if (length == 0) continue; -#ifdef INIT_DEBUG - early_debug("INIT: ["); - early_debug_u64(base); - early_debug(", "); - early_debug_u64(base + length); - early_debug(")\n"); -#endif + if (cmdline_verbose_logging) { + early_debug("\t["); + early_debug_u64(base); + early_debug(", "); + early_debug_u64(base + length); + early_debug(")\n"); + } if (!pageheap_add_range(base, length)) halt(" - id_heap_add_range failed\n"); found = true; @@ -319,19 +341,59 @@ void init_physical_heap(void) static void setup_initmap(void) { u64 kernel_size = u64_from_pointer(&END) - KERNEL_BASE_PHYS; + create_region(KERNEL_BASE_PHYS, kernel_size, REGION_KERN_LOAD); + region page_region = 0; for_regions(r) { - if ((r->type == REGION_PHYSICAL) && (r->base <= KERNEL_BASE_PHYS) && - (r->base + r->length > KERNEL_BASE_PHYS)) { - /* This is the memory region where the kernel has been loaded: adjust the region - * boundaries so that the memory occupied by the kernel code does not appear as free - * memory, and possibly and make a new memory region. */ - if (r->base < KERNEL_BASE_PHYS) - create_region(r->base, KERNEL_BASE_PHYS - r->base, r->type); - region_resize(r, r->base - pad(KERNEL_BASE_PHYS + kernel_size, PAGESIZE)); - - page_region = r; - break; + if (r->type == REGION_PHYSICAL) { + for_regions(s) { + if (s->type != REGION_PHYSICAL && + s->length != 0 && + r->base <= s->base && + r->base + r->length > s->base) { + u64 inner_start = s->base; + u64 inner_end = s->base + s->length; + + if (inner_end > r->base + r->length) { + inner_end = r->base + r->length; + } + if (cmdline_verbose_logging) { + early_debug("Reserving region: ["); + early_debug_u64(r->base); + early_debug(" - "); + early_debug_u64(r->base + r->length); + early_debug("] (physmem), ["); + early_debug_u64(inner_start); + early_debug(" - "); + early_debug_u64(inner_end); + early_debug("] ("); + early_debug_u64(s->type); + early_debug(")\n"); + } + if (r->base < inner_start) { + create_region(r->base, inner_start - r->base, r->type); + if (cmdline_verbose_logging) { + early_debug("\tcreate: "); + early_debug_u64(r->base); + early_debug(" - "); + early_debug_u64(inner_start); + early_debug("\n"); + } + } + region_resize(r, r->base - pad(inner_end, PAGESIZE)); + if (cmdline_verbose_logging) { + early_debug("\tshrink: "); + early_debug_u64(r->base); + early_debug(" - "); + early_debug_u64(r->base + r->length); + early_debug("\n"); + } + if (s->type == REGION_KERN_LOAD) { + assert(!page_region); + page_region = r; + } + } + } } } assert(page_region); @@ -366,11 +428,14 @@ static void setup_initmap(void) } // init linker set -void init_service(u64 rdi, u64 rsi) +void init_service(u64 rdi, u64 rsi, hvm_start_info start_info) { u8 *params = pointer_from_u64(rsi); + boolean should_setup_initmap = false; const char *cmdline = 0; u32 cmdline_size; + void *ramdisk = 0; + u32 ramdisk_size; if (params && (*(u16 *)(params + BOOT_PARAM_OFFSET_BOOT_FLAG) == 0xAA55) && (*(u32 *)(params + BOOT_PARAM_OFFSET_HEADER) == 0x53726448)) { @@ -389,9 +454,55 @@ void init_service(u64 rdi, u64 rsi) BOOT_PARAM_OFFSET_CMD_LINE_PTR))); cmdline_size = *((u32 *)(params + BOOT_PARAM_OFFSET_CMDLINE_SIZE)); - setup_initmap(); + ramdisk = pointer_from_u64((u64)*((u32 *)(params + + BOOT_PARAM_OFFSET_RAMDISK_IMAGE))); + ramdisk_size = *((u32 *)(params + BOOT_PARAM_OFFSET_RAMDISK_SIZE)); + + should_setup_initmap = true; + } else if (start_info) + { + cmdline = pointer_from_u64(start_info->cmdline_paddr); + cmdline_size = 0; + const char *cmdline_p = cmdline; + while (*cmdline_p) + { + cmdline_size++; + cmdline_p++; + } + + if (start_info->nr_modules) + { + hvm_modlist_entry ramdisk_entry = pointer_from_u64(start_info->modlist_paddr); + ramdisk = pointer_from_u64(ramdisk_entry->paddr); + ramdisk_size = ramdisk_entry->size; + } + should_setup_initmap = true; } + if (cmdline) { + create_region(u64_from_pointer(cmdline), cmdline_size, REGION_CMDLINE); + sstring input = sstring_from_cstring(cmdline, cmdline_size); + sstring token, rest; + sstring delim = ss(" "); + token = runtime_strtok_r(&input, delim, &rest); + while (!sstring_is_null(token)) { + if(runtime_strcmp(token, ss("verbose")) == 0) { + cmdline_verbose_logging = true; + } + token = runtime_strtok_r(0, delim, &rest); + } + } + + if (ramdisk) + create_region(u64_from_pointer(ramdisk), ramdisk_size, REGION_RAMDISK); + +#ifdef INIT_DEBUG + cmdline_verbose_logging = true; +#endif + + if (should_setup_initmap) + setup_initmap(); + serial_init(); early_init_debug("init_service"); @@ -402,8 +513,6 @@ void init_service(u64 rdi, u64 rsi) init_hwrand(); kaslr(); init_kernel_heaps(); - if (cmdline) - create_region(u64_from_pointer(cmdline), cmdline_size, REGION_CMDLINE); u64 stack_size = 32*PAGESIZE; u64 stack_location = allocate_u64((heap)heap_page_backed(get_kernel_heaps()), stack_size); stack_location += stack_size - STACK_ALIGNMENT; @@ -421,8 +530,7 @@ void pvh_start(hvm_start_info start_info) if (mem_table[i].type == HVM_MEMMAP_TYPE_RAM) create_region(mem_table[i].addr, mem_table[i].size, REGION_PHYSICAL); } - setup_initmap(); - init_service(0, 0); + init_service(0, 0, start_info); } RO_AFTER_INIT static struct console_driver serial_console_driver = { @@ -499,6 +607,7 @@ void detect_devices(kernel_heaps kh, storage_attach sa) init_pvscsi(kh, sa); init_nvme(kh, sa); init_ata_pci(kh, sa); + init_ramdisk(kh, sa); init_virtio_9p(kh); init_virtio_socket(kh); diff --git a/platform/riscv-virt/service.c b/platform/riscv-virt/service.c index 3e224503b..33ef4d161 100644 --- a/platform/riscv-virt/service.c +++ b/platform/riscv-virt/service.c @@ -63,6 +63,11 @@ range kern_get_elf(void) return irange(INVALID_PHYSICAL, INVALID_PHYSICAL); } +range kern_get_ramdisk(void) +{ + return irange(INVALID_PHYSICAL, INVALID_PHYSICAL); +} + void reclaim_regions(void) { /* mmu init complete; unmap temporary identity map */ diff --git a/platform/virt/service.c b/platform/virt/service.c index 8322f7653..3455b26fa 100644 --- a/platform/virt/service.c +++ b/platform/virt/service.c @@ -194,6 +194,11 @@ range kern_get_elf(void) return irange(INVALID_PHYSICAL, INVALID_PHYSICAL); } +range kern_get_ramdisk(void) +{ + return irange(INVALID_PHYSICAL, INVALID_PHYSICAL); +} + void reclaim_regions(void) { } diff --git a/src/drivers/ramdisk.c b/src/drivers/ramdisk.c new file mode 100644 index 000000000..5d64ac1b7 --- /dev/null +++ b/src/drivers/ramdisk.c @@ -0,0 +1,68 @@ +#include +#include + +#include "ramdisk.h" + +typedef struct storage *storage; + +declare_closure_struct(2, 3, void, ramdisk_io, + storage, st, boolean, write, + void *buf, range blocks, status_handler sh); + +typedef struct storage +{ + closure_struct(storage_simple_req_handler, req_handler); + closure_struct(ramdisk_io, read); + closure_struct(ramdisk_io, write); + void *ramdisk; + u64 ramdisk_size; +} *storage; + +define_closure_function(2, 3, void, ramdisk_io, + storage, st, boolean, write, + void *buf, range blocks, status_handler sh) +{ + storage st = bound(st); + boolean write = bound(write); + + if (write) + { + apply(sh, timm("result", "read-only device")); + return; + } + + u64 start_byte_offset = blocks.start * SECTOR_SIZE; + u64 end_byte_offset = blocks.end * SECTOR_SIZE; + if (start_byte_offset > end_byte_offset || end_byte_offset > st->ramdisk_size) + { + apply(sh, timm("result", "read out of bounds")); + return; + } + + runtime_memcpy(buf, st->ramdisk + start_byte_offset, end_byte_offset - start_byte_offset); + apply(sh, STATUS_OK); +} + +void init_ramdisk(kernel_heaps kh, storage_attach a) +{ + range ramdisk_phys = kern_get_ramdisk(); + if (ramdisk_phys.start == INVALID_PHYSICAL) + { + msg_print("RAMDISK: not detected"); + return; + } + u64 ramdisk_size = range_span(ramdisk_phys); + u64 v = allocate_u64((heap)heap_virtual_huge(kh), ramdisk_size); + map(v, ramdisk_phys.start, ramdisk_size, pageflags_memory()); + + heap h = heap_locked(kh); + storage st = allocate(h, sizeof(struct storage)); + st->ramdisk = pointer_from_u64(v); + st->ramdisk_size = ramdisk_size; + apply(a, + storage_init_req_handler(&st->req_handler, + init_closure(&st->read, ramdisk_io, st, false), + init_closure(&st->write, ramdisk_io, st, true)), + ramdisk_size, -1); + msg_print("RAMDISK: %u bytes at %p", st->ramdisk_size, st->ramdisk); +} \ No newline at end of file diff --git a/src/drivers/ramdisk.h b/src/drivers/ramdisk.h new file mode 100644 index 000000000..738882353 --- /dev/null +++ b/src/drivers/ramdisk.h @@ -0,0 +1 @@ +void init_ramdisk(kernel_heaps kh, storage_attach a); diff --git a/src/kernel/kernel.h b/src/kernel/kernel.h index a83c956c1..a95150f00 100644 --- a/src/kernel/kernel.h +++ b/src/kernel/kernel.h @@ -602,6 +602,7 @@ void init_platform_devices(kernel_heaps kh); void init_cpuinfo_machine(cpuinfo ci, heap backed); void kernel_runtime_init(kernel_heaps kh); range kern_get_elf(void); +range kern_get_ramdisk(void); void reclaim_regions(void); extern u64 kernel_phys_offset; diff --git a/src/kernel/region.h b/src/kernel/region.h index e8c9bfc9c..15ab9aded 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -19,7 +19,8 @@ typedef struct region *region; #define REGION_RECLAIM 14 /* areas to be unmapped and reclaimed in stage3 (only stage2 stack presently) */ #define REGION_SMBIOS 15 /* SMBIOS entry point */ #define REGION_RSDP 16 /* location of the ACPI RSDP */ - +#define REGION_RAMDISK 17 /* kernel ramdisk */ +#define REGION_KERN_LOAD 18 /* kernel load region */ static inline region create_region(u64 base, u64 length, int type) { diff --git a/src/x86_64/crt0.s b/src/x86_64/crt0.s index 85db91e8c..1dd3ee8c5 100644 --- a/src/x86_64/crt0.s +++ b/src/x86_64/crt0.s @@ -396,6 +396,7 @@ write_xmsr: .end: _start: + xor edx, edx call init_service hlt .end: