--- nono/vm/bootloader.cpp 2026/04/29 17:05:24 1.1.1.2 +++ nono/vm/bootloader.cpp 2026/04/29 17:05:59 1.1.1.5 @@ -21,21 +21,39 @@ #include "aout.h" #include "autofd.h" #include "elf.h" +#include "iodevstream.h" #include "mainapp.h" #include "mainram.h" #include #include #include #include +#include + +// info で指定された実行ファイルを mainram にロードする。 +/*static*/ bool +BootLoader::LoadExec(MainRAMDevice *mainram_, LoadInfo *info) +{ + BootLoader loader(mainram_); + return loader.LoadExec(info); +} + +// info で指定されたデータファイルを mainram にロードする。 +/*static*/ bool +BootLoader::LoadData(MainRAMDevice *mainram_, LoadInfo *info) +{ + BootLoader loader(mainram_); + return loader.LoadData(info); +} // コンストラクタ -BootLoader::BootLoader(MainRAMDevice *ram_) +BootLoader::BootLoader(MainRAMDevice *mainram_) : inherited(OBJ_BOOTLOADER) { - ram = ram_; + mainram = mainram_; // RAM デバイスのログレベルを踏襲する。 - loglevel = ram->loglevel; + loglevel = mainram->loglevel; } // デストラクタ @@ -55,9 +73,9 @@ BootLoader::LoadData(LoadInfo *info) assert(info->size != 0); // ゲストにコピー。 - IODeviceStream ds(ram, info->start); - WriteFromHost(ds, info->data, info->size); - + if (mainram->WriteMem(info->start, info->data, info->size) == false) { + return false; + } info->end = info->start + info->size; return true; @@ -94,30 +112,30 @@ BootLoader::LoadExecFromFile(LoadInfo *i fd = open(info->path, O_RDONLY); if (fd == -1) { - warn("%s \"%s\" open failed", __func__, info->path); + warn("%s \"%s\"", __method__, info->path); return false; } if (fstat(fd, &st) == -1) { - warn("%s \"%s\" fstat failed", __func__, info->path); + warn("%s \"%s\" fstat failed", __method__, info->path); return false; } if (!S_ISREG(st.st_mode)) { - warnx("%s \"%s\" not a regular file", __func__, info->path); + warnx("%s \"%s\" not a regular file", __method__, info->path); return false; } // 今の所マジック判定は最初の4バイトで出来るので if (st.st_size < 4) { - warnx("%s \"%s\" file too short", __func__, info->path); + warnx("%s \"%s\" file too short", __method__, info->path); return false; } filesize = st.st_size; filedata = (uint8 *)mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0); if (filedata == MAP_FAILED) { - warn("%s \"%s\" mmap failed", __func__, info->path); + warn("%s \"%s\" mmap failed", __method__, info->path); return false; } @@ -152,7 +170,7 @@ BootLoader::LoadGzFile(LoadInfo *info) // gzip なら(?) ファイルの末尾4バイトが (LE で?) 展開後サイズ(?)。 decompsize = le32toh(*(const uint32 *)&infile[infilesize - 4]); - std::unique_ptr dstbuf(new uint8[decompsize]); + std::vector dstbuf(decompsize); // gzip 展開 // (uncompress() の方が楽そうに見えるが gzip 形式に対応してないらしい) @@ -167,7 +185,7 @@ BootLoader::LoadGzFile(LoadInfo *info) z.next_in = const_cast(infile); z.avail_in = infilesize - 4; - z.next_out = dstbuf.get(); + z.next_out = dstbuf.data(); z.avail_out = decompsize; rv = inflate(&z, Z_NO_FLUSH); if (rv != Z_OK) { @@ -178,7 +196,7 @@ BootLoader::LoadGzFile(LoadInfo *info) inflateEnd(&z); // 展開できたのでロード - info->data = dstbuf.get(); + info->data = dstbuf.data(); info->size = decompsize; return LoadExecFromBuf(info); } @@ -273,17 +291,21 @@ BootLoader::Load_aout(LoadInfo *info) "(text=%u + data=%u, filesize=%d); loading %d bytes", __func__, info->path, aout.textsize, aout.datasize, (int)info->size, copylen); - /* FALLTHROUGH */ + // FALLTHROUGH } - if (aout.entry + copylen > ram->GetSize()) { + if (aout.entry + copylen > mainram->GetSize()) { warnx("%s \"%s\" out of memory in VM", __func__, info->path); return false; } // 再配置不要なので、text + data を entry に置いて entry に飛ぶだけ - IODeviceStream ds(ram, aout.entry); - WriteFromHost(ds, info->data + sizeof(aout), copylen); + bool ok = mainram->WriteMem(aout.entry, info->data + sizeof(aout), copylen); + if (ok == false) { + warnx("%s \"%s\" WriteMem($%x, $%x) failed", + __func__, info->path, aout.entry, copylen); + return false; + } // a.out は entry だけでよい info->entry = aout.entry; @@ -469,7 +491,7 @@ BootLoader::Load_elf32_exec(LoadInfo *in return false; } - IODeviceStream ds(ram); + IODeviceStream ds(mainram); for (int j = 0; j < e_phnum; j++) { const Elf32_Phdr *phdr = @@ -491,13 +513,13 @@ BootLoader::Load_elf32_exec(LoadInfo *in } if (p_type == PT_LOAD) { - if (p_vaddr + p_memsz > ram->GetSize()) { + if (p_vaddr + p_memsz > mainram->GetSize()) { warnx("%s \"%s\" out of memory in VM", __func__, info->path); return false; } - // 読み込み開始位置。 - // 実際にはカーネルのプログラムヘッダは1つのはずだけど一応。 + // 読み込み開始位置を一応覚えておく。 + // 隙間のある2つ以上のヘッダが来られるとあまり意味はなくなるが。 if (j == 0) { info->start = p_vaddr; } else { @@ -505,9 +527,9 @@ BootLoader::Load_elf32_exec(LoadInfo *in } ds.SetAddr(p_vaddr); - WriteFromHost(ds, info->data + p_offset, p_filesz); + ds.WriteMem(info->data + p_offset, p_filesz); for (int i = p_filesz; i < p_memsz; i++) { - ds.Write8(0); + ds.Write1(0); } bootmsg += string_format("%d+%d", p_filesz, p_memsz - p_filesz); } else if (p_type == PT_NOTE) { @@ -714,7 +736,7 @@ BootLoader::Load_elf32_sym(LoadInfo *inf */ // まず、さっき読んだ section names セクションを RAM にコピー。 if (e_shstrndx != SHN_UNDEF) { - readfile_global(maxp, info->data + shstroff, shstrsz); + mainram->WriteMem(maxp, info->data + shstroff, shstrsz); shp[e_shstrndx].sh_offset = htoelf32(maxp - elfp); maxp += roundup(shstrsz, ELFROUND); @@ -735,7 +757,7 @@ BootLoader::Load_elf32_sym(LoadInfo *inf uint32 sh_offset = elf32toh(shp[i].sh_offset); // ファイル先頭から uint32 sh_size = elf32toh(shp[i].sh_size); // サイズ if (loglevel >= 1) { - putmsgn("[%2d] sh_name = %s", i, &shstr[sh_name]); + putmsgn("[%2u] sh_name = %s", i, &shstr[sh_name]); putmsgn(" sh_type = $%08x (%s)", sh_type, GetElfShTypeStr(sh_type)); putmsgn(" sh_addr = $%08x", sh_addr); @@ -790,7 +812,7 @@ BootLoader::Load_elf32_sym(LoadInfo *inf case SHT_SYMTAB: havesym: bootmsg += string_format("%s%d", (first ? " [" : "+"), sh_size); - readfile_global(maxp, info->data + sh_offset, sh_size); + mainram->WriteMem(maxp, info->data + sh_offset, sh_size); shp[i].sh_offset = htoelf32(maxp - elfp); maxp += roundup(sh_size, ELFROUND); first = false; @@ -840,7 +862,7 @@ BootLoader::Load_elf32_sym(LoadInfo *inf putmsgn("Modified Section Header:"); for (int k = 0; k < elf16toh(elf.e_shnum); k++) { auto& s = shp[k]; - putmsgn("[%2d] %-8s offset=%08x size=%08x", + putmsgn("[%2u] %-8s offset=%08x size=%08x", k, GetElfShTypeStr(elf32toh(s.sh_type)) + 4, elf32toh(s.sh_offset), @@ -849,7 +871,7 @@ BootLoader::Load_elf32_sym(LoadInfo *inf } // ローカルの shp を shpp の位置に書き出す。 // このために shp はターゲットエンディアンになっている。 - readfile_global(shpp, &shp[0], sz); + mainram->WriteMem(shpp, &shp[0], sz); /* * Update the ELF HEADER to give information relative to elfp. @@ -869,7 +891,7 @@ BootLoader::Load_elf32_sym(LoadInfo *inf putmsgn(" e_shentsize = $%04x x %d", elf16toh(elf.e_shentsize), elf16toh(elf.e_shnum)); } - readfile_global(elfp, &elf, sizeof(elf)); + mainram->WriteMem(elfp, &elf, sizeof(elf)); info->sym = elfp; info->end = maxp; @@ -900,8 +922,7 @@ BootLoader::Load_elf32_rel(LoadInfo *inf return false; } - IODeviceStream ds(ram); - ds.SetAddr(entry); + IODeviceStream ds(mainram, entry); for (int j = 0; j < e_shnum; j++) { const Elf32_Shdr *shdr = @@ -920,11 +941,11 @@ BootLoader::Load_elf32_rel(LoadInfo *inf } if (sh_type == SHT_PROGBITS) { - WriteFromHost(ds, info->data + sh_offset, sh_size); + ds.WriteMem(info->data + sh_offset, sh_size); } else if (sh_type == SHT_RELA || sh_type == SHT_REL) { // 再配置情報があるのは .R 形式ではない warnx("%s \"%s\" has relocation section", __func__, info->path); - return 0; + return false; } else { // ? } @@ -936,32 +957,6 @@ BootLoader::Load_elf32_rel(LoadInfo *inf return true; } -// ホストの src から len バイトを ds の現在位置からに書き込む。 -// ds のアドレスは更新される。 -void -BootLoader::WriteFromHost(IODeviceStream& ds, const void *src, int len) -{ - const uint8 *s = (const uint8 *)src; - - for (int i = 0; i < len; i++) { - ds.Write8(*s++); - } -} - -// ホストの src から len バイトを RAM の dstaddr からに書き込む。 -// 呼び出し元の dstaddr は更新されない。 -// 関数名は libsa/loadfile_elf32.c 由来。 -void -BootLoader::readfile_global(uint32 dstaddr, const void *src, int len) -{ - const uint8 *s = (const uint8 *)src; - IODeviceStream ds(ram, dstaddr); - - for (int i = 0; i < len; i++) { - ds.Write8(*s++); - } -} - // // LoadInfo クラス