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

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

unix.superglobalmegacorp.com

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