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