|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.11! root 7: //
! 8: // メインメモリ
! 9: //
! 10:
1.1 root 11: #include "ram.h"
1.1.1.2 root 12: #include "aout.h"
1.1.1.7 root 13: #include "autofd.h"
1.1.1.11! root 14: #include "config.h"
1.1.1.2 root 15: #include "elf.h"
16: #include "iodevstream.h"
17: #include "mainapp.h"
1.1.1.7 root 18: #include "mpu.h"
1.1.1.2 root 19: #include <fcntl.h>
20: #include <sys/stat.h>
21: #include <sys/mman.h>
22: #include <zlib.h>
1.1 root 23:
1.1.1.11! root 24: // グローバル参照用
! 25: RAMDevice *gRAM;
1.1.1.4 root 26:
1.1 root 27: // RAM はロングワード単位でホストバイトオーダ配置なので、
28: // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。
1.1.1.8 root 29: std::unique_ptr<uint8[]> mainram;
1.1.1.4 root 30:
1.1.1.11! root 31: // コンストラクタ
1.1 root 32: RAMDevice::RAMDevice()
1.1.1.9 root 33: : inherited("RAM")
1.1 root 34: {
35: devaddr = 0;
36:
1.1.1.4 root 37: // アクセスウェイト
38: switch (gMainApp.GetVMType()) {
39: case VMTYPE_LUNA88K:
40: // 取扱説明書p.21 に、CMMU からのアクセスタイムが
41: // リード(4byte)で 200ns、バーストリード(16byte)で 320ns
42: // ライト(4byte)で 160ns、バーストライト(16byte)で 280ns とある。
43: // 25MHz は 40ns/clockで、この数値は CMMU からのアクセス全体の時間
44: // らしいので、ここで加算するウェイトはそれから 2クロック引いたもの。
45: read_wait = 3;
46: write_wait = 2;
47: break;
48: case VMTYPE_LUNA1:
49: // LUNA-I は1ウェイト。
50: read_wait = 1;
51: write_wait = 1;
52: break;
53:
54: case VMTYPE_X68030:
55: default:
56: // X68030 ではシステムポートが設定するのでここでは不要。
57: break;
58: }
1.1 root 59: }
60:
1.1.1.11! root 61: // デストラクタ
1.1 root 62: RAMDevice::~RAMDevice()
63: {
1.1.1.11! root 64: gRAM = NULL;
1.1 root 65: }
66:
67: bool
68: RAMDevice::Init()
69: {
1.1.1.4 root 70: int ram_size_MB;
71:
72: const ConfigItem& item = gConfig->Find("ram-size");
73: ram_size_MB = item.AsInt();
1.1.1.7 root 74: if (ram_size_MB < 1) {
1.1.1.3 root 75: item.Err();
76: return false;
1.1 root 77: }
1.1.1.7 root 78: // 下限以外の制約は機種による
79: switch (gMainApp.GetVMType()) {
80: case VMTYPE_X68030:
81: // メインメモリは 12MB まで。
82: // 内部は 8KB 単位で処理できるが設定が 1MB 単位。
83: if (ram_size_MB > 12) {
1.1.1.9 root 84: item.Err("configurable maximum main memory size is 12 [MB]");
1.1.1.7 root 85: return false;
86: }
87: break;
88:
89: case VMTYPE_LUNA1:
90: // 16MB までは、実機に合わせて 4MB 単位とする。
91: // see http://wiki.netbsd.org/ports/luna68k/luna68k_info/#hardware
92: //
93: // 16MB を超える増設 (or 魔改造) 部分は 1MB 単位で 255MB までとする。
94: // 実 ROM のメモリチェックは 32KB だかそのくらいずつ行われ、
95: // 最後に番兵として Null 領域 (BusError ではなく) が必要。
96: // 現行の構成をあまり変えない範囲なら厳密には (256MB - 32KB) が
97: // 上限だが、設定ファイルからの指定が 1MB 単位なので 255MB。
98: if (ram_size_MB <= 16) {
99: if (ram_size_MB % 4 != 0) {
1.1.1.9 root 100: item.Err("for 16MB or less, must be specified in 4 [MB] unit");
1.1.1.7 root 101: return false;
102: }
103: } else if (ram_size_MB > 255) {
1.1.1.9 root 104: item.Err("configurable maximum RAM size is 255 [MB]");
1.1.1.7 root 105: return false;
106: }
107: break;
108:
109: case VMTYPE_LUNA88K:
110: // 64MB までは、実機に合わせて 16MB 単位とする。
111: //
112: // 64MB を超える増設 (or 魔改造) 部分は未確認。
113: if (ram_size_MB <= 64) {
114: if (ram_size_MB % 16 != 0) {
1.1.1.9 root 115: item.Err("for 64MB or less, must be specified in 16 [MB] unit");
1.1.1.7 root 116: return false;
117: }
118: } else if (ram_size_MB > 255) {
1.1.1.9 root 119: item.Err("configurable maximum RAM size is 255 [MB]");
1.1.1.7 root 120: return false;
121: }
122: break;
123:
124: default:
125: __unreachable();
126: }
1.1.1.3 root 127:
1.1.1.4 root 128: ram_size = ram_size_MB * 1024 * 1024;
1.1.1.8 root 129: mainram.reset(new uint8[ram_size]);
1.1 root 130:
1.1.1.7 root 131: // devtable[] への RAM デバイスの配置はこの後 VM::Init 側で行っている
132:
1.1 root 133: return true;
134: }
135:
1.1.1.11! root 136: // 電源オン/リセット
1.1.1.4 root 137: void
1.1.1.11! root 138: RAMDevice::ResetHard(bool poweron)
1.1.1.4 root 139: {
1.1.1.11! root 140: if (poweron) {
! 141: // XXX ノイズを用意する
! 142: }
! 143:
1.1.1.4 root 144: // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない)
145: if (gMainApp.GetVMType() == VMTYPE_X68030) {
146: read_wait = 0;
147: write_wait = 0;
148: }
149: }
150:
1.1 root 151: uint64
152: RAMDevice::Read8(uint32 addr)
153: {
1.1.1.4 root 154: gMPU->AddCycle(read_wait);
1.1 root 155: uint32 data;
1.1.1.8 root 156: data = mainram[HLB(addr)];
1.1.1.6 root 157: putlog(4, "$%08x.B -> $%02x", addr, data);
1.1 root 158: return data;
159: }
160:
161: uint64
162: RAMDevice::Read16(uint32 addr)
163: {
1.1.1.4 root 164: gMPU->AddCycle(read_wait);
1.1 root 165: uint32 data;
1.1.1.8 root 166: data = *(uint16 *)&mainram[HLW(addr)];
1.1.1.6 root 167: putlog(4, "$%08x.W -> $%04x", addr, data);
1.1 root 168: return data;
169: }
170:
171: uint64
172: RAMDevice::Read32(uint32 addr)
173: {
1.1.1.4 root 174: gMPU->AddCycle(read_wait);
1.1 root 175: uint32 data;
1.1.1.8 root 176: data = *(uint32 *)&mainram[addr];
1.1.1.6 root 177: putlog(4, "$%08x.L -> $%08x", addr, data);
1.1 root 178: return data;
179: }
180:
181: uint64
182: RAMDevice::Write8(uint32 addr, uint32 data)
183: {
1.1.1.4 root 184: gMPU->AddCycle(write_wait);
1.1.1.8 root 185: mainram[HLB(addr)] = data;
1.1.1.6 root 186: putlog(3, "$%08x.B <- $%02x", addr, data);
1.1 root 187: return 0;
188: }
189:
190: uint64
191: RAMDevice::Write16(uint32 addr, uint32 data)
192: {
1.1.1.4 root 193: gMPU->AddCycle(write_wait);
1.1.1.8 root 194: *(uint16 *)&mainram[HLW(addr)] = data;
1.1.1.6 root 195: putlog(3, "$%08x.W <- $%04x", addr, data);
1.1 root 196: return 0;
197: }
198:
199: uint64
200: RAMDevice::Write32(uint32 addr, uint32 data)
201: {
1.1.1.4 root 202: gMPU->AddCycle(write_wait);
1.1.1.8 root 203: *(uint32 *)&mainram[addr] = data;
1.1.1.6 root 204: putlog(3, "$%08x.L <- $%08x", addr, data);
1.1 root 205: return 0;
206: }
207:
208: uint64
209: RAMDevice::Peek8(uint32 addr)
210: {
1.1.1.8 root 211: return mainram[HLB(addr)];
1.1 root 212: }
1.1.1.2 root 213:
1.1.1.4 root 214: // アクセスウェイトを設定 (X68030 でシステムポートから呼ばれる)
215: void
216: RAMDevice::SetWait(uint32 wait)
217: {
218: read_wait = wait;
219: write_wait = wait;
220: }
221:
1.1.1.2 root 222: // filepath で指定されるホストの実行ファイルをゲストにロードする。
223: // ファイルのフォーマットは自動で認識する。
224: // 戻り値はエントリポイントアドレス。エラーなら 0 を返す。
225: uint32
1.1.1.7 root 226: RAMDevice::LoadFile(const char *filepath)
1.1.1.2 root 227: {
228: uint8 *file;
229: struct stat st;
230: size_t filesize;
231: uint32 entry;
1.1.1.7 root 232: autofd fd;
1.1.1.2 root 233:
234: fd = open(filepath, O_RDONLY);
235: if (fd == -1) {
1.1.1.9 root 236: warn("%s \"%s\" open failed", __func__, filepath);
1.1.1.2 root 237: return 0;
238: }
239:
240: if (fstat(fd, &st) == -1) {
1.1.1.9 root 241: warn("%s \"%s\" fstat failed", __func__, filepath);
1.1.1.2 root 242: return 0;
243: }
244:
245: if (!S_ISREG(st.st_mode)) {
1.1.1.9 root 246: warnx("%s \"%s\" not a regular file", __func__, filepath);
1.1.1.2 root 247: return 0;
248: }
249:
250: // 今の所マジック判定は最初の4バイトで出来るので
251: if (st.st_size < 4) {
1.1.1.9 root 252: warnx("%s \"%s\" file too short", __func__, filepath);
1.1.1.2 root 253: return 0;
254: }
255: filesize = st.st_size;
256:
257: file = (uint8 *)mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
258: if (file == MAP_FAILED) {
1.1.1.9 root 259: warn("%s \"%s\" mmap failed", __func__, filepath);
1.1.1.2 root 260: return 0;
261: }
262:
263: // 先頭3バイトの gzip マジックを調べる
264: if (file[0] == 0x1f && file[1] == 0x8b && file[2] == 0x08) {
265: // gzip
1.1.1.7 root 266: entry = LoadGzFile(filepath, file, filesize);
1.1.1.2 root 267: } else {
268: // 通常ファイル
1.1.1.7 root 269: entry = LoadFile(filepath, file, filesize);
1.1.1.2 root 270: }
271:
272: munmap(file, filesize);
273: return entry;
274: }
275:
276: // gzip を展開してゲストにロードする。
277: uint32
1.1.1.7 root 278: RAMDevice::LoadGzFile(const char *filepath, const uint8 *infile,
279: size_t infilesize)
1.1.1.2 root 280: {
281: z_stream z {};
282: uint32 decompsize;
283: int rv;
284:
285: // gzip なら(?) ファイルの末尾4バイトが (LE で?) 展開後サイズ(?)。
1.1.1.3 root 286: decompsize = le32toh(*(const uint32 *)&infile[infilesize - 4]);
1.1.1.2 root 287: std::unique_ptr<uint8[]> dstbuf(new uint8[decompsize]);
288:
289: // gzip 展開
290: // (uncompress() の方が楽そうに見えるが gzip 形式に対応してないらしい)
291: z.zalloc = Z_NULL;
292: z.zfree = Z_NULL;
293: z.opaque = Z_NULL;
294: rv = inflateInit2(&z, 47);
295: if (rv != Z_OK) {
1.1.1.9 root 296: warnx("%s \"%s\" inflateInit2 failed %d", __func__, filepath, rv);
1.1.1.2 root 297: return 0;
298: }
299:
1.1.1.3 root 300: z.next_in = const_cast<Bytef *>(infile);
1.1.1.2 root 301: z.avail_in = infilesize - 4;
302: z.next_out = dstbuf.get();
303: z.avail_out = decompsize;
304: rv = inflate(&z, Z_NO_FLUSH);
305: if (rv != Z_OK) {
1.1.1.9 root 306: warnx("%s \"%s\" inflate failed %d", __func__, filepath, rv);
1.1.1.2 root 307: return 0;
308: }
309:
310: inflateEnd(&z);
311:
312: // 展開できたのでロード
1.1.1.7 root 313: return LoadFile(filepath, dstbuf.get(), decompsize);
1.1.1.2 root 314: }
315:
316: // file, filesize で示されるバッファを実行ファイルとみなしてゲストにロードする。
317: // ファイルのフォーマットは自動で認識する。
318: // name はここではエラーメッセージとかの表示用でしかない。
319: // 戻り値はエントリポイントアドレス。エラーなら 0 を返す。
320: uint32
1.1.1.7 root 321: RAMDevice::LoadFile(const char *name, const uint8 *file, size_t filesize)
1.1.1.2 root 322: {
323: uint32 entry = 0;
324:
325: // フォーマットだけ判定して分岐
1.1.1.3 root 326: const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)file;
327: const aout_header *aout = (const aout_header *)file;
1.1.1.2 root 328: if (memcmp(ehdr->e_ident, "\177ELF", 4) == 0) {
1.1.1.7 root 329: entry = Load_elf32(name, file, filesize);
1.1.1.11! root 330: } else if (AOUT_MAGIC(be32toh(aout->magic)) == AOUT_OMAGIC) {
1.1.1.7 root 331: entry = Load_aout(name, file, filesize);
1.1.1.2 root 332: } else {
1.1.1.9 root 333: warnx("%s \"%s\" unknown executable file format", __func__, name);
1.1.1.2 root 334: }
335:
336: return entry;
337: }
338:
339: // ホストの a.out をゲストの RAM に読み込む。
340: // 戻り値はエントリポイントアドレス。エラーなら 0 を返す。
341: uint32
1.1.1.7 root 342: RAMDevice::Load_aout(const char *name, const uint8 *file, size_t filesize)
1.1.1.2 root 343: {
344: aout_header aout;
345: int copylen;
346:
347: if (filesize < sizeof(aout)) {
1.1.1.9 root 348: warnx("%s \"%s\" file too short", __func__, name);
1.1.1.2 root 349: return 0;
350: }
351:
352: // ヘッダを読み込む
353: // BigEndian しかターゲットにしてないので最初から全部変換しとく
1.1.1.3 root 354: aout.magic = be32toh(((const aout_header *)file)->magic);
355: aout.textsize = be32toh(((const aout_header *)file)->textsize);
356: aout.datasize = be32toh(((const aout_header *)file)->datasize);
357: aout.bsssize = be32toh(((const aout_header *)file)->bsssize);
358: aout.symsize = be32toh(((const aout_header *)file)->symsize);
359: aout.entry = be32toh(((const aout_header *)file)->entry);
360: aout.textrelsize = be32toh(((const aout_header *)file)->textrelsize);
361: aout.datarelsize = be32toh(((const aout_header *)file)->datarelsize);
1.1.1.2 root 362:
1.1.1.11! root 363: if (loglevel >= 1) {
! 364: const char *mstr;
! 365: switch (AOUT_MAGIC(aout.magic)) {
! 366: case AOUT_OMAGIC: mstr = "OMAGIC"; break;
! 367: case AOUT_NMAGIC: mstr = "NMAGIC"; break;
! 368: case AOUT_ZMAGIC: mstr = "ZMAGIC"; break;
! 369: default:
! 370: mstr = "unsupported magic";
! 371: break;
! 372: }
! 373: putmsgn("%s magic = %08x (MID=0x%03x, %s)", __func__,
! 374: aout.magic, AOUT_MID(aout.magic), mstr);
! 375: putmsgn("%s textsize = %08x", __func__, aout.textsize);
! 376: putmsgn("%s datasize = %08x", __func__, aout.datasize);
! 377: putmsgn("%s bsssize = %08x", __func__, aout.bsssize);
! 378: putmsgn("%s symsize = %08x", __func__, aout.symsize);
! 379: putmsgn("%s entry = %08x", __func__, aout.entry);
! 380: putmsgn("%s textrelsize = %08x", __func__, aout.textrelsize);
! 381: putmsgn("%s datarelsize = %08x", __func__, aout.datarelsize);
! 382: }
! 383:
! 384: // MID はチェックしない。
! 385: // CPU アーキテクチャが一致するかくらいはチェックしたいところだが、
! 386: // MID は CPU ごとではなく OS(?) ごとに異なっているのと、MID の
! 387: // 一元管理された一次情報が存在しないので、正解リストを作るのが困難。
1.1.1.2 root 388:
389: // とりあえず再配置は無視
390: if (aout.textrelsize != 0 || aout.datarelsize != 0) {
1.1.1.9 root 391: warnx("%s \"%s\" relocation not supported", __func__, name);
1.1.1.2 root 392: return 0;
393: }
394:
395: // OpenBSD の boot は text+data が filesize より大きくて何かおかしいが
396: // OMAGIC の a.out は text+data が連続しているだけなので、とりあえず
397: // 何も考えずにファイルサイズ分ロードしておく。
398: copylen = aout.textsize + aout.datasize;
399: if (copylen >= filesize) {
400: copylen = filesize;
1.1.1.9 root 401: warnx("warning: %s \"%s\" corrupted? "
1.1.1.2 root 402: "(text=%u + data=%u, filesize=%d); loading %d bytes",
1.1.1.9 root 403: __func__,
1.1.1.2 root 404: name, aout.textsize, aout.datasize, (int)filesize, copylen);
405: /* FALLTHROUGH */
406: }
407:
1.1.1.7 root 408: if (aout.entry + copylen > GetSize()) {
1.1.1.9 root 409: warnx("%s \"%s\" out of memory in VM", __func__, name);
1.1.1.7 root 410: return 0;
411: }
412:
1.1.1.2 root 413: // 再配置不要なので、text + data を entry に置いて entry に飛ぶだけ
414: IODeviceStream ds(this, aout.entry);
415: const uint8 *src = file + sizeof(aout);
416: for (int i = 0; i < copylen; i++) {
417: ds.Write8(*src++);
418: }
419:
420: return aout.entry;
421: }
422:
423: // ELF フォーマットのエンディアンからホストエンディアンに変換
424: #define elf16toh(x) ((ehdr->e_ident[EI_DATA] == ELFDATA2MSB) ? \
425: be16toh(x) : le16toh(x))
426: #define elf32toh(x) ((ehdr->e_ident[EI_DATA] == ELFDATA2MSB) ? \
427: be32toh(x) : le32toh(x))
428:
1.1.1.5 root 429: // XXX このへん、そのうちきれいにする
430: #define GetElfStr1(array, v) GetElfStr(array, countof(array), v)
431: static const char *
432: GetElfStr(const std::pair<uint, const char *> *map, uint mapcount, uint v)
433: {
434: for (int i = 0; i < mapcount; i++) {
435: if (map[i].first == v) {
436: return map[i].second;
437: }
438: }
439: return "?";
440: }
441:
442: static std::pair<uint, const char *> class_str[] = {
443: { ELFCLASSNONE, "NONE" },
444: { ELFCLASS32, "32bit" },
445: { ELFCLASS64, "64bit" },
446: };
447: #define GetElfClassStr(x) GetElfStr1(class_str, (x))
448:
449: static std::pair<uint, const char *> data_str[] = {
450: { ELFDATANONE, "NONE" },
451: { ELFDATA2LSB, "LE" },
452: { ELFDATA2MSB, "BE" },
453: };
454: #define GetElfDataStr(x) GetElfStr1(data_str, (x))
455:
456: static std::pair<uint, const char *> etype_str[] = {
457: { ET_NONE, "ET_NONE" },
458: { ET_REL, "ET_REL" },
459: { ET_EXEC, "ET_EXEC" },
460: { ET_DYN, "ET_DYN" },
461: { ET_CORE, "ET_CORE" },
462: };
463: #define GetElfETypeStr(x) GetElfStr1(etype_str, (x))
464:
465: static std::pair<uint, const char *> machine_str[] = {
466: // 多いので関係分のみ
467: { EM_NONE, "NONE" },
468: { EM_68K, "Motorola 68000" },
469: { EM_88K, "Motorola 88000" },
470: };
471: #define GetElfMachineStr(x) GetElfStr1(machine_str, (x))
472:
473: static std::pair<uint, const char *> ptype_str[] = {
474: { PT_NULL, "PT_NULL" },
475: { PT_LOAD, "PT_LOAD" },
476: { PT_DYNAMIC, "PT_DYNAMIC" },
477: { PT_INTERP, "PT_INTERP" },
478: { PT_NOTE, "PT_NOTE" },
479: { PT_SHLIB, "PT_SHLIB" },
480: { PT_PHDR, "PT_PHDR" },
481: { PT_GNU_RELRO, "PT_GNU_RELRO" }, // GNU specific
482: { PT_OPENBSD_RANDOMIZE, "PT_OPENBSD_RANDOMIZE" },
483: { PT_OPENBSD_WXNEEDED, "PT_OPENBSD_WXNEEDED" },
484: { PT_OPENBSD_BOOTDATA, "PT_OPENBSD_BOOTDATA" },
485: };
486: #define GetElfPTypeStr(x) GetElfStr1(ptype_str, (x))
487:
1.1.1.9 root 488: static std::pair<uint, const char *> shtype_str[] = {
489: { SHT_NULL, "SHT_NULL" },
490: { SHT_PROGBITS, "SHT_PROGBITS" },
491: { SHT_RELA, "SHT_RELA" },
492: { SHT_NOBITS, "SHT_NOBITS" },
493: { SHT_REL, "SHT_REL" },
494: };
495: #define GetElfShTypeStr(x) GetElfStr1(shtype_str, (x))
496:
497: // ホストの ELF をゲストの RAM に読み込む。
1.1.1.2 root 498: // 戻り値はエントリポイントアドレス。エラーなら 0 を返す。
499: uint32
1.1.1.7 root 500: RAMDevice::Load_elf32(const char *name, const uint8 *file, size_t filesize)
1.1.1.2 root 501: {
502: uint16 target_elf_mid;
503:
1.1.1.7 root 504: if (gMainApp.HasVMFeature(VMF_M68K)) {
1.1.1.2 root 505: target_elf_mid = EM_68K;
1.1.1.7 root 506: } else if (gMainApp.HasVMFeature(VMF_M88K)) {
1.1.1.2 root 507: target_elf_mid = EM_88K;
1.1.1.7 root 508: } else {
509: PANIC("Unknown CPU?");
1.1.1.2 root 510: }
511:
512: // ヘッダをチェック
513: const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)file;
514: if (filesize < sizeof(*ehdr)) {
1.1.1.9 root 515: warnx("%s \"%s\" file too short", __func__, name);
1.1.1.2 root 516: return 0;
517: }
518: uint16 e_type = elf16toh(ehdr->e_type);
519: uint16 e_machine = elf16toh(ehdr->e_machine);
520: uint32 e_entry = elf32toh(ehdr->e_entry);
1.1.1.5 root 521: if (loglevel >= 1) {
522: uint n;
523: n = ehdr->e_ident[EI_CLASS];
1.1.1.7 root 524: putlogn("EI_CLASS = $%02x (%s)", n, GetElfClassStr(n));
1.1.1.5 root 525: n = ehdr->e_ident[EI_DATA];
1.1.1.7 root 526: putlogn("EI_DATA = $%02x (%s)", n, GetElfDataStr(n));
1.1.1.5 root 527:
1.1.1.7 root 528: putlogn("e_type = $%02x (%s)", e_type, GetElfETypeStr(e_type));
529: putlogn("e_machine = $%02x (%s)", e_machine,
1.1.1.5 root 530: GetElfMachineStr(e_machine));
1.1.1.7 root 531: putlogn("e_entry = $%08x", e_entry);
1.1.1.5 root 532: }
1.1.1.2 root 533:
534: if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
1.1.1.9 root 535: warnx("%s \"%s\" not ELF32 format", __func__, name);
1.1.1.2 root 536: return 0;
537: }
538: if (e_machine != target_elf_mid) {
1.1.1.9 root 539: warnx("%s \"%s\" machine type mismatch "
540: "($%02x expected but $%02x)", __func__,
1.1.1.2 root 541: name, target_elf_mid, e_machine);
542: return 0;
543: }
544:
1.1.1.9 root 545: switch (e_type) {
546: case ET_EXEC:
547: if (Load_elf32_exec(name, file, filesize)) {
548: return e_entry;
549: }
550: break;
551: case ET_REL:
552: return Load_elf32_rel(name, file, filesize);
553: default:
554: warnx("%s \"%s\" unsupported file type", __func__, name);
555: break;
556: }
557: return 0;
558: }
559:
560: // ホストの ELF 実行形式ファイルをゲストの RAM に読み込む。
561: // 読み込めたら true、エラーなら false を返す。
562: // エントリポイントは呼び出し元が知っているのでこっちでは関与しない。
563: bool
564: RAMDevice::Load_elf32_exec(const char *name, const uint8 *file, size_t filesize)
565: {
566: const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)file;
567:
1.1.1.2 root 568: // プログラムヘッダに読み込むべき領域が示されている
569: // phoff がプログラムヘッダのファイル先頭からのオフセット
570: // phentsize がプログラムヘッダ1つの大きさ
571: // phnum がプログラムヘッダの個数
572: uint32 e_phoff = elf32toh(ehdr->e_phoff);
573: uint16 e_phentsize = elf16toh(ehdr->e_phentsize);
574: uint16 e_phnum = elf16toh(ehdr->e_phnum);
1.1.1.5 root 575: if (loglevel >= 1) {
1.1.1.7 root 576: putlogn("e_phoff = $%08x", e_phoff);
577: putlogn("e_phentsize = $%04x", e_phentsize);
578: putlogn("e_phnum = %d", e_phnum);
1.1.1.5 root 579: }
1.1.1.2 root 580: if (e_phentsize != sizeof(Elf32_Phdr)) {
1.1.1.9 root 581: warnx("%s \"%s\" unknown program header size 0x%x", __func__,
1.1.1.2 root 582: name, e_phentsize);
1.1.1.9 root 583: return false;
1.1.1.2 root 584: }
585:
586: IODeviceStream ds(this);
587:
588: for (int j = 0; j < e_phnum; j++) {
589: const Elf32_Phdr *phdr = &((const Elf32_Phdr*)(file + e_phoff))[j];
590: // p_type が PT_LOAD なところをロードする。
591: // その際 p_memsz > p_filesz なら差が BSS 領域。
592: uint32 p_type = elf32toh(phdr->p_type); // タイプ
593: uint32 p_offset = elf32toh(phdr->p_offset); // ファイル上のオフセット
594: uint32 p_vaddr = elf32toh(phdr->p_vaddr); // 仮想アドレス
595: uint32 p_filesz = elf32toh(phdr->p_filesz); // 読み込み元ファイルサイズ
596: uint32 p_memsz = elf32toh(phdr->p_memsz); // 書き込み先サイズ
1.1.1.5 root 597: if (loglevel >= 1) {
1.1.1.7 root 598: putlogn("[%d] p_type = $%08x (%s)", j,
1.1.1.5 root 599: p_type, GetElfPTypeStr(p_type));
1.1.1.7 root 600: putlogn(" p_offset = $%08x", p_offset);
601: putlogn(" p_vaddr = $%08x", p_vaddr);
602: putlogn(" p_filesz = $%08x", p_filesz);
603: putlogn(" p_memsz = $%08x", p_memsz);
1.1.1.5 root 604: }
1.1.1.2 root 605:
606: if (p_type == PT_LOAD) {
1.1.1.7 root 607: if (p_vaddr + p_memsz > GetSize()) {
1.1.1.9 root 608: warnx("%s \"%s\" out of memory in VM", __func__, name);
609: return false;
1.1.1.7 root 610: }
611:
1.1.1.2 root 612: ds.SetAddr(p_vaddr);
613: const uint8 *src = file + p_offset;
614: int i = 0;
615: for (; i < p_filesz; i++) {
616: ds.Write8(*src++);
617: }
618: for (; i < p_memsz; i++) {
619: ds.Write8(0);
620: }
1.1.1.5 root 621: } else if (p_type == PT_NOTE) {
622: // ベンダー文字列みたいなのらしいので無視してよい
623: continue;
624: } else if (p_type == PT_OPENBSD_RANDOMIZE) {
1.1.1.3 root 625: // XXX どうする?
626: continue;
627:
1.1.1.2 root 628: } else {
1.1.1.9 root 629: warnx("%s \"%s\" p_type 0x%x(%s) not supported", __func__,
1.1.1.5 root 630: name, p_type, GetElfPTypeStr(p_type));
1.1.1.9 root 631: return false;
632: }
633: }
634:
635: return true;
636: }
637:
638: // ホストの ELF オブジェクトの text セクションをゲストの RAM に読み込む。
639: // .o(オブジェクトファイル) 用。
640: // 読み込めたら true、エラーなら false を返す。
641: // 戻り値はエントリポイントアドレス。エラーなら 0 を返す。
642: uint32
643: RAMDevice::Load_elf32_rel(const char *name, const uint8 *file, size_t filesize)
644: {
645: const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)file;
646: uint32 entry = 0x20000;
647:
648: uint32 e_shoff = elf32toh(ehdr->e_shoff);
649: uint16 e_shentsize = elf16toh(ehdr->e_shentsize);
650: uint16 e_shnum = elf16toh(ehdr->e_shnum);
651: if (loglevel >= 1) {
652: putlogn("e_shoff = $%08x", e_shoff);
653: putlogn("e_shentsize = $%04x", e_shentsize);
654: putlogn("e_shnum = %d", e_shnum);
655: }
656: if (e_shentsize != sizeof(Elf32_Shdr)) {
657: warnx("%s \"%s\" unknown section header size 0x%x", __func__,
658: name, e_shentsize);
659: return 0;
660: }
661:
662: IODeviceStream ds(this);
663: ds.SetAddr(entry);
664:
665: for (int j = 0; j < e_shnum; j++) {
666: const Elf32_Shdr *shdr = &((const Elf32_Shdr*)(file + e_shoff))[j];
667: // sh_type
668: uint32 sh_type = elf32toh(shdr->sh_type); // タイプ
669: uint32 sh_addr = elf32toh(shdr->sh_addr); // アドレス
670: uint32 sh_offset = elf32toh(shdr->sh_offset); // ファイル先頭から
671: uint32 sh_size = elf32toh(shdr->sh_size); // サイズ
672: if (loglevel >= 1) {
673: putlogn("[%d] sh_type = $%08x (%s)", j,
674: sh_type, GetElfShTypeStr(sh_type));
675: putlogn(" sh_addr = $%08x", sh_addr);
676: putlogn(" sh_offset = $%08x", sh_offset);
677: putlogn(" sh_size = $%08x", sh_size);
678: }
679:
680: if (sh_type == SHT_PROGBITS) {
681: const uint8 *src = file + sh_offset;
682: int i = 0;
683: for (; i < sh_size; i++) {
684: ds.Write8(*src++);
685: }
686: } else if (sh_type == SHT_RELA || sh_type == SHT_REL) {
687: // 再配置情報があるのは .R 形式ではない
688: warnx("%s \"%s\" has relocation section", __func__, name);
1.1.1.2 root 689: return 0;
1.1.1.9 root 690: } else {
691: // ?
1.1.1.2 root 692: }
693: }
694:
1.1.1.9 root 695: return entry;
1.1.1.2 root 696: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.