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

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()
                     30: {
                     31:        logname = "ram";
                     32:        devname = "MainRAM";
                     33:        devaddr = 0;
                     34: 
1.1.1.4   root       35:        // アクセスウェイト
                     36:        switch (gMainApp.GetVMType()) {
                     37:         case VMTYPE_LUNA88K:
                     38:                // 取扱説明書p.21 に、CMMU からのアクセスタイムが
                     39:                // リード(4byte)で 200ns、バーストリード(16byte)で 320ns
                     40:                // ライト(4byte)で 160ns、バーストライト(16byte)で 280ns とある。
                     41:                // 25MHz は 40ns/clockで、この数値は CMMU からのアクセス全体の時間
                     42:                // らしいので、ここで加算するウェイトはそれから 2クロック引いたもの。
                     43:                read_wait  = 3;
                     44:                write_wait = 2;
                     45:                break;
                     46:         case VMTYPE_LUNA1:
                     47:                // LUNA-I は1ウェイト。
                     48:                read_wait  = 1;
                     49:                write_wait = 1;
                     50:                break;
                     51: 
                     52:         case VMTYPE_X68030:
                     53:         default:
                     54:                // X68030 ではシステムポートが設定するのでここでは不要。
                     55:                break;
                     56:        }
1.1       root       57: }
                     58: 
                     59: RAMDevice::~RAMDevice()
                     60: {
                     61: }
                     62: 
                     63: bool
                     64: RAMDevice::Init()
                     65: {
1.1.1.4   root       66:        int ram_size_MB;
                     67: 
                     68:        const ConfigItem& item = gConfig->Find("ram-size");
                     69:        ram_size_MB = item.AsInt();
1.1.1.7   root       70:        if (ram_size_MB < 1) {
1.1.1.3   root       71:                item.Err();
                     72:                return false;
1.1       root       73:        }
1.1.1.7   root       74:        // 下限以外の制約は機種による
                     75:        switch (gMainApp.GetVMType()) {
                     76:         case VMTYPE_X68030:
                     77:                // メインメモリは 12MB まで。
                     78:                // 内部は 8KB 単位で処理できるが設定が 1MB 単位。
                     79:                if (ram_size_MB > 12) {
                     80:                        item.Err();
                     81:                        return false;
                     82:                }
                     83:                break;
                     84: 
                     85:         case VMTYPE_LUNA1:
                     86:                // 16MB までは、実機に合わせて 4MB 単位とする。
                     87:                // see http://wiki.netbsd.org/ports/luna68k/luna68k_info/#hardware
                     88:                //
                     89:                // 16MB を超える増設 (or 魔改造) 部分は 1MB 単位で 255MB までとする。
                     90:                // 実 ROM のメモリチェックは 32KB だかそのくらいずつ行われ、
                     91:                // 最後に番兵として Null 領域 (BusError ではなく) が必要。
                     92:                // 現行の構成をあまり変えない範囲なら厳密には (256MB - 32KB) が
                     93:                // 上限だが、設定ファイルからの指定が 1MB 単位なので 255MB。
                     94:                if (ram_size_MB <= 16) {
                     95:                        if (ram_size_MB % 4 != 0) {
                     96:                                item.Err();
                     97:                                return false;
                     98:                        }
                     99:                } else if (ram_size_MB > 255) {
                    100:                        item.Err();
                    101:                        return false;
                    102:                }
                    103:                break;
                    104: 
                    105:         case VMTYPE_LUNA88K:
                    106:                // 64MB までは、実機に合わせて 16MB 単位とする。
                    107:                //
                    108:                // 64MB を超える増設 (or 魔改造) 部分は未確認。
                    109:                if (ram_size_MB <= 64) {
                    110:                        if (ram_size_MB % 16 != 0) {
                    111:                                item.Err();
                    112:                                return false;
                    113:                        }
                    114:                } else if (ram_size_MB > 255) {
                    115:                        item.Err();
                    116:                        return false;
                    117:                }
                    118:                break;
                    119: 
                    120:         default:
                    121:                __unreachable();
                    122:        }
1.1.1.3   root      123: 
1.1.1.4   root      124:        ram_size = ram_size_MB * 1024 * 1024;
1.1.1.8 ! root      125:        mainram.reset(new uint8[ram_size]);
1.1       root      126: 
1.1.1.7   root      127:        // devtable[] への RAM デバイスの配置はこの後 VM::Init 側で行っている
                    128: 
1.1       root      129:        return true;
                    130: }
                    131: 
