--- nono/vm/ram.cpp 2026/04/29 17:04:50 1.1.1.7 +++ nono/vm/ram.cpp 2026/04/29 17:04:59 1.1.1.10 @@ -24,12 +24,11 @@ std::unique_ptr gRAM; // RAM はロングワード単位でホストバイトオーダ配置なので、 // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。 -std::unique_ptr ram; +std::unique_ptr mainram; RAMDevice::RAMDevice() + : inherited("RAM") { - logname = "ram"; - devname = "MainRAM"; devaddr = 0; // アクセスウェイト @@ -77,7 +76,7 @@ RAMDevice::Init() // メインメモリは 12MB まで。 // 内部は 8KB 単位で処理できるが設定が 1MB 単位。 if (ram_size_MB > 12) { - item.Err(); + item.Err("configurable maximum main memory size is 12 [MB]"); return false; } break; @@ -93,11 +92,11 @@ RAMDevice::Init() // 上限だが、設定ファイルからの指定が 1MB 単位なので 255MB。 if (ram_size_MB <= 16) { if (ram_size_MB % 4 != 0) { - item.Err(); + item.Err("for 16MB or less, must be specified in 4 [MB] unit"); return false; } } else if (ram_size_MB > 255) { - item.Err(); + item.Err("configurable maximum RAM size is 255 [MB]"); return false; } break; @@ -108,11 +107,11 @@ RAMDevice::Init() // 64MB を超える増設 (or 魔改造) 部分は未確認。 if (ram_size_MB <= 64) { if (ram_size_MB % 16 != 0) { - item.Err(); + item.Err("for 64MB or less, must be specified in 16 [MB] unit"); return false; } } else if (ram_size_MB > 255) { - item.Err(); + item.Err("configurable maximum RAM size is 255 [MB]"); return false; } break; @@ -122,13 +121,21 @@ RAMDevice::Init() } ram_size = ram_size_MB * 1024 * 1024; - ram.reset(new uint8[ram_size]); + mainram.reset(new uint8[ram_size]); // devtable[] への RAM デバイスの配置はこの後 VM::Init 側で行っている return true; } +bool +RAMDevice::PowerOn() +{ + // XXX ノイズを用意する + + return true; +} + void RAMDevice::ResetHard() { @@ -144,7 +151,7 @@ RAMDevice::Read8(uint32 addr) { gMPU->AddCycle(read_wait); uint32 data; - data = ram[HLB(addr)]; + data = mainram[HLB(addr)]; putlog(4, "$%08x.B -> $%02x", addr, data); return data; } @@ -154,7 +161,7 @@ RAMDevice::Read16(uint32 addr) { gMPU->AddCycle(read_wait); uint32 data; - data = *(uint16 *)&ram[HLW(addr)]; + data = *(uint16 *)&mainram[HLW(addr)]; putlog(4, "$%08x.W -> $%04x", addr, data); return data; } @@ -164,7 +171,7 @@ RAMDevice::Read32(uint32 addr) { gMPU->AddCycle(read_wait); uint32 data; - data = *(uint32 *)&ram[addr]; + data = *(uint32 *)&mainram[addr]; putlog(4, "$%08x.L -> $%08x", addr, data); return data; } @@ -173,7 +180,7 @@ uint64 RAMDevice::Write8(uint32 addr, uint32 data) { gMPU->AddCycle(write_wait); - ram[HLB(addr)] = data; + mainram[HLB(addr)] = data; putlog(3, "$%08x.B <- $%02x", addr, data); return 0; } @@ -182,7 +189,7 @@ uint64 RAMDevice::Write16(uint32 addr, uint32 data) { gMPU->AddCycle(write_wait); - *(uint16 *)&ram[HLW(addr)] = data; + *(uint16 *)&mainram[HLW(addr)] = data; putlog(3, "$%08x.W <- $%04x", addr, data); return 0; } @@ -191,7 +198,7 @@ uint64 RAMDevice::Write32(uint32 addr, uint32 data) { gMPU->AddCycle(write_wait); - *(uint32 *)&ram[addr] = data; + *(uint32 *)&mainram[addr] = data; putlog(3, "$%08x.L <- $%08x", addr, data); return 0; } @@ -199,7 +206,7 @@ RAMDevice::Write32(uint32 addr, uint32 d uint64 RAMDevice::Peek8(uint32 addr) { - return ram[HLB(addr)]; + return mainram[HLB(addr)]; } // アクセスウェイトを設定 (X68030 でシステムポートから呼ばれる) @@ -224,30 +231,30 @@ RAMDevice::LoadFile(const char *filepath fd = open(filepath, O_RDONLY); if (fd == -1) { - warn("LoadFile \"%s\" open failed", filepath); + warn("%s \"%s\" open failed", __func__, filepath); return 0; } if (fstat(fd, &st) == -1) { - warn("LoadFile \"%s\" fstat failed", filepath); + warn("%s \"%s\" fstat failed", __func__, filepath); return 0; } if (!S_ISREG(st.st_mode)) { - warnx("LoadFile \"%s\" not a regular file", filepath); + warnx("%s \"%s\" not a regular file", __func__, filepath); return 0; } // 今の所マジック判定は最初の4バイトで出来るので if (st.st_size < 4) { - warnx("LoadFile \"%s\" file too short", filepath); + warnx("%s \"%s\" file too short", __func__, filepath); return 0; } filesize = st.st_size; file = (uint8 *)mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0); if (file == MAP_FAILED) { - warn("LoadFile \"%s\" mmap failed", filepath); + warn("%s \"%s\" mmap failed", __func__, filepath); return 0; } @@ -284,7 +291,7 @@ RAMDevice::LoadGzFile(const char *filepa z.opaque = Z_NULL; rv = inflateInit2(&z, 47); if (rv != Z_OK) { - warnx("LoadGzFile \"%s\" inflateInit2 failed %d", filepath, rv); + warnx("%s \"%s\" inflateInit2 failed %d", __func__, filepath, rv); return 0; } @@ -294,7 +301,7 @@ RAMDevice::LoadGzFile(const char *filepa z.avail_out = decompsize; rv = inflate(&z, Z_NO_FLUSH); if (rv != Z_OK) { - warnx("LoadGzFile \"%s\" inflate failed %d", filepath, rv); + warnx("%s \"%s\" inflate failed %d", __func__, filepath, rv); return 0; } @@ -321,7 +328,7 @@ RAMDevice::LoadFile(const char *name, co } else if ((be32toh(aout->magic) & 0xffff) == AOUT_OMAGIC) { entry = Load_aout(name, file, filesize); } else { - warnx("LoadFile \"%s\" unknown executable file format", name); + warnx("%s \"%s\" unknown executable file format", __func__, name); } return entry; @@ -336,7 +343,7 @@ RAMDevice::Load_aout(const char *name, c int copylen; if (filesize < sizeof(aout)) { - warnx("Load_aout \"%s\" file too short", name); + warnx("%s \"%s\" file too short", __func__, name); return 0; } @@ -352,18 +359,21 @@ RAMDevice::Load_aout(const char *name, c aout.datarelsize = be32toh(((const aout_header *)file)->datarelsize); // マジックをチェック - uint32 target_mid; + uint32 mid = AOUT_MID(aout.magic); + bool mid_mismatch = false; if (gMainApp.HasVMFeature(VMF_M68K)) { - target_mid = AOUT_MID_M68K; + if (mid != AOUT_MID_BSD_M68K8K && mid != AOUT_MID_BSD_M68K4K) { + mid_mismatch = true; + } } else if (gMainApp.HasVMFeature(VMF_M88K)) { - target_mid = AOUT_MID_M88K; + if (mid != AOUT_MID_BSD_M88K && mid != AOUT_MID_MACH_M88K) { + mid_mismatch = true; + } } else { PANIC("Unknown CPU?"); } - uint32 mid = AOUT_MID(aout.magic); - if (mid != target_mid) { - warnx("Load_aout \"%s\" machine id mismatch (%03x expected but %03x)", - name, target_mid, mid); + if (mid_mismatch) { + warnx("%s \"%s\" machine id $%03x mismatch", __func__, name, mid); return 0; } @@ -377,7 +387,7 @@ RAMDevice::Load_aout(const char *name, c // とりあえず再配置は無視 if (aout.textrelsize != 0 || aout.datarelsize != 0) { - warnx("Load_aout \"%s\" relocation not supported", name); + warnx("%s \"%s\" relocation not supported", __func__, name); return 0; } @@ -387,14 +397,15 @@ RAMDevice::Load_aout(const char *name, c copylen = aout.textsize + aout.datasize; if (copylen >= filesize) { copylen = filesize; - warnx("warning: Load_aout \"%s\" coruppted? " + warnx("warning: %s \"%s\" corrupted? " "(text=%u + data=%u, filesize=%d); loading %d bytes", + __func__, name, aout.textsize, aout.datasize, (int)filesize, copylen); /* FALLTHROUGH */ } if (aout.entry + copylen > GetSize()) { - warnx("Load_aout \"%s\" out of memory in VM", name); + warnx("%s \"%s\" out of memory in VM", __func__, name); return 0; } @@ -473,7 +484,16 @@ static std::pair pty }; #define GetElfPTypeStr(x) GetElfStr1(ptype_str, (x)) -// ホストの a.out をゲストの RAM に読み込む。 +static std::pair shtype_str[] = { + { SHT_NULL, "SHT_NULL" }, + { SHT_PROGBITS, "SHT_PROGBITS" }, + { SHT_RELA, "SHT_RELA" }, + { SHT_NOBITS, "SHT_NOBITS" }, + { SHT_REL, "SHT_REL" }, +}; +#define GetElfShTypeStr(x) GetElfStr1(shtype_str, (x)) + +// ホストの ELF をゲストの RAM に読み込む。 // 戻り値はエントリポイントアドレス。エラーなら 0 を返す。 uint32 RAMDevice::Load_elf32(const char *name, const uint8 *file, size_t filesize) @@ -491,7 +511,7 @@ RAMDevice::Load_elf32(const char *name, // ヘッダをチェック const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)file; if (filesize < sizeof(*ehdr)) { - warnx("Load_elf32 \"%s\" file too short", name); + warnx("%s \"%s\" file too short", __func__, name); return 0; } uint16 e_type = elf16toh(ehdr->e_type); @@ -511,20 +531,39 @@ RAMDevice::Load_elf32(const char *name, } if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) { - warnx("Load_elf32 \"%s\" not ELF32 format", name); - return 0; - } - if (e_type != ET_EXEC) { - warnx("Load_elf32 \"%s\" not executable file", name); + warnx("%s \"%s\" not ELF32 format", __func__, name); return 0; } if (e_machine != target_elf_mid) { - warnx("Load_elf32 \"%s\" machine type mismatch " - "($%02x expected but $%02x)", + warnx("%s \"%s\" machine type mismatch " + "($%02x expected but $%02x)", __func__, name, target_elf_mid, e_machine); return 0; } + switch (e_type) { + case ET_EXEC: + if (Load_elf32_exec(name, file, filesize)) { + return e_entry; + } + break; + case ET_REL: + return Load_elf32_rel(name, file, filesize); + default: + warnx("%s \"%s\" unsupported file type", __func__, name); + break; + } + return 0; +} + +// ホストの ELF 実行形式ファイルをゲストの RAM に読み込む。 +// 読み込めたら true、エラーなら false を返す。 +// エントリポイントは呼び出し元が知っているのでこっちでは関与しない。 +bool +RAMDevice::Load_elf32_exec(const char *name, const uint8 *file, size_t filesize) +{ + const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)file; + // プログラムヘッダに読み込むべき領域が示されている // phoff がプログラムヘッダのファイル先頭からのオフセット // phentsize がプログラムヘッダ1つの大きさ @@ -538,9 +577,9 @@ RAMDevice::Load_elf32(const char *name, putlogn("e_phnum = %d", e_phnum); } if (e_phentsize != sizeof(Elf32_Phdr)) { - warnx("Load_elf32 \"%s\" unknown program header size 0x%x", + warnx("%s \"%s\" unknown program header size 0x%x", __func__, name, e_phentsize); - return 0; + return false; } IODeviceStream ds(this); @@ -565,8 +604,8 @@ RAMDevice::Load_elf32(const char *name, if (p_type == PT_LOAD) { if (p_vaddr + p_memsz > GetSize()) { - warn("Load_elf32 \"%s\" out of memory in VM", name); - return 0; + warnx("%s \"%s\" out of memory in VM", __func__, name); + return false; } ds.SetAddr(p_vaddr); @@ -586,11 +625,71 @@ RAMDevice::Load_elf32(const char *name, continue; } else { - warnx("Load_elf32 \"%s\" p_type 0x%x(%s) not supported", + warnx("%s \"%s\" p_type 0x%x(%s) not supported", __func__, name, p_type, GetElfPTypeStr(p_type)); + return false; + } + } + + return true; +} + +// ホストの ELF オブジェクトの text セクションをゲストの RAM に読み込む。 +// .o(オブジェクトファイル) 用。 +// 読み込めたら true、エラーなら false を返す。 +// 戻り値はエントリポイントアドレス。エラーなら 0 を返す。 +uint32 +RAMDevice::Load_elf32_rel(const char *name, const uint8 *file, size_t filesize) +{ + const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)file; + uint32 entry = 0x20000; + + uint32 e_shoff = elf32toh(ehdr->e_shoff); + uint16 e_shentsize = elf16toh(ehdr->e_shentsize); + uint16 e_shnum = elf16toh(ehdr->e_shnum); + if (loglevel >= 1) { + putlogn("e_shoff = $%08x", e_shoff); + putlogn("e_shentsize = $%04x", e_shentsize); + putlogn("e_shnum = %d", e_shnum); + } + if (e_shentsize != sizeof(Elf32_Shdr)) { + warnx("%s \"%s\" unknown section header size 0x%x", __func__, + name, e_shentsize); + return 0; + } + + IODeviceStream ds(this); + ds.SetAddr(entry); + + for (int j = 0; j < e_shnum; j++) { + const Elf32_Shdr *shdr = &((const Elf32_Shdr*)(file + e_shoff))[j]; + // sh_type + uint32 sh_type = elf32toh(shdr->sh_type); // タイプ + uint32 sh_addr = elf32toh(shdr->sh_addr); // アドレス + uint32 sh_offset = elf32toh(shdr->sh_offset); // ファイル先頭から + uint32 sh_size = elf32toh(shdr->sh_size); // サイズ + if (loglevel >= 1) { + putlogn("[%d] sh_type = $%08x (%s)", j, + sh_type, GetElfShTypeStr(sh_type)); + putlogn(" sh_addr = $%08x", sh_addr); + putlogn(" sh_offset = $%08x", sh_offset); + putlogn(" sh_size = $%08x", sh_size); + } + + if (sh_type == SHT_PROGBITS) { + const uint8 *src = file + sh_offset; + int i = 0; + for (; i < sh_size; i++) { + ds.Write8(*src++); + } + } else if (sh_type == SHT_RELA || sh_type == SHT_REL) { + // 再配置情報があるのは .R 形式ではない + warnx("%s \"%s\" has relocation section", __func__, name); return 0; + } else { + // ? } } - return e_entry; + return entry; }