Annotation of nono/vm/ram.cpp, revision 1.1.1.9

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.