1.1.1.8 ! root      132: bool
        !           133: RAMDevice::PowerOn()
        !           134: {
        !           135:        // XXX ノイズを用意する
        !           136: 
        !           137:        return true;
        !           138: }
        !           139: 
1.1.1.4   root      140: void
                    141: RAMDevice::ResetHard()
                    142: {
                    143:        // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない)
                    144:        if (gMainApp.GetVMType() == VMTYPE_X68030) {
                    145:                read_wait  = 0;
                    146:                write_wait = 0;
                    147:        }
                    148: }
                    149: 
1.1       root      150: uint64
                    151: RAMDevice::Read8(uint32 addr)
                    152: {
1.1.1.4   root      153:        gMPU->AddCycle(read_wait);
1.1       root      154:        uint32 data;
1.1.1.8 ! root      155:        data = mainram[HLB(addr)];
1.1.1.6   root      156:        putlog(4, "$%08x.B -> $%02x", addr, data);
1.1       root      157:        return data;
                    158: }
                    159: 
                    160: uint64
                    161: RAMDevice::Read16(uint32 addr)
                    162: {
1.1.1.4   root      163:        gMPU->AddCycle(read_wait);
1.1       root      164:        uint32 data;
1.1.1.8 ! root      165:        data = *(uint16 *)&mainram[HLW(addr)];
1.1.1.6   root      166:        putlog(4, "$%08x.W -> $%04x", addr, data);
1.1       root      167:        return data;
                    168: }
                    169: 
                    170: uint64
                    171: RAMDevice::Read32(uint32 addr)
                    172: {
1.1.1.4   root      173:        gMPU->AddCycle(read_wait);
1.1       root      174:        uint32 data;
1.1.1.8 ! root      175:        data = *(uint32 *)&mainram[addr];
1.1.1.6   root      176:        putlog(4, "$%08x.L -> $%08x", addr, data);
1.1       root      177:        return data;
                    178: }
                    179: 
                    180: uint64
                    181: RAMDevice::Write8(uint32 addr, uint32 data)
                    182: {
1.1.1.4   root      183:        gMPU->AddCycle(write_wait);
1.1.1.8 ! root      184:        mainram[HLB(addr)] = data;
1.1.1.6   root      185:        putlog(3, "$%08x.B <- $%02x", addr, data);
1.1       root      186:        return 0;
                    187: }
                    188: 
                    189: uint64
                    190: RAMDevice::Write16(uint32 addr, uint32 data)
                    191: {
1.1.1.4   root      192:        gMPU->AddCycle(write_wait);
1.1.1.8 ! root      193:        *(uint16 *)&mainram[HLW(addr)] = data;
1.1.1.6   root      194:        putlog(3, "$%08x.W <- $%04x", addr, data);
1.1       root      195:        return 0;
                    196: }
                    197: 
                    198: uint64
                    199: RAMDevice::Write32(uint32 addr, uint32 data)
                    200: {
1.1.1.4   root      201:        gMPU->AddCycle(write_wait);
1.1.1.8 ! root      202:        *(uint32 *)&mainram[addr] = data;
1.1.1.6   root      203:        putlog(3, "$%08x.L <- $%08x", addr, data);
1.1       root      204:        return 0;
                    205: }
                    206: 
                    207: uint64
                    208: RAMDevice::Peek8(uint32 addr)
                    209: {
1.1.1.8 ! root      210:        return mainram[HLB(addr)];
1.1       root      211: }
1.1.1.2   root      212: 
1.1.1.4   root      213: // アクセスウェイトを設定 (X68030 でシステムポートから呼ばれる)
                    214: void
                    215: RAMDevice::SetWait(uint32 wait)
                    216: {
                    217:        read_wait  = wait;
                    218:        write_wait = wait;
                    219: }
                    220: 
1.1.1.2   root      221: // filepath で指定されるホストの実行ファイルをゲストにロードする。
                    222: // ファイルのフォーマットは自動で認識する。
                    223: // 戻り値はエントリポイントアドレス。エラーなら 0 を返す。
                    224: uint32
