--- nono/vm/bootloader.cpp 2026/04/29 17:05:17 1.1 +++ nono/vm/bootloader.cpp 2026/04/29 17:05:28 1.1.1.3 @@ -21,21 +21,23 @@ #include "aout.h" #include "autofd.h" #include "elf.h" +#include "iodevstream.h" #include "mainapp.h" #include "mainram.h" #include #include #include #include +#include // コンストラクタ -BootLoader::BootLoader(MainRAMDevice *ram_) +BootLoader::BootLoader(MainRAMDevice *mainram_) : inherited(OBJ_BOOTLOADER) { - ram = ram_; + mainram = mainram_; // RAM デバイスのログレベルを踏襲する。 - loglevel = ram->loglevel; + loglevel = mainram->loglevel; } // デストラクタ @@ -43,11 +45,48 @@ BootLoader::~BootLoader() { } -// info->path で指定されたホストの実行ファイルをゲストにロードする。 +// info で指定されたデータファイルをゲストにロードする。 +// info->data, size が指定されていればバッファから読み込む (現状こちらのみ)。 +// info->start には読み込み先アドレスを指定する (戻り値ではない)。 +// info->end にはロードした最終アドレス(の次のアドレス) が返る (ここは同じ)。 +// 成功すれば true、失敗すれば false を返す。 +bool +BootLoader::LoadData(LoadInfo *info) +{ + assert(info->data != NULL); + assert(info->size != 0); + + // ゲストにコピー。 + if (mainram->WriteMem(info->start, info->data, info->size) == false) { + return false; + } + info->end = info->start + info->size; + + return true; +} + +// info で指定された実行ファイルをゲストにロードする。 +// info->data, size が指定されていればバッファから読み込む。 +// 指定されてなければホストの info->path から読み込む (その際 data, size は +// 内部で使用する)。 +// info->path はいずれにしてもエラー表示の際に使用する。 +// 実行ファイルのフォーマットは自動で認識する。 +// 成功すれば true、失敗すれば false を返す。 +bool +BootLoader::LoadExec(LoadInfo *info) +{ + if (info->data == NULL || info->size == 0) { + return LoadExecFromFile(info); + } else { + return LoadExecFromBuf(info); + } +} + +// info->path で指定された実行ファイルをゲストにロードする。 // ファイルのフォーマットは自動で認識する。 // 成功すれば true、失敗すれば false を返す。 bool -BootLoader::LoadFromFile(LoadInfo *info) +BootLoader::LoadExecFromFile(LoadInfo *info) { uint8 *filedata; size_t filesize; @@ -93,7 +132,7 @@ BootLoader::LoadFromFile(LoadInfo *info) rv = LoadGzFile(info); } else { // 通常ファイル - rv = LoadFromData(info); + rv = LoadExecFromBuf(info); } munmap(filedata, filesize); @@ -115,7 +154,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 形式に対応してないらしい) @@ -130,7 +169,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) { @@ -141,16 +180,16 @@ BootLoader::LoadGzFile(LoadInfo *info) inflateEnd(&z); // 展開できたのでロード - info->data = dstbuf.get(); + info->data = dstbuf.data(); info->size = decompsize; - return LoadFromData(info); + return LoadExecFromBuf(info); } // info->data, size で指定されたバッファを実行ファイルとみなしてゲストに // ロードする。ファイルのフォーマットは自動で認識する。 // 成功すれば true、失敗すれば false を返す。 bool -BootLoader::LoadFromData(LoadInfo *info) +BootLoader::LoadExecFromBuf(LoadInfo *info) { bool rv; @@ -239,14 +278,18 @@ BootLoader::Load_aout(LoadInfo *info) /* 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; @@ -432,7 +475,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 = @@ -454,7 +497,7 @@ 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; } @@ -467,10 +510,10 @@ BootLoader::Load_elf32_exec(LoadInfo *in info->start = std::min(info->start, p_vaddr); } - ds.SetAddr(p_vaddr); - WriteFromHost(ds, info->data + p_offset, p_filesz); + ds.SetOffset(p_vaddr); + 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) { @@ -487,11 +530,14 @@ BootLoader::Load_elf32_exec(LoadInfo *in } } - info->end = ds.GetAddr(); + info->end = ds.GetOffset(); + info->sym = info->end; // シンボルテーブルをロード。出来なくても構わないので続行する。 // 本当は NetBSD カーネルの時に限るのだが、とりあえず。 - Load_elf32_sym(info, bootmsg); + if (info->loadsym) { + Load_elf32_sym(info, bootmsg); + } // boot がカーネルを読んだ時と同じ形式のログを出しておく。(検証用) putmsg(1, "%s=0x%x", bootmsg.c_str(), info->end - info->start); @@ -674,7 +720,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); @@ -695,7 +741,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); @@ -750,7 +796,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; @@ -800,7 +846,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), @@ -809,7 +855,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. @@ -829,7 +875,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; @@ -860,8 +906,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 = @@ -880,11 +925,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 { // ? } @@ -892,36 +937,10 @@ BootLoader::Load_elf32_rel(LoadInfo *inf info->start = entry; info->entry = entry; - info->end = ds.GetAddr(); + info->end = ds.GetOffset(); 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 クラス @@ -929,6 +948,7 @@ BootLoader::readfile_global(uint32 dstad LoadInfo::LoadInfo() { + loadsym = true; entry = -1; }