1.1.1.7   root      225: RAMDevice::LoadFile(const char *filepath)
1.1.1.2   root      226: {
                    227:        uint8 *file;
                    228:        struct stat st;
                    229:        size_t filesize;
                    230:        uint32 entry;
1.1.1.7   root      231:        autofd fd;
1.1.1.2   root      232: 
                    233:        fd = open(filepath, O_RDONLY);
                    234:        if (fd == -1) {
                    235:                warn("LoadFile \"%s\" open failed", filepath);
                    236:                return 0;
                    237:        }
                    238: 
                    239:        if (fstat(fd, &st) == -1) {
                    240:                warn("LoadFile \"%s\" fstat failed", filepath);
                    241:                return 0;
                    242:        }
                    243: 
                    244:        if (!S_ISREG(st.st_mode)) {
                    245:                warnx("LoadFile \"%s\" not a regular file", filepath);
                    246:                return 0;
                    247:        }
                    248: 
                    249:        // 今の所マジック判定は最初の4バイトで出来るので
                    250:        if (st.st_size < 4) {
                    251:                warnx("LoadFile \"%s\" file too short", filepath);
                    252:                return 0;
                    253:        }
                    254:        filesize = st.st_size;
                    255: 
                    256:        file = (uint8 *)mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
                    257:        if (file == MAP_FAILED) {
                    258:                warn("LoadFile \"%s\" mmap failed", filepath);
                    259:                return 0;
                    260:        }
                    261: 
                    262:        // 先頭3バイトの gzip マジックを調べる
                    263:        if (file[0] == 0x1f && file[1] == 0x8b && file[2] == 0x08) {
                    264:                // gzip
1.1.1.7   root      265:                entry = LoadGzFile(filepath, file, filesize);
1.1.1.2   root      266:        } else {
                    267:                // 通常ファイル
1.1.1.7   root      268:                entry = LoadFile(filepath, file, filesize);
1.1.1.2   root      269:        }
                    270: 
                    271:        munmap(file, filesize);
                    272:        return entry;
                    273: }
                    274: 
                    275: // gzip を展開してゲストにロードする。
                    276: uint32
1.1.1.7   root      277: RAMDevice::LoadGzFile(const char *filepath, const uint8 *infile,
                    278:        size_t infilesize)
1.1.1.2   root      279: {
                    280:        z_stream z {};
                    281:        uint32 decompsize;
                    282:        int rv;
                    283: 
                    284:        // gzip なら(?) ファイルの末尾4バイトが (LE で?) 展開後サイズ(?)。
1.1.1.3   root      285:        decompsize = le32toh(*(const uint32 *)&infile[infilesize - 4]);
1.1.1.2   root      286:        std::unique_ptr<uint8[]> dstbuf(new uint8[decompsize]);
                    287: 
                    288:        // gzip 展開
                    289:        // (uncompress() の方が楽そうに見えるが gzip 形式に対応してないらしい)
                    290:        z.zalloc = Z_NULL;
                    291:        z.zfree = Z_NULL;
                    292:        z.opaque = Z_NULL;
                    293:        rv = inflateInit2(&z, 47);
                    294:        if (rv != Z_OK) {
                    295:                warnx("LoadGzFile \"%s\" inflateInit2 failed %d", filepath, rv);
                    296:                return 0;
                    297:        }
                    298: 
1.1.1.3   root      299:        z.next_in = const_cast<Bytef *>(infile);
1.1.1.2   root      300:        z.avail_in = infilesize - 4;
                    301:        z.next_out = dstbuf.get();
                    302:        z.avail_out = decompsize;
                    303:        rv = inflate(&z, Z_NO_FLUSH);
                    304:        if (rv != Z_OK) {
                    305:                warnx("LoadGzFile \"%s\" inflate failed %d", filepath, rv);
                    306:                return 0;
                    307:        }
                    308: 
                    309:        inflateEnd(&z);
                    310: 
                    311:        // 展開できたのでロード
1.1.1.7   root      312:        return LoadFile(filepath, dstbuf.get(), decompsize);
1.1.1.2   root      313: }
                    314: 
                    315: // file, filesize で示されるバッファを実行ファイルとみなしてゲストにロードする。
                    316: // ファイルのフォーマットは自動で認識する。
                    317: // name はここではエラーメッセージとかの表示用でしかない。
                    318: // 戻り値はエントリポイントアドレス。エラーなら 0 を返す。
                    319: uint32
1.1.1.7   root      320: RAMDevice::LoadFile(const char *name, const uint8 *file, size_t filesize)
1.1.1.2   root      321: {
                    322:        uint32 entry = 0;
                    323: 
                    324:        // フォーマットだけ判定して分岐
1.1.1.3   root      325:        const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)file;
                    326:        const aout_header *aout = (const aout_header *)file;
1.1.1.2   root      327:        if (memcmp(ehdr->e_ident, "\177ELF", 4) == 0) {
1.1.1.7   root      328:                entry = Load_elf32(name, file, filesize);
1.1.1.2   root      329:        } else if ((be32toh(aout->magic) & 0xffff) == AOUT_OMAGIC) {
1.1.1.7   root      330:                entry = Load_aout(name, file, filesize);
1.1.1.2   root      331:        } else {
                    332:                warnx("LoadFile \"%s\" unknown executable file format", name);
                    333:        }
                    334: 
                    335:        return entry;
                    336: }
                    337: 
                    338: // ホストの a.out をゲストの RAM に読み込む。
                    339: // 戻り値はエントリポイントアドレス。エラーなら 0 を返す。
                    340: uint32
1.1.1.7   root      341: RAMDevice::Load_aout(const char *name, const uint8 *file, size_t filesize)
1.1.1.2   root      342: {
                    343:        aout_header aout;
                    344:        int copylen;
                    345: 
                    346:        if (filesize < sizeof(aout)) {
                    347:                warnx("Load_aout \"%s\" file too short", name);
                    348:                return 0;
                    349:        }
                    350: 
                    351:        // ヘッダを読み込む
                    352:        // BigEndian しかターゲットにしてないので最初から全部変換しとく
1.1.1.3   root      353:        aout.magic       = be32toh(((const aout_header *)file)->magic);
                    354:        aout.textsize    = be32toh(((const aout_header *)file)->textsize);
                    355:        aout.datasize    = be32toh(((const aout_header *)file)->datasize);
                    356:        aout.bsssize     = be32toh(((const aout_header *)file)->bsssize);
                    357:        aout.symsize     = be32toh(((const aout_header *)file)->symsize);
                    358:        aout.entry       = be32toh(((const aout_header *)file)->entry);
                    359:        aout.textrelsize = be32toh(((const aout_header *)file)->textrelsize);
                    360:        aout.datarelsize = be32toh(((const aout_header *)file)->datarelsize);
1.1.1.2   root      361: 
                    362:        // マジックをチェック
1.1.1.7   root      363:        uint32 target_mid;
                    364:        if (gMainApp.HasVMFeature(VMF_M68K)) {
                    365:                target_mid = AOUT_MID_M68K;
                    366:        } else if (gMainApp.HasVMFeature(VMF_M88K)) {
                    367:                target_mid = AOUT_MID_M88K;
                    368:        } else {
                    369:                PANIC("Unknown CPU?");
                    370:        }
1.1.1.2   root      371:        uint32 mid = AOUT_MID(aout.magic);
                    372:        if (mid != target_mid) {
                    373:                warnx("Load_aout \"%s\" machine id mismatch (%03x expected but %03x)",
                    374:                        name, target_mid, mid);
                    375:                return 0;
                    376:        }
                    377: 
                    378:        putmsg(1, "%s textsize    = %08x", __func__, aout.textsize);
                    379:        putmsg(1, "%s datasize    = %08x", __func__, aout.datasize);
                    380:        putmsg(1, "%s bsssize     = %08x", __func__, aout.bsssize);
                    381:        putmsg(1, "%s symsize     = %08x", __func__, aout.symsize);
                    382:        putmsg(1, "%s entry       = %08x", __func__, aout.entry);
                    383:        putmsg(1, "%s textrelsize = %08x", __func__, aout.textrelsize);
                    384:        putmsg(1, "%s datarelsize = %08x", __func__, aout.datarelsize);
                    385: 
                    386:        // とりあえず再配置は無視
                    387:        if (aout.textrelsize != 0 || aout.datarelsize != 0) {
                    388:                warnx("Load_aout \"%s\" relocation not supported", name);
                    389:                return 0;
                    390:        }
                    391: 
                    392:        // OpenBSD の boot は text+data が filesize より大きくて何かおかしいが
                    393:        // OMAGIC の a.out は text+data が連続しているだけなので、とりあえず
                    394:        // 何も考えずにファイルサイズ分ロードしておく。
                    395:        copylen = aout.textsize + aout.datasize;
                    396:        if (copylen >= filesize) {
                    397:                copylen = filesize;
1.1.1.8 ! root      398:                warnx("warning: Load_aout \"%s\" corrupted? "
1.1.1.2   root      399:                      "(text=%u + data=%u, filesize=%d); loading %d bytes",
                    400:                        name, aout.textsize, aout.datasize, (int)filesize, copylen);
                    401:                /* FALLTHROUGH */
                    402:        }
                    403: 
1.1.1.7   root      404:        if (aout.entry + copylen > GetSize()) {
                    405:                warnx("Load_aout \"%s\" out of memory in VM", name);
                    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.2   root      484: // ホストの a.out をゲストの RAM に読み込む。
                    485: // 戻り値はエントリポイントアドレス。エラーなら 0 を返す。
                    486: uint32
1.1.1.7   root      487: RAMDevice::Load_elf32(const char *name, const uint8 *file, size_t filesize)
1.1.1.2   root      488: {
                    489:        uint16 target_elf_mid;
                    490: 
1.1.1.7   root      491:        if (gMainApp.HasVMFeature(VMF_M68K)) {
1.1.1.2   root      492:                target_elf_mid = EM_68K;
1.1.1.7   root      493:        } else if (gMainApp.HasVMFeature(VMF_M88K)) {
1.1.1.2   root      494:                target_elf_mid = EM_88K;
1.1.1.7   root      495:        } else {
                    496:                PANIC("Unknown CPU?");
1.1.1.2   root      497:        }
                    498: 
                    499:        // ヘッダをチェック
                    500:        const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)file;
                    501:        if (filesize < sizeof(*ehdr)) {
                    502:                warnx("Load_elf32 \"%s\" file too short", name);
                    503:                return 0;
                    504:        }
                    505:        uint16 e_type    = elf16toh(ehdr->e_type);
                    506:        uint16 e_machine = elf16toh(ehdr->e_machine);
                    507:        uint32 e_entry   = elf32toh(ehdr->e_entry);
1.1.1.5   root      508:        if (loglevel >= 1) {
                    509:                uint n;
                    510:                n = ehdr->e_ident[EI_CLASS];
1.1.1.7   root      511:                putlogn("EI_CLASS    = $%02x (%s)", n, GetElfClassStr(n));
1.1.1.5   root      512:                n = ehdr->e_ident[EI_DATA];
1.1.1.7   root      513:                putlogn("EI_DATA     = $%02x (%s)", n, GetElfDataStr(n));
1.1.1.5   root      514: 
1.1.1.7   root      515:                putlogn("e_type      = $%02x (%s)", e_type, GetElfETypeStr(e_type));
                    516:                putlogn("e_machine   = $%02x (%s)", e_machine,
1.1.1.5   root      517:                        GetElfMachineStr(e_machine));
1.1.1.7   root      518:                putlogn("e_entry     = $%08x", e_entry);
1.1.1.5   root      519:        }
1.1.1.2   root      520: 
                    521:        if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
                    522:                warnx("Load_elf32 \"%s\" not ELF32 format", name);
                    523:                return 0;
                    524:        }
                    525:        if (e_type != ET_EXEC) {
                    526:                warnx("Load_elf32 \"%s\" not executable file", name);
                    527:                return 0;
                    528:        }
                    529:        if (e_machine != target_elf_mid) {
                    530:                warnx("Load_elf32 \"%s\" machine type mismatch "
                    531:                        "($%02x expected but $%02x)",
                    532:                        name, target_elf_mid, e_machine);
                    533:                return 0;
                    534:        }
                    535: 
                    536:        // プログラムヘッダに読み込むべき領域が示されている
                    537:        // phoff がプログラムヘッダのファイル先頭からのオフセット
                    538:        // phentsize がプログラムヘッダ1つの大きさ
                    539:        // phnum がプログラムヘッダの個数
                    540:        uint32 e_phoff     = elf32toh(ehdr->e_phoff);
                    541:        uint16 e_phentsize = elf16toh(ehdr->e_phentsize);
                    542:        uint16 e_phnum     = elf16toh(ehdr->e_phnum);
1.1.1.5   root      543:        if (loglevel >= 1) {
1.1.1.7   root      544:                putlogn("e_phoff     = $%08x", e_phoff);
                    545:                putlogn("e_phentsize = $%04x", e_phentsize);
                    546:                putlogn("e_phnum     = %d",    e_phnum);
1.1.1.5   root      547:        }
1.1.1.2   root      548:        if (e_phentsize != sizeof(Elf32_Phdr)) {
                    549:                warnx("Load_elf32 \"%s\" unknown program header size 0x%x",
                    550:                        name, e_phentsize);
                    551:                return 0;
                    552:        }
                    553: 
                    554:        IODeviceStream ds(this);
                    555: 
                    556:        for (int j = 0; j < e_phnum; j++) {
                    557:                const Elf32_Phdr *phdr = &((const Elf32_Phdr*)(file + e_phoff))[j];
                    558:                // p_type が PT_LOAD なところをロードする。
                    559:                // その際 p_memsz > p_filesz なら差が BSS 領域。
                    560:                uint32 p_type   = elf32toh(phdr->p_type);       // タイプ
                    561:                uint32 p_offset = elf32toh(phdr->p_offset);     // ファイル上のオフセット
                    562:                uint32 p_vaddr  = elf32toh(phdr->p_vaddr);      // 仮想アドレス
                    563:                uint32 p_filesz = elf32toh(phdr->p_filesz);     // 読み込み元ファイルサイズ
                    564:                uint32 p_memsz  = elf32toh(phdr->p_memsz);      // 書き込み先サイズ
1.1.1.5   root      565:                if (loglevel >= 1) {
1.1.1.7   root      566:                        putlogn("[%d] p_type   = $%08x (%s)", j,
1.1.1.5   root      567:                                p_type, GetElfPTypeStr(p_type));
1.1.1.7   root      568:                        putlogn("    p_offset = $%08x", p_offset);
                    569:                        putlogn("    p_vaddr  = $%08x", p_vaddr);
                    570:                        putlogn("    p_filesz = $%08x", p_filesz);
                    571:                        putlogn("    p_memsz  = $%08x", p_memsz);
1.1.1.5   root      572:                }
1.1.1.2   root      573: 
                    574:                if (p_type == PT_LOAD) {
1.1.1.7   root      575:                        if (p_vaddr + p_memsz > GetSize()) {
                    576:                                warn("Load_elf32 \"%s\" out of memory in VM", name);
                    577:                                return 0;
                    578:                        }
                    579: 
1.1.1.2   root      580:                        ds.SetAddr(p_vaddr);
                    581:                        const uint8 *src = file + p_offset;
                    582:                        int i = 0;
                    583:                        for (; i < p_filesz; i++) {
                    584:                                ds.Write8(*src++);
                    585:                        }
                    586:                        for (; i < p_memsz; i++) {
                    587:                                ds.Write8(0);
                    588:                        }
1.1.1.5   root      589:                } else if (p_type == PT_NOTE) {
                    590:                        // ベンダー文字列みたいなのらしいので無視してよい
                    591:                        continue;
                    592:                } else if (p_type == PT_OPENBSD_RANDOMIZE) {
1.1.1.3   root      593:                        // XXX どうする?
                    594:                        continue;
                    595: 
1.1.1.2   root      596:                } else {
1.1.1.5   root      597:                        warnx("Load_elf32 \"%s\" p_type 0x%x(%s) not supported",
                    598:                                name, p_type, GetElfPTypeStr(p_type));
1.1.1.2   root      599:                        return 0;
                    600:                }
                    601:        }
                    602: 
                    603:        return e_entry;
                    604: }

unix.superglobalmegacorp.com

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