Annotation of nono/vm/romemu_luna.cpp, revision 1.1.1.6

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.2   root        7: // LUNA-I の ROM エミュレーション
                      8: 
                      9: //             IODevice
                     10: //                |
                     11: //     +----------+----------+
                     12: //     v                     v
                     13: // ROMDevice          LunaPROMEmuDeivce (ROM エミュレーション)
                     14: //     |
                     15: //     v
                     16: // PROMDevice (実ROM)
                     17: 
                     18: #include "romemu_luna.h"
1.1       root       19: #include "aout.h"
                     20: #include "bitmap.h"
                     21: #include "bt454.h"
1.1.1.2   root       22: #include "ethernet.h"
1.1       root       23: #include "ffs_dinode.h"
                     24: #include "ffs_dir.h"
                     25: #include "ffs_fs.h"
                     26: #include "mainapp.h"
                     27: #include "memorystream.h"
                     28: #include "mk48t02.h"
1.1.1.2   root       29: #include "mpu680x0.h"
1.1       root       30: #include "pio.h"
                     31: #include "ram.h"
                     32: #include "sio.h"
                     33: #include "spc.h"
                     34: 
                     35: // ROM エミュレーションの状態遷移
                     36: enum {
                     37:        STATE_CLOSED = 0,       // バックドアは塞がれている
                     38:        STATE_RESET,            // リセット後、アクセス前
                     39:        STATE_INIT,                     // プロンプト初期化中
                     40:        STATE_PROMPT,           // プロンプト実行中
                     41: };
                     42: 
                     43: // コンストラクタ
                     44: LunaPROMEmuDevice::LunaPROMEmuDevice()
                     45: {
1.1.1.6 ! root       46:        logname = "prom";
        !            47:        devname = "PROM";
        !            48: 
1.1.1.2   root       49:        // LUNA-I の ROM の特定アドレスを読み出す人がいるので、
                     50:        // サイズは実 ROM と同じにしておく必要がある。
                     51:        devlen = 128 * 1024;
                     52:        romdata.reset(new uint8 [devlen]);
1.1       root       53: }
                     54: 
                     55: // デストラクタ
                     56: LunaPROMEmuDevice::~LunaPROMEmuDevice()
                     57: {
                     58: }
                     59: 
                     60: bool
                     61: LunaPROMEmuDevice::Init()
                     62: {
                     63:        // 都度都度 dynamic_cast は面倒なので、ここで一度代入しとく
                     64:        nvram = dynamic_cast<MK48T02Device*>(gRTC.get());
                     65: 
1.1.1.2   root       66:        MemoryStreamBE ms(romdata.get());
1.1       root       67:        ms.Write32(0x00002000);         // +00: リセットベクタ SP
                     68:        ms.Write32(0x41000400);         // +04: リセットベクタ PC
                     69:        ms.Write32(0);                          // +08
                     70:        ms.Write32(0x41000500);         // +0c: メモリサイズ格納先
                     71: 
                     72:        // リセット時に実行する命令
1.1.1.2   root       73:        ms.SetPtr(&romdata[0x400]);
                     74:        ms.Write16(0x2039);                     //      move.l  (ROMIO_INIT),d0
                     75:        ms.Write32(ROMIO_INIT);
                     76:        ms.Write16(0x660c);                     //      bne             _go             ; 起動先あればGO
1.1       root       77:                                                                //_prompt:
1.1.1.2   root       78:        ms.Write32(0x4e722500);         //      stop    #0x2500 ; キー入力を待つ
1.1.1.6 ! root       79:        ms.Write16(0x2039);                     //      move.l  (ROMIO_ENTRY),d0
        !            80:        ms.Write32(ROMIO_ENTRY);        //                                      ; キー入力処理
1.1.1.2   root       81:        ms.Write16(0x67f4);                     //      beq             _prompt ; 起動先なければループ
1.1       root       82:                                                                //_go:
                     83:        ms.Write16(0x2040);                     //      move.l  d0,a0   ; ジャンプ先を a0 にセット
1.1.1.2   root       84:        ms.Write16(0x2039);                     //      move.l  (ROMIO_CLOSE),d0
                     85:        ms.Write32(ROMIO_CLOSE);        //                                      ; 後始末
1.1       root       86:        ms.Write16(0x4ed0);                     //      jmp             (a0)    ; ジャンプ
                     87: 
                     88:        // Lv6 (SIO) 割り込みハンドラ
1.1.1.6 ! root       89:        // キーボード割り込みが上がったら KEYIN をコールする
1.1.1.2   root       90:        ms.SetPtr(&romdata[0x600]);
1.1.1.6 ! root       91:        ms.Write16(0x4ab9);                     //      tst.l   (ROMIO_KEYIN)
        !            92:        ms.Write32(ROMIO_KEYIN);        //                                      ; キー入力処理
1.1       root       93:        ms.Write16(0x4e73);                     //      rte
                     94: 
1.1.1.2   root       95:        // MAC アドレス
                     96:        const macaddr_t macaddr = gEthernet->GetMacAddr();
                     97:        strcpy((char *)&romdata[0x1ffd8], "ENADDR");
                     98:        memcpy(&romdata[0x1ffe0], macaddr.to_string().c_str(), 12);
1.1       root       99: 
                    100:        // RAM にベクタを書き込む
                    101:        // XXX VBR を 41000000 に向けるのとどっちが楽かはある
                    102:        gRAM->Write32(0x78, 0x41000600);        // +78: Lv6 割り込み
                    103: 
                    104:        return true;
                    105: }
                    106: 
                    107: void
                    108: LunaPROMEmuDevice::ResetHard()
                    109: {
1.1.1.2   root      110:        is_closed = false;
1.1       root      111: }
                    112: 
                    113: // アドレスデコーダ
                    114: inline uint64
                    115: LunaPROMEmuDevice::Decoder(uint32 addr) const
                    116: {
1.1.1.2   root      117:        // 折り返しなし
1.1       root      118:        return addr - baseaddr;
                    119: }
                    120: 
                    121: uint64
1.1.1.2   root      122: LunaPROMEmuDevice::Read8(uint32 addr)
                    123: {
                    124:        uint64 offset = Decoder(addr);
                    125: 
                    126:        // 謎の IO 空間はロングワードアクセスのみ
                    127:        return romdata[offset & (devlen - 1)];
                    128: }
                    129: 
                    130: uint64
                    131: LunaPROMEmuDevice::Read16(uint32 addr)
                    132: {
                    133:        uint64 offset = Decoder(addr);
                    134: 
                    135:        // 謎の IO 空間はロングワードアクセスのみ
                    136:        return be16toh(*(uint16 *)&romdata[offset & (devlen - 1)]);
                    137: }
                    138: 
                    139: uint64
1.1       root      140: LunaPROMEmuDevice::Read32(uint32 addr)
                    141: {
                    142:        uint64 offset = Decoder(addr);
                    143: 
                    144:        // ロングワードアクセスでだけ謎の I/O 空間が見える
1.1.1.2   root      145:        if (!is_closed) {
1.1       root      146:                switch (offset) {
1.1.1.2   root      147:                 case ROMIO_INIT - baseaddr:
                    148:                        return ROM_Init();
1.1       root      149: 
1.1.1.2   root      150:                 case ROMIO_KEYIN - baseaddr:
                    151:                        return ROM_Keyin();
1.1       root      152: 
1.1.1.2   root      153:                 case ROMIO_CLOSE - baseaddr:
                    154:                        return ROM_Close();
1.1       root      155: 
1.1.1.6 ! root      156:                 case ROMIO_ENTRY - baseaddr:
        !           157:                        return entrypoint;
        !           158: 
1.1       root      159:                 default:
                    160:                        break;
                    161:                }
                    162:        }
1.1.1.2   root      163:        return be32toh(*(uint32 *)&romdata[offset & (devlen - 1)]);
                    164: }
                    165: 
                    166: uint64
                    167: LunaPROMEmuDevice::Write8(uint32 addr, uint32 data)
                    168: {
                    169:        return 0;
                    170: }
                    171: 
                    172: uint64
                    173: LunaPROMEmuDevice::Write16(uint32 addr, uint32 data)
                    174: {
                    175:        return 0;
                    176: }
                    177: 
                    178: uint64
                    179: LunaPROMEmuDevice::Write32(uint32 addr, uint32 data)
                    180: {
                    181:        return 0;
                    182: }
                    183: 
                    184: uint64
                    185: LunaPROMEmuDevice::Peek8(uint32 addr)
                    186: {
                    187:        uint64 offset = Decoder(addr);
                    188: 
                    189:        return romdata[offset & (devlen - 1)];
1.1       root      190: }
                    191: 
                    192: // 起動時の処理を行う。
                    193: // 次段実行ファイルの読み込みに成功すればそのエントリポイントを返す。
                    194: // そうでなければ 0 を返すので、プロンプトに処理を移すこと。
                    195: uint32
1.1.1.2   root      196: LunaPROMEmuDevice::ROM_Init()
1.1       root      197: {
                    198:        MemoryStreamBE ms;
                    199:        uint32 entry;
                    200: 
                    201:        entrypoint = 0;
                    202: 
                    203:        // ROM 0x41000000.L リセットベクタ(SP,PC)もカーネルが参照している
                    204:        //                  (これは Init() が用意している)
                    205:        // ROM 0x4100000c.L メモリサイズ(バイト数)格納先アドレス
                    206:        // ROM 0x410000b8.L プレーンマスク格納先アドレス
                    207: 
                    208:        // メモリサイズはとりあえず 0x41000500 に格納
1.1.1.2   root      209:        ms.SetPtr(&romdata[0x500]);
1.1       root      210:        ms.Write32(::ram_size);
                    211: 
                    212:        // プレーン数(1..4)をプレーンマスク(0x01..0x0f)に
                    213:        int nplane = gBitmap->GetPlaneCount();
                    214:        int planemask = (1 << nplane) - 1;
                    215:        // 実際は RAM 上を指しているのだが、とりあえずすぐ隣に置いておく。
1.1.1.2   root      216:        ms.SetPtr(&romdata[0xb8]);
1.1       root      217:        ms.Write32(0x410000bc);
                    218:        ms.Write32(planemask);
                    219: 
                    220:        // 初期パレット
1.1.1.4   root      221:        // 偶数番は白(R/G/B=15/15/15)、奇数番は黒(0/0/0)。
                    222:        uint8 val = 0xf0;
                    223:        gBT454->Write8(0, 0);   // select palette
                    224:        for (int i = 0; i < 16; i++) {
                    225:                gBT454->Write8(1, val); // R
                    226:                gBT454->Write8(1, val); // G
                    227:                gBT454->Write8(1, val); // B
                    228:                val ^= 0xf0;
                    229:        }
1.1       root      230: 
                    231:        // SCSI
                    232:        // BDID の書き込みによってホストデバイスがバスにアタッチされる構造なので。
                    233:        gSPC->Write8(SPC::BDID, 7);
                    234: 
1.1.1.2   root      235:        // 内蔵 ROM: キーボード(chB)を初期化
                    236:        gSIO->Write8(0x51000006, 0x01);         // CR1
                    237:        gSIO->Write8(0x51000006, 0x10);         //    RX Int(all char)
                    238:        gSIO->Write8(0x51000006, 0x03);         // CR3
                    239:        gSIO->Write8(0x51000006, 0xc1);         //    RX Enable, 8bit
                    240:        gSIO->Write8(0x51000006, 0x04);         // CR4
                    241:        gSIO->Write8(0x51000006, 0x44);         //    Stop 1bit
                    242:        gSIO->Write8(0x51000006, 0x05);         // CR5
                    243:        gSIO->Write8(0x51000006, 0x68);         //    TX Enable, 8bit
                    244: 
                    245:        // 内蔵 ROM: スクリーンを初期化
1.1       root      246:        text.Init(80, 32);
                    247:        gBitmap->EmuConsoleOpen(&text);
1.1.1.2   root      248:        inputbuf.clear();
                    249:        inputpos = 0;
                    250:        is_shift = false;
1.1.1.3   root      251:        mousecnt = 0;
1.1.1.2   root      252:        prompt_idx = 0;
                    253:        prompt = default_prompt;
1.1       root      254: 
                    255:        text.Print(0, 0, "NONO %d.%d.%d Emulated ROM Monitor",
                    256:                NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER);
                    257:        text.Locate(0, 2);
                    258: 
                    259:        // 表示環境が整ったところで NVRAM を照合
                    260:        if (VerifyNVRAM() == false) {
                    261:                InitNVRAM();
                    262:                text.Print("** NVRAM Initialized.\n");
                    263:                text.Print("\n");
                    264:                return 0;
                    265:        }
                    266: 
1.1.1.5   root      267:        // 実際の画面更新は ConsoleUpdate() を呼ぶことで行われるので、
1.1       root      268:        // タイトルを Print してはいるが、エラーなくブートプログラムに制御を
                    269:        // 渡せた場合にはそれすら表示せずにゲストに処理を移す。
                    270:        // 意図して或いは意図せずプロンプトに降りる場合だけ Update が起きて
                    271:        // 初めて画面が更新される。
                    272: 
                    273:        // DIPSW#1-1 が UP なら自動起動、DOWN なら ROM モニタ起動なので、
                    274:        // これを真似する。
                    275:        entry = 0;
                    276:        if ((gPIO0->GetDIPSW1() & 1)) {
                    277:                if (gMainApp.host_file) {
                    278:                        // ホストのファイルを読み込んでエントリポイントアドレスを
                    279:                        // この Read アクセスの読み出し値として返す。
                    280:                        // エラーがあればエラーメッセージは呼び出し先側で表示してある。
                    281:                        entry = LoadHostFile();
                    282:                } else {
                    283:                        // NVRAM の設定に従ってブート先を探す。
                    284:                        errmsg.clear();
                    285:                        entry = LoadByNVRAM("");
                    286:                        if (entry == 0) {
                    287:                                text.Print("** %s\n", errmsg.c_str());
                    288:                        }
                    289:                }
                    290:        }
                    291: 
1.1.1.2   root      292:        if (entry == 0) {
                    293:                ConsoleUpdate();
                    294:        }
                    295: 
1.1       root      296:        return entry;
                    297: }
                    298: 
                    299: // ROM 処理のクローズ。
                    300: // 次段プログラムにジャンプするための処理も含む。
                    301: uint32
1.1.1.2   root      302: LunaPROMEmuDevice::ROM_Close()
1.1       root      303: {
                    304:        // ここでバックドアに蓋をする
1.1.1.2   root      305:        is_closed = true;
1.1       root      306: 
                    307:        // コンソールクローズ
                    308:        gBitmap->EmuConsoleClose();
                    309: 
                    310:        // NetBSD のブートローダがカーネルを読み込む時にはいくつかレジスタ
                    311:        // 渡しのパラメータがあるので、ここで用意する。本当はターゲットが
                    312:        // NetBSD カーネルの時に限定すべきのような気もするけど、とりあえず。
                    313:        // ROM がブートローダを読み込む時にはそのような取り決め事は一切ない
                    314:        // ので、ブートローダを読む時にも同じ値が入ってしまうが気にしない
                    315:        // ことにする。
                    316:        // 必要なパラメータは
                    317:        // %d6 に bootdev、NetBSD/luna68k の場合は
                    318:        // bootdev = $MACUPP00
                    319:        //            ||||++-- パーティション番号
                    320:        //            |||+---- SCSI ID (XXX ただしここでは 6 決め打ち)
                    321:        //            ||+----- unit (spc0 なら 0 のやつのはず)
                    322:        //            |+------ アダプタ (spc = 0、lance = 1)
                    323:        //            +------- magic ($a)
                    324:        //
                    325:        // %d7 に howto (0 でよい)
                    326:        // (と %a0 にジャンプ先を入れるがこれは Init() が書き出した ROM
                    327:        // アセンブラコード側で行っている)
                    328:        m68kcpu *cpu = gMPU680x0->GetCPU();
                    329:        RegD(6) = 0xa0060000;
                    330:        RegD(7) = 0;
                    331: 
                    332:        // 戻り値は使わないのでなんでもいい
                    333:        return 0;
                    334: }
                    335: 
1.1.1.2   root      336: // ROM プロンプトのキー入力。
1.1       root      337: // VM 側の仮想マシンを回すため、ここでは入力待ちはしない。
                    338: // エントリポイントが取得できればそれを、そうでなければ 0 を返す。
                    339: uint32
1.1.1.2   root      340: LunaPROMEmuDevice::ROM_Keyin()
1.1       root      341: {
1.1.1.2   root      342:        uint32 lunakey = gSIO->Read8(0x51000004);
1.1       root      343: 
1.1.1.3   root      344:        // マウス入力の 2, 3バイト目は無視
                    345:        if (mousecnt > 0) {
                    346:                mousecnt--;
                    347:                return 0;
                    348:        }
                    349: 
1.1.1.2   root      350:        // SHIFT キーだけ状態を持つので先に処理
                    351:        if (lunakey == 0x0c || lunakey == 0x0d) {       // 左右SHIFT押下
                    352:                is_shift = true;
                    353:                return 0;
                    354:        }
                    355:        if (lunakey == 0x8c || lunakey == 0x8d) {       // 左右SHIFT開放
1.1       root      356:                is_shift = false;
1.1.1.2   root      357:                return 0;
                    358:        }
1.1.1.3   root      359:        // マウスデータの1バイト目なら、後続2バイトをスキップ
                    360:        if ((lunakey & 0xf8) == 0x80) {
                    361:                mousecnt = 2;
                    362:                return 0;
                    363:        }
                    364:        // キー開放は無視してよい
1.1.1.2   root      365:        if ((lunakey & 0x80)) {
                    366:                return 0;
                    367:        }
1.1       root      368: 
1.1.1.2   root      369:        switch (lunakey) {
                    370:         case 0x11:             // BS
                    371:                if (inputpos > 0) {
                    372:                        inputbuf.erase(--inputpos);
1.1       root      373:                }
1.1.1.2   root      374:                break;
                    375:         case 0x12:             // Enter
                    376:         {
                    377:                // 現在位置のカーソルを消去
                    378:                uint16 *rawbuf = text.GetRawBuf();
                    379:                int curx = prompt.length() + inputpos;
                    380:                rawbuf[text.GetY() * text.GetCol() + curx] &= ~TA::On;
                    381:                // 改行
                    382:                text.Putc('\n');
                    383:                // コマンド処理。
                    384:                // エントリポイントが見付かればもうここは放棄するので帰るだけ。
                    385:                uint32 entry = Command();
                    386:                if (entry != 0) {
                    387:                        return entry;
1.1       root      388:                }
1.1.1.2   root      389:                inputbuf.clear();
                    390:                inputpos = 0;
                    391:                break;
                    392:         }
                    393:         case 0x1d:             // ←
                    394:                if (inputpos > 0) {
                    395:                        inputpos--;
1.1       root      396:                }
1.1.1.2   root      397:                break;
                    398:         case 0x1e:             // →
                    399:                if (inputpos < inputbuf.length()) {
1.1       root      400:                        inputpos++;
                    401:                }
                    402:                break;
1.1.1.2   root      403:         default:               // 通常文字
                    404:         {
                    405:                char asciicode;
                    406:                if (is_shift) {
                    407:                        asciicode = lunakey2shifttable[lunakey];
                    408:                } else {
                    409:                        asciicode = lunakey2asciitable[lunakey];
                    410:                }
                    411:                if (asciicode == 0) {
                    412:                        // 割り当てなし
                    413:                        return 0;
                    414:                }
                    415:                inputbuf.insert(inputbuf.begin() + inputpos, asciicode);
                    416:                inputpos++;
                    417:                break;
                    418:         }
1.1       root      419:        }
1.1.1.2   root      420:        putmsg(2, "inputbuf=%zd|%s|", inputbuf.length(), inputbuf.c_str());
                    421:        ConsoleUpdate();
                    422:        return 0;
                    423: }
1.1       root      424: 
1.1.1.2   root      425: // 画面を更新
                    426: void
                    427: LunaPROMEmuDevice::ConsoleUpdate()
                    428: {
1.1       root      429:        // 入力行全体を都度更新 (面倒なので行をはみ出さないようにする)
                    430:        std::string buf = prompt + inputbuf;
                    431:        text.Print(0, text.GetY(), "%-79s", buf.c_str());
                    432:        // カーソルを描画 (生バッファを触って属性を立てる)
                    433:        uint16 *rawbuf = text.GetRawBuf();
                    434:        int curx = prompt.length() + inputpos;
                    435:        rawbuf[text.GetY() * text.GetCol() + curx] |= TA::On;
                    436:        // 画面更新
                    437:        gBitmap->EmuConsoleUpdate();
                    438: }
                    439: 
                    440: // 入力コマンド処理
                    441: uint32
1.1.1.2   root      442: LunaPROMEmuDevice::Command()
1.1       root      443: {
1.1.1.2   root      444:        std::vector<char> buf(inputbuf.length() + 1);
1.1       root      445:        std::vector<std::string> arg;
                    446: 
                    447:        // 1ワードごとに分解
1.1.1.2   root      448:        strcpy(&buf[0], inputbuf.c_str());
                    449:        char *p = &buf[0];
1.1       root      450:        char *s = p;
                    451:        while (*p != '\0') {
                    452:                if (*p == ' ') {
                    453:                        *p++ = '\0';
                    454:                        arg.push_back(std::string(s));
                    455:                        s = p;
                    456:                } else {
                    457:                        p++;
                    458:                }
                    459:        }
                    460:        if (p != s) {
                    461:                arg.push_back(std::string(s));
                    462:        }
                    463:        if (loglevel >= 1) {
                    464:                for (int i = 0; i < arg.size(); i++) {
                    465:                        putmsg("arg[%d]=|%s|", i, arg[i].c_str());
                    466:                }
                    467:        }
                    468: 
                    469:        // "k" コマンド中ならここで先に処理する
                    470:        if (prompt_idx != 0) {
1.1.1.2   root      471:                CommandK(arg);
1.1       root      472:                return 0;
                    473:        }
                    474: 
                    475:        // 空行
                    476:        if (arg.size() == 0) {
                    477:                return 0;
                    478:        }
                    479: 
                    480:        // 1ワード目がコマンド
                    481:        if (arg[0] == "h") {
                    482:                // ヘルプメッセージ
                    483:                text.Print("Commands\n");
                    484:                text.Print(
                    485: "  g [<filename>]     : load program\n"
                    486: "  gh                 : load host program (specified by -A option)\n"
                    487: "  h                  : show this message\n"
                    488: "  k                  : show/set boot constants\n"
                    489: "  x                  : execute loaded program\n"
                    490:                );
                    491:                return 0;
                    492:        }
                    493:        if (arg[0] == "g") {
1.1.1.2   root      494:                CommandG(arg);
1.1       root      495:                return 0;
                    496:        }
                    497:        if (arg[0] == "gh") {
1.1.1.2   root      498:                CommandGH();
1.1       root      499:                return 0;
                    500:        }
                    501:        if (arg[0] == "k") {
1.1.1.2   root      502:                CommandK(arg);
1.1       root      503:                return 0;
                    504:        }
                    505:        if (arg[0] == "x") {
1.1.1.2   root      506:                return CommandX();
1.1       root      507:        }
                    508: 
                    509:        text.Print("** Unknown command: %s\n", arg[0].c_str());
                    510:        return 0;
                    511: }
                    512: 
                    513: // "g" コマンド
                    514: // g なら NVRAM の情報に従ってプログラムをロード。
                    515: // g <fname> なら NVRAM の fname だけ指定の名前を使ってロード。NVRAM には
                    516: // 書き込まない。
                    517: void
1.1.1.2   root      518: LunaPROMEmuDevice::CommandG(const std::vector<std::string>& arg)
1.1       root      519: {
                    520:        std::string ctlr = nvram->PeekString(0x0030);
                    521:        if (ctlr == "dk") {                     // harddisk
                    522:                std::string fname {};
                    523: 
                    524:                switch (arg.size()) {
                    525:                 case 1:
                    526:                        break;
                    527:                 case 2:
                    528:                        fname = arg[1];
                    529:                        break;
                    530:                 default:
                    531:                        text.Print("** Invalid argument.\n");
                    532:                        return;
                    533:                }
                    534:                errmsg.clear();
                    535:                entrypoint = LoadByNVRAM(fname);
                    536:                if (entrypoint == 0) {
                    537:                        text.Print("** %s\n", errmsg.c_str());
                    538:                }
                    539: 
                    540:        } else if (ctlr == "et" ||      // netboot
                    541:                   ctlr == "sd" ||      // cassette tape
                    542:                   ctlr == "fl"   )     // floppy
                    543:        {
                    544:                text.Print("** %s boot not supported.\n", ctlr.c_str());
                    545:                return;
                    546:        } else {
                    547:                // 起きないはず
                    548:                text.Print("** Invalid boot controller name.\n");
                    549:                return;
                    550:        }
                    551: 
                    552:        if (entrypoint) {
                    553:                text.Print("Loaded.  Entry point = $%08x\n", entrypoint);
                    554:        }
                    555: }
                    556: 
                    557: // "gh" コマンド (勝手に拡張)
                    558: // -A オプションで指定されたホストプログラムをロードする。
                    559: void
1.1.1.2   root      560: LunaPROMEmuDevice::CommandGH()
1.1       root      561: {
                    562:        entrypoint = 0;
                    563:        if (gMainApp.host_file) {
                    564:                // 指定されてたら読み込む
                    565:                entrypoint = LoadHostFile();
                    566:        } else {
                    567:                text.Print("** Cannot loaded; host program is not specified.\n");
                    568:        }
                    569: }
                    570: 
                    571: // -A オプションで指定されたホストファイルをロードする。
                    572: // ロードできればエントリポイントを返す。
                    573: // host_file が指定されている時に呼ぶこと。
                    574: uint32
                    575: LunaPROMEmuDevice::LoadHostFile()
                    576: {
                    577:        assert(gMainApp.host_file);
                    578: 
                    579:        uint32 entry = gRAM->LoadFile(gMainApp.host_file, AOUT_MID_M68K);
                    580:        if (entry) {
                    581:                text.Print("Host program loaded.  Entry point = $%08x\n",
                    582:                        entry);
                    583:        } else {
                    584:                text.Print("** Couldn't load specified host program.\n");
                    585:        }
                    586:        return entry;
                    587: }
                    588: 
                    589: 
                    590: // k コマンドのパラメータ表
                    591: struct kinfo {
                    592:        uint32 offset;                          // NVRAM 上のオフセット
                    593:        const char * const name;        // 表示名
                    594:        int next;                                       // 次インデックス
                    595: };
                    596: static const struct kinfo kinfo[] = {
                    597:        { 0 },  // 0 は通常プロンプトを指すのでここでは使わない
                    598:        { 0x0030,       "controller",  0 },     // [1] BOOT (next は動的判定する)
                    599:        { 0x0090,       "drive unit",  3 },     // [2] DKUNIT
                    600:        { 0x00b0,       "partition ",  4 },     // [3] DKPART
                    601:        { 0x00d0,       "filename  ",  0 },     // [4] FLNAME
                    602:        { 0x0050,       "hostname  ",  6 },     // [5] HOST
                    603:        { 0x0070,       "servername",  7 },     // [6] SERVER
                    604:        { 0x0190,       "filename  ",  8 },     // [7] ETBOOT
                    605:        { 0x01b0,       "",                        0 }, // [8] ETFILE (ETBOOT と1行で処理する)
                    606: };
                    607: 
                    608: // "k" コマンド
                    609: void
1.1.1.2   root      610: LunaPROMEmuDevice::CommandK(const std::vector<std::string>& arg)
1.1       root      611: {
                    612:        uint32 offset;
                    613:        const char *name;
                    614:        int next;
                    615: 
                    616:        // 入力を処理
                    617:        if (prompt_idx == 0) {
                    618:                // ここは1行目表示前なので前行の入力はない。
                    619:                next = 1;
                    620:        } else {
                    621:                std::string val;
                    622:                bool rv;
                    623: 
                    624:                // 入力があれば更新
                    625:                if (arg.size() != 0) {
                    626:                        rv = CommandKInput(arg[0]);
                    627:                } else {
                    628:                        // [7] の時に入力があれば CommandKInput() の中で更新されるが、
                    629:                        // 入力がなければそこを通らないので、こっちでやらないといけない。
                    630:                        // うーん。
                    631:                        if (prompt_idx == 7) {
                    632:                                prompt_idx = kinfo[prompt_idx].next;
                    633:                        }
                    634:                        rv = true;
                    635:                }
                    636: 
                    637:                // これ以降は更新後の prompt_idx を使う
                    638: 
                    639:                // 入力エラーがあった時はこの行を再入力するため
                    640:                next = prompt_idx;
                    641: 
                    642:                if (rv == true) {
                    643:                        // 入力があっても空でも次インデックスへ。
                    644:                         if (prompt_idx == 1) {
                    645:                                // BOOT なら現在値によって次のインデックスが変わる
                    646:                                // "dk" なら [2]、"et" なら [5]。他は未対応
                    647:                                offset = kinfo[prompt_idx].offset;
                    648:                                val = nvram->PeekString(offset);
                    649:                                if (val == "dk") {
                    650:                                        next = 2;
                    651:                                } else if (val == "et") {
                    652:                                        next = 5;
                    653:                                } else {
                    654:                                        // 起きることはないはず
                    655:                                        text.Print("** Inconsistent boot parameter: %s\n",
                    656:                                                val.c_str());
                    657:                                }
                    658:                        } else {
                    659:                                // それ以外はテーブルにかかれている通り
                    660:                                next = kinfo[prompt_idx].next;
                    661:                        }
                    662:                }
                    663:        }
                    664: 
                    665:        // この行のプロンプト文字列を作成
                    666:        prompt_idx = next;
                    667:        if (prompt_idx == 0) {
                    668:                // 最終行なら元に戻す
                    669:                prompt = default_prompt;
                    670:        } else {
                    671:                // 次のプロンプトに変更
                    672:                name = kinfo[prompt_idx].name;
                    673:                offset = kinfo[prompt_idx].offset;
                    674:                std::string val = nvram->PeekString(offset);
                    675: 
                    676:                // [7] ETBOOT だけ1行で ETBOOT:ETFILE 形式
                    677:                if (prompt_idx == 7) {
                    678:                        next = kinfo[prompt_idx].next;  // ETFILE
                    679:                        offset = kinfo[next].offset;
                    680:                        val += ":";
                    681:                        val += nvram->PeekString(offset);
                    682:                }
                    683: 
                    684:                prompt = string_format("%s: %s  ?", name, val.c_str());
                    685:        }
                    686: }
                    687: 
                    688: // k コマンドの入力値を処理する部分。
                    689: // 成功すれば true を返す。
                    690: // 失敗すれば false を返す。
                    691: // 実機 ROM は入力値にエラーがあると黙って再入力を促す。
                    692: // エラーメッセージくらい表示してもいいかもだがとりあえず真似しておく。
                    693: bool
                    694: LunaPROMEmuDevice::CommandKInput(const std::string& val)
                    695: {
                    696:        int offset;
                    697:        bool rv = true;
                    698: 
                    699:        offset = kinfo[prompt_idx].offset;
                    700: 
                    701:        switch (prompt_idx) {
                    702:         case 1:        // BOOT
                    703:                // 正常な入力値は "dk", "et", "sd", "fl" のみ。
                    704:                if (val != "dk" && val != "et" && val != "sd" && val != "fl") {
                    705:                        return false;
                    706:                }
                    707:                rv = nvram->WriteString(offset, val);
                    708:                if (rv == false) {
                    709:                        return false;
                    710:                }
                    711:                break;
                    712: 
                    713:         case 7:        // ETBOOT
                    714:         {
                    715:                // こいつだけ ETBOOT:ETFILE 形式で2つのパラメータを同時に処理する
                    716: 
                    717:                // ':' で前後に分ける
                    718:                int sep = val.find(':');
                    719:                if (sep == std::string::npos) {
                    720:                        return false;
                    721:                }
                    722:                std::string etboot = val.substr(0, sep);
                    723:                std::string etfile = val.substr(sep + 1, val.size() - sep + 1);
                    724:                if (etboot.empty() || etfile.empty()) {
                    725:                        return false;
                    726:                }
                    727: 
                    728:                // ETBOOT
                    729:                rv = nvram->WriteString(offset, etboot);
                    730:                if (rv == false) {
                    731:                        return false;
                    732:                }
                    733: 
                    734:                // 次へ
                    735:                prompt_idx = kinfo[prompt_idx].next;
                    736: 
                    737:                // ETFILE
                    738:                offset = kinfo[prompt_idx].offset;
                    739:                rv = nvram->WriteString(offset, etfile);
                    740:                if (rv == false) {
                    741:                        return false;
                    742:                }
                    743:                break;
                    744:         }
                    745: 
                    746:         default:
                    747:                rv = nvram->WriteString(offset, val);
                    748:                if (rv == false) {
                    749:                        return false;
                    750:                }
                    751:                break;
                    752:        }
                    753: 
                    754:        WriteNVRAMCsum();
                    755:        return rv;
                    756: }
                    757: 
                    758: // "x" コマンド
                    759: // すでに読み込まれてるはずのエントリポイントにジャンプするだけ。
                    760: uint32
1.1.1.2   root      761: LunaPROMEmuDevice::CommandX()
1.1       root      762: {
                    763:        if (entrypoint == 0) {
                    764:                text.Print("** Program is not loaded.\n");
                    765:        }
                    766:        return entrypoint;
                    767: }
                    768: 
                    769: // NVRAM のチェックサムを返す
                    770: uint8
                    771: LunaPROMEmuDevice::CalcNVRAMCsum()
                    772: {
                    773:        uint8 eor = 0;
                    774:        for (uint32 addr = 0x20; addr < 0x560; addr++) {
                    775:                eor ^= nvram->Peek(addr);
                    776:        }
                    777:        return eor;
                    778: }
                    779: 
                    780: // NVRAM のチェックサムを計算して書き込む
                    781: void
                    782: LunaPROMEmuDevice::WriteNVRAMCsum()
                    783: {
                    784:        uint8 eor = CalcNVRAMCsum();
                    785: 
                    786:        nvram->Write(0x001c, eor);
                    787:        nvram->Write(0x001d, eor);
                    788:        nvram->Write(0x001e, eor);
                    789: }
                    790: 
                    791: // NVRAM のマジックとチェックサムを照合する
                    792: bool
                    793: LunaPROMEmuDevice::VerifyNVRAM()
                    794: {
                    795:        if (nvram->PeekString(0x0004) != "<nv>") {
                    796:                return false;
                    797:        }
                    798: 
                    799:        uint8 eor = CalcNVRAMCsum();
                    800:        for (uint32 addr = 0x1c; addr < 0x1f; addr++) {
                    801:                if (nvram->Peek(addr) != eor) {
                    802:                        return false;
                    803:                }
                    804:        }
                    805:        return true;
                    806: }
                    807: 
                    808: // NVRAM を初期化する
                    809: bool
                    810: LunaPROMEmuDevice::InitNVRAM()
                    811: {
                    812:        // 初期値どうしたもんか
                    813:        nvram->WriteString(0x0004, "<nv>");
                    814:        nvram->WriteString(0x0020, "BOOT");
                    815:        nvram->WriteString(0x0030, "dk");
                    816:        nvram->WriteString(0x0040, "HOST");
                    817:        nvram->WriteString(0x0050, "nono");     // 偽札的なアレ
                    818:        nvram->WriteString(0x0060, "SERVER");
                    819:        nvram->WriteString(0x0070, "servername");
                    820:        nvram->WriteString(0x0080, "DKUNIT");
                    821:        nvram->WriteString(0x0090, "0");
                    822:        nvram->WriteString(0x00a0, "DKPART");
                    823:        nvram->WriteString(0x00b0, "c");
                    824:        nvram->WriteString(0x00c0, "DKFILE");
                    825:        nvram->WriteString(0x00d0, "vmunix");
                    826:        nvram->WriteString(0x00e0, "FLUNIT");
                    827:        nvram->WriteString(0x00f0, "2");
                    828:        nvram->WriteString(0x0100, "FLFILE");
                    829:        nvram->WriteString(0x0110, "vmunix");
                    830:        nvram->WriteString(0x0120, "STUNIT");
                    831:        nvram->WriteString(0x0130, "0");
                    832:        nvram->WriteString(0x0140, "STFLNO");
                    833:        nvram->WriteString(0x0150, "1");
                    834:        nvram->WriteString(0x0160, "STFILE");
                    835:        nvram->WriteString(0x0170, "vmunix");
                    836:        nvram->WriteString(0x0180, "ETBOOT");
                    837:        nvram->WriteString(0x0190, "server");
                    838:        nvram->WriteString(0x01a0, "ETFILE");
                    839:        nvram->WriteString(0x01b0, "/vmunix");
                    840:        nvram->WriteString(0x0560, "ENADDR");
                    841:        nvram->WriteString(0x0570, ""); // どうするか
                    842: 
                    843:        // チェックサム再計算
                    844:        WriteNVRAMCsum();
                    845: 
                    846:        return true;
                    847: }
                    848: 
                    849: // キーコードから文字への変換
                    850: /*static*/ const uint8
                    851: LunaPROMEmuDevice::lunakey2asciitable[] = {
                    852:         0, 0, 0, 0, 0, 0, 0, 0,
                    853:         0, 0, 0, 0, 0, 0, 0, 0,
                    854:         0, 0, 0, 0, ' ', 0, 0, 0,
                    855:         0, 0, 0, 0, 0, 0, 0, 0,
                    856:         0,   0,  '1', '2', '3', '4', '5', '6',
                    857:        '7', '8', '9', '0', '-', '^', '\\', 0,
                    858:         0,   0,  'q', 'w', 'e', 'r', 't', 'y',
                    859:        'u', 'i', 'o', 'p', '@', '[',  0,   0,
                    860:         0,   0,  'a', 's', 'd', 'f', 'g', 'h',
                    861:        'j', 'k', 'l', ';', ':', ']',  0,   0,
                    862:         0,   0,  'z', 'x', 'c', 'v', 'b', 'n',
                    863:        'm', ',', '.', '/',  0,   0,   0,   0,
                    864:         0, 0, 0, 0, 0, 0, 0, 0,        // XXX テンキー
                    865:         0, 0, 0, 0, 0, 0, 0, 0,
                    866:         0, 0, 0, 0, 0, 0, 0, 0,
                    867:         0, 0, 0, 0, 0, 0, 0, 0,
                    868: };
                    869: /*static*/ const uint8
                    870: LunaPROMEmuDevice::lunakey2shifttable[] = {
                    871:         0, 0, 0, 0, 0, 0, 0, 0,
                    872:         0, 0, 0, 0, 0, 0, 0, 0,
                    873:         0, 0, 0, 0, ' ', 0, 0, 0,
                    874:         0, 0, 0, 0, 0, 0, 0, 0,
                    875:         0,   0,  '1', '2', '3', '4', '5', '6',
                    876:        '7', '8', '9', '0', '=', '~', '|',  0,
                    877:         0,   0,  'Q', 'W', 'E', 'R', 'T', 'Y',
                    878:        'U', 'I', 'O', 'P', '`', '{',  0,   0,
                    879:         0,   0,  'A', 'S', 'D', 'F', 'G', 'H',
                    880:        'J', 'K', 'L', '+', '*', '}',  0,   0,
                    881:         0,   0,  'Z', 'X', 'C', 'V', 'B', 'N',
                    882:        'M', '<', '>', '?', '_',  0,   0,   0,
                    883:         0, 0, 0, 0, 0, 0, 0, 0,        // XXX テンキー
                    884:         0, 0, 0, 0, 0, 0, 0, 0,
                    885:         0, 0, 0, 0, 0, 0, 0, 0,
                    886:         0, 0, 0, 0, 0, 0, 0, 0,
                    887: };
                    888: 
                    889: 
                    890: //
                    891: // UFS ブート
                    892: //
                    893: 
                    894: // ディスクラベル (1セクタ目)
                    895: // svnweb.freebsd.org/csrg/sys/luna68k/stand/omron_disklabel.h
                    896: struct scd_dk_label
                    897: {
                    898:        char asciilabel[128];   /* for compatibility */
                    899:        char pad[512 - (128 + 8*8 + 11*2 + 4)];
                    900:        uint16 badchk;                  /* checksum of bad track */
                    901:        uint32 maxblk;                  /* # of total logical block */
                    902:        uint16 dtype;                   /* disk drive type */
                    903:        uint16 ndisk;                   /* # of disk drives */
                    904:        uint16 ncyl;                    /* # of data cylinders */
                    905:        uint16 acyl;                    /* # of altenate cylinders */
                    906:        uint16 nhead;                   /* # of heads in this partition */
                    907:        uint16 nsect;                   /* # of 512 byte sectors per track */
                    908:        uint16 bhead;                   /* identifies proper label locations */
                    909:        uint16 ppart;                   /* physical partition # */
                    910:        struct {                                /* logical partitions */
                    911:                uint32 blkno;           /* starting block */
                    912:                uint32 nblk;            /* number of blocks */
                    913:        } map[8];
                    914:        uint16 magic;                   /* identifies this label format */
                    915:        uint16 cksum;                   /* xor checksum of sector */
                    916: 
                    917:        static const uint16 DKL_MAGIC = 0xdabe;
                    918: };
                    919: static_assert(sizeof(scd_dk_label) == 512, "size must be 512");
                    920: 
                    921: // オレオレ inode 情報クラス
1.1.1.2   root      922: class inodefile final
1.1       root      923: {
                    924:  public:
                    925:        inodefile(Device *dev) {
                    926:                parent = dev;
                    927:        }
1.1.1.2   root      928:        ~inodefile() { }
1.1       root      929: 
                    930:        // ディレクトリエントリからファイルを検索
                    931:        uint32 FindFile(const std::string& name);
                    932: 
                    933:        uint32 ino {};                          // inode 番号
                    934:        struct ufs1_dinode di {};       // disk inode 情報 (ゲストエンディアンで保持)
                    935:        std::vector<uint8> data {};     // ファイル(またはディレクトリ)本文
                    936:  private:
                    937:        Device *parent {};                      // 親デバイス
                    938: };
                    939: 
                    940: // ファイルシステムハンドルっぽいもの
1.1.1.2   root      941: class Filesys final
1.1       root      942: {
                    943:  public:
                    944:        Filesys(Device *dev) {
                    945:                parent = dev;
                    946:                fs = &fs0;
                    947:        }
1.1.1.2   root      948:        ~Filesys() { }
1.1       root      949: 
                    950:        // ファイルシステムをオープン
                    951:        bool Open(SCSIHD *hd_, uint32 start, uint32 size);
                    952:        // inode 情報を読み込む
                    953:        bool Readi(inodefile& inode);
                    954:        // データを読み込む
                    955:        bool ReadData(inodefile& inode);
                    956: 
                    957:        std::string errstr{};   // エラーメッセージ
                    958: 
                    959:  private:
                    960:        Device *parent {};              // 親デバイス
                    961:        SCSIHD *hd {};                  // ターゲット SCSI HD
                    962:        // パーティション情報
                    963:        uint32 part_start {};   // パーティションの先頭セクタ
                    964:        uint32 part_size {};    // パーティションのサイズ(セクタ数)
                    965:        // スーパーブロック情報
                    966:        // fs の(たぶんほとんどの)整数パラメータは読み込み時にホストエンディアン
                    967:        // に変換してあるのでそのままアクセスしてよい。構造体とかまでは全部対応
                    968:        // してないので、必要になったら書き足すこと。
                    969:        struct fs *fs;                  // 体裁を揃えるためポインタを使いたい
                    970:        struct fs fs0;                  // こっちが実体
                    971: };
                    972: 
                    973: // NVRAM の設定に従って起動先を探す。
                    974: // fname が指定されればそれをファイル名に使う。empty なら NVRAM の DKFILE
                    975: // をファイル名に使う。
                    976: // 成功すればエントリポイントを返す。
                    977: // 失敗ならをエラーメッセージを errmsg にセットして 0 を返す。
                    978: uint32
                    979: LunaPROMEmuDevice::LoadByNVRAM(const std::string& fname)
                    980: {
                    981:        // 起動先情報を NVRAM (mk48t02) に問い合わせる
                    982:        // DKUNIT はとりあえず無視して SCSI ID=6
                    983:        // DKPART は 'a'..'h' でパーティション。
                    984:        // DKFILE が読み込むカーネル名 (NetBSD ではブートローダ)。
                    985:        int dkunit = nvram->Peek(0x0090) - '0';
                    986:        int dkpart = nvram->Peek(0x00b0) - 'a';
                    987:        std::string dkfile_name;
                    988:        if (!fname.empty()) {
                    989:                dkfile_name = fname;
                    990:        } else {
                    991:                dkfile_name = nvram->PeekString(0x00d0);
                    992:        }
                    993:        putmsg(1, "%s DKUNIT=%d", __func__, dkunit);
                    994:        putmsg(1, "%s DKPART=%c", __func__, dkpart + 'a');
                    995:        putmsg(1, "%s DKFILE=|%s|", __func__, dkfile_name.c_str());
                    996: 
                    997:        // ユニット (今は SCSI ID=6 決め打ち)
                    998:        int id = 6;
                    999:        SCSITarget *target = gSPC->GetTarget(id);
                   1000:        if (target == NULL) {
                   1001:                errmsg = "No bootable disks";
                   1002:                putmsg(0, "%s", errmsg.c_str());
                   1003:                return 0;
                   1004:        }
1.1.1.3   root     1005:        if (target->GetDevType() != SCSI::DevType::HD) {
1.1       root     1006:                errmsg = "No bootable disks";
                   1007:                putmsg(0, "%s", errmsg.c_str());
                   1008:                return 0;
                   1009:        }
                   1010: 
                   1011:        SCSIHD *hd = dynamic_cast<SCSIHD*>(target);
                   1012:        putmsg(2, "%s SCSIHD[%d] found", __func__, id);
                   1013: 
                   1014:        // +0 セクタ目(512byte)に Sun disklabel
                   1015:        scd_dk_label dk;
                   1016:        if (hd->PeekImage(&dk, 0, sizeof(dk)) == false) {
                   1017:                putmsg(0, "SCSIHD[%d] ReadSector failed", id);
                   1018:                errmsg = string_format("dk%d Read disklabel failed.", dkunit);
                   1019:                return 0;
                   1020:        }
                   1021: 
                   1022:        // +$1fc の MAGIC をチェック
                   1023:        uint32 magic = be16toh(dk.magic);
                   1024:        if (magic != scd_dk_label::DKL_MAGIC) {
                   1025:                putmsg(0, "SCSIHD[%d] Bad magic 0x%04x (!= 0x%x)",
                   1026:                        id, magic, scd_dk_label::DKL_MAGIC);
                   1027:                errmsg = string_format("dk%d Bad disklabel magic.", dkunit);
                   1028:                return 0;
                   1029:        }
                   1030: 
                   1031:        // チェックサム照合は手抜きで省略
                   1032: 
                   1033:        // 指定パーティションの開始位置とサイズ
                   1034:        if (loglevel >= 2) {
                   1035:                // デバッグ用に全部表示
                   1036:                for (int i = 0; i < 8; i++) {
                   1037:                        putmsg("%s partition %c: { start=%8u size=%8u }", __func__,
                   1038:                                'a' + i,
                   1039:                                be32toh(dk.map[i].blkno),
                   1040:                                be32toh(dk.map[i].nblk));
                   1041:                }
                   1042:        }
                   1043:        uint32 part_start = be32toh(dk.map[dkpart].blkno);
                   1044:        uint32 part_size  = be32toh(dk.map[dkpart].nblk);
                   1045:        putmsg(1, "%s partition=%c, start=%u size=%u", __func__,
                   1046:                dkpart + 'a', part_start, part_size);
                   1047: 
                   1048:        // ファイルシステムをオープン (マウントっぽいイメージ)
                   1049:        Filesys fsys(this);
                   1050:        if (fsys.Open(hd, part_start, part_size) == false) {
                   1051:                putmsg(0, "SCSIHD[%d] %c: %s", id, dkpart + 'a', fsys.errstr.c_str());
                   1052:                errmsg = string_format("dk%d Open ffs failed.", dkunit);
                   1053:                return 0;
                   1054:        }
                   1055: 
                   1056:        // XXX 以降エラーメッセージ全部同じ
                   1057:        errmsg = string_format("dk%d Read ffs failed.", dkunit);
                   1058: 
                   1059:        std::vector<std::string> dkfile_paths;
                   1060:        int idx = 0;
                   1061:        inodefile dir(this);
                   1062:        inodefile dkfile(this);
                   1063: 
                   1064:        enum {
                   1065:                STATE_REG,      // 通常ファイル (終了条件)
                   1066:                STATE_PATH,     // パス解析
                   1067:                STATE_DIR,      // ディレクトリ読み込み
                   1068:                STATE_FIND,     // ディレクトリからファイルを検索
                   1069:                STATE_LINK,     // シンボリックリンク
                   1070:        } state;
                   1071: 
                   1072:        // DKFILE の先頭に '/' がなければここで足しておく。
                   1073:        // ファイル名を分解する際にルートディレクトリマークが必要なので。
                   1074:        if (dkfile_name[0] != '/') {
                   1075:                dkfile_name.insert(0, 1, '/');
                   1076:        }
                   1077:        state = STATE_PATH;
                   1078: 
                   1079:        while (state != STATE_REG) {
                   1080:                switch (state) {
                   1081:                 case STATE_PATH:
                   1082:                        // ファイル名をパスに分解
                   1083:                        // dkfile_name にパス名をセットしてからここに来ること。
                   1084:                        putmsg(1, "%s Path dkfile_name=|%s|", __func__,
                   1085:                                dkfile_name.c_str());
                   1086:                        if (dkfile_name.empty()) {
                   1087:                                putmsg(0, "SCSIHD[%d] %c: Filename empty?", id, dkpart + 'a');
                   1088:                                return 0;
                   1089:                        }
                   1090:                        dkfile_paths.clear();
                   1091:                        for (int s = 0; s < dkfile_name.size(); ) {
                   1092:                                int p = dkfile_name.find('/', s);
                   1093:                                if (p == std::string::npos) {
                   1094:                                        p = dkfile_name.size();
                   1095:                                }
                   1096:                                // '/' が連続していなければパスコンポーネント
                   1097:                                if (p != s) {
                   1098:                                        dkfile_paths.push_back(dkfile_name.substr(s, p - s));
                   1099:                                }
                   1100:                                s = p + 1;
                   1101:                        }
                   1102:                        idx = 0;
                   1103:                        if (loglevel >= 1) {
                   1104:                                for (int i = 0; i < dkfile_paths.size(); i++) {
                   1105:                                        putmsg("%s dkfile_path[%d]=|%s|",
                   1106:                                                __func__, i, dkfile_paths[i].c_str());
                   1107:                                }
                   1108:                        }
                   1109:                        // パスが '/' から始まっていればルートディレクトリの読み込みから。
                   1110:                        // そうでなければ現在のディレクトリでファイルの検索から。
                   1111:                        if (dkfile_name[0] == '/') {
                   1112:                                // ルートディレクトリの inode 番号は伝統的に #2 と
                   1113:                                // いうことになっている。
                   1114:                                dir.ino = 2;
                   1115:                                state = STATE_DIR;
                   1116:                        } else {
                   1117:                                state = STATE_FIND;
                   1118:                        }
                   1119:                        break;
                   1120: 
                   1121:                 case STATE_DIR:
                   1122:                        // inode 番号からディレクトリエントリを取得。
                   1123:                        // dir.ino をセットしてからここに来ること。
                   1124:                        putmsg(1, "%s Readdir ino=%d", __func__, dir.ino);
                   1125:                        if (fsys.Readi(dir) == false) {
                   1126:                                putmsg(0, "SCSIHD[%d] %c: %s",
                   1127:                                        id, dkpart + 'a', fsys.errstr.c_str());
                   1128:                                return 0;
                   1129:                        }
                   1130:                        // 中身(ディレクトリエントリ) を取得
                   1131:                        if (fsys.ReadData(dir) == false) {
                   1132:                                putmsg(0, "SCSIHD[%d] %c: %s",
                   1133:                                        id, dkpart + 'a', fsys.errstr.c_str());
                   1134:                                return 0;
                   1135:                        }
                   1136:                        state = STATE_FIND;
                   1137:                        break;
                   1138: 
                   1139:                 case STATE_FIND:
                   1140:                        // ディレクトリエントリ dir.data から
                   1141:                        // ファイル名 dkfile_paths[idx] を探す。
                   1142:                        putmsg(1, "%s FindFile %s", __func__, dkfile_paths[idx].c_str());
                   1143:                        dkfile.ino = dir.FindFile(dkfile_paths[idx]);
                   1144:                        if (dkfile.ino == 0) {
                   1145:                                putmsg(0, "SCSIHD[%d] %c: %s",
                   1146:                                        id, dkpart + 'a', fsys.errstr.c_str());
                   1147:                                return 0;
                   1148:                        }
                   1149:                        // ファイルの inode 情報を取得。
                   1150:                        if (fsys.Readi(dkfile) == false) {
                   1151:                                putmsg(0, "SCSIHD[%d] %c: %s",
                   1152:                                        id, dkpart + 'a', fsys.errstr.c_str());
                   1153:                                return 0;
                   1154:                        }
                   1155:                        switch (be16toh(dkfile.di.di_mode) & IFMT) {
                   1156:                         case IFREG:    // 通常ファイル
                   1157:                                state = STATE_REG;
                   1158:                                break;
                   1159: 
                   1160:                         case IFLNK:    // シンボリックリンク
                   1161:                                state = STATE_LINK;
                   1162:                                break;
                   1163: 
                   1164:                         case IFDIR:    // ディレクトリ
                   1165:                                dir.ino = dkfile.ino;
                   1166:                                idx++;
                   1167:                                state = STATE_DIR;
                   1168:                                break;
                   1169: 
                   1170:                         default:               // それ以外は対応してないし来ないはず
                   1171:                                putmsg(0, "SCSIHD[%d] %c:%s invalid filemode %06o",
                   1172:                                        id, dkpart + 'a', dkfile_name.c_str(),
                   1173:                                        be16toh(dkfile.di.di_mode));
                   1174:                                return 0;
                   1175:                        }
                   1176:                        break;
                   1177: 
                   1178:                 case STATE_LINK:
                   1179:                        // リンク先ファイル名を取り出す
                   1180:                        putmsg(1, "%s Readlink", __func__);
                   1181:                        if (fsys.ReadData(dkfile) == false) {
                   1182:                                return 0;
                   1183:                        }
                   1184:                        dkfile_name = std::string((const char *)dkfile.data.data(),
                   1185:                                dkfile.data.size());
                   1186:                        // パス解析へ
                   1187:                        state = STATE_PATH;
                   1188:                        break;
                   1189: 
                   1190:                 default:
                   1191:                        __unreachable();
                   1192:                }
                   1193:        }
                   1194:        // 通常ファイルに到達
                   1195: 
                   1196:        if (idx != dkfile_paths.size() - 1) {
                   1197:                // パスの最後のコンポーネントじゃなければエラー
                   1198:                putmsg(0, "SCSIHD[%d] %c:%s path not found",
                   1199:                        id, dkpart + 'a', dkfile_name.c_str());
                   1200:                return 0;
                   1201:        }
                   1202:        // ファイル本体を読み込み
                   1203:        if (fsys.ReadData(dkfile) == false) {
                   1204:                putmsg(0, "SCSIHD[%d] %c: %s", id, dkpart + 'a', fsys.errstr.c_str());
                   1205:                return 0;
                   1206:        }
                   1207: 
                   1208:        // ロード
                   1209:        uint32 entry;
                   1210:        std::string name = string_format("SCSIHD %d,%c:%s",
                   1211:                id, dkpart + 'a', dkfile_name.c_str());
                   1212:        entry = gRAM->LoadFile(name.c_str(), dkfile.data.data(),
                   1213:                dkfile.data.size(), AOUT_MID_M68K);
                   1214: 
                   1215:        return entry;
                   1216: }
                   1217: 
                   1218: // パーティションを FFS としてオープンする(マウントのようなイメージ)。
                   1219: // start, size はこのパーティションの開始セクタとセクタ数。
                   1220: bool
                   1221: Filesys::Open(SCSIHD *hd_, uint32 start, uint32 size)
                   1222: {
                   1223:        hd = hd_;
                   1224:        part_start = start;
                   1225:        part_size  = size;
                   1226: 
                   1227:        // FFS の先頭にはブートブロックがあり、続けてスーパーブロックがある。
                   1228:        // ブートブロックはブートローダのための領域で、ここもファイルシステムの
                   1229:        // 内側という認識のようだ。
                   1230:        //
                   1231:        // ブートブロックの大きさはおそらくファイルシステムごとに固定で、
                   1232:        // FFSv1(?) なら 8KB のようだ。ここは LUNA-I の ROM が解釈できるのと
                   1233:        // 同じファイルシステムだけ扱えればよいので、8KB 固定とする。
                   1234:        // 続いてスーパーブロックがある。ここにこのファイルシステムのパラメータ
                   1235:        // が書いてある。
                   1236:        //
                   1237:        // +-------------+ 0   <- part_start (パーティション先頭)
                   1238:        // | BootBlock   |
                   1239:        // +-------------+ 8KB
                   1240:        // | SuperBlock  |
                   1241:        // |    fs_iblkno ---+
                   1242:        // +-------------+   |
                   1243:        // :             :   |
                   1244:        //                   |
                   1245:        // :             :   |
                   1246:        // +-------------+ <-+
                   1247:        // | InodeBlock? |
                   1248:        //
                   1249:        // スーパーブロックの構造は <ufs/ffs/fs.h> の struct fs 参照。
                   1250: 
                   1251:        // スーパーブロックを読む
                   1252:        hd->PeekImage(&fs0, part_start * 512 + 8192, sizeof(fs0));
                   1253:        // 読み込んだスーパーブロックはゲストエンディアン(BE) なので
                   1254:        // 使う前に (もう面倒なのでほぼ全部) ホストエンディアンにしておく。
                   1255:        // ヘッダに定義してあるマクロをそのまま使いたいからだけど、正気かなこれ。
                   1256:        fs->fs_firstfield               = be32toh(fs->fs_firstfield);
                   1257:        fs->fs_sblkno                   = be32toh(fs->fs_sblkno);
                   1258:        fs->fs_cblkno                   = be32toh(fs->fs_cblkno);
                   1259:        fs->fs_iblkno                   = be32toh(fs->fs_iblkno);
                   1260:        fs->fs_dblkno                   = be32toh(fs->fs_dblkno);
                   1261:        fs->fs_old_cgoffset             = be32toh(fs->fs_old_cgoffset);
                   1262:        fs->fs_old_cgmask               = be32toh(fs->fs_old_cgmask);
                   1263:        fs->fs_old_time                 = be32toh(fs->fs_old_time);
                   1264:        fs->fs_old_size                 = be32toh(fs->fs_old_size);
                   1265:        fs->fs_old_dsize                = be32toh(fs->fs_old_dsize);
                   1266:        fs->fs_ncg                              = be32toh(fs->fs_ncg);
                   1267:        fs->fs_bsize                    = be32toh(fs->fs_bsize);
                   1268:        fs->fs_fsize                    = be32toh(fs->fs_fsize);
                   1269:        fs->fs_frag                             = be32toh(fs->fs_frag);
                   1270:        fs->fs_minfree                  = be32toh(fs->fs_minfree);
                   1271:        fs->fs_old_rotdelay             = be32toh(fs->fs_old_rotdelay);
                   1272:        fs->fs_old_rps                  = be32toh(fs->fs_old_rps);
                   1273:        fs->fs_bmask                    = be32toh(fs->fs_bmask);
                   1274:        fs->fs_fmask                    = be32toh(fs->fs_fmask);
                   1275:        fs->fs_bshift                   = be32toh(fs->fs_bshift);
                   1276:        fs->fs_fshift                   = be32toh(fs->fs_fshift);
                   1277:        fs->fs_maxcontig                = be32toh(fs->fs_maxcontig);
                   1278:        fs->fs_maxbpg                   = be32toh(fs->fs_maxbpg);
                   1279:        fs->fs_fragshift                = be32toh(fs->fs_fragshift);
                   1280:        fs->fs_fsbtodb                  = be32toh(fs->fs_fsbtodb);
                   1281:        fs->fs_sbsize                   = be32toh(fs->fs_sbsize);
                   1282:        //fs->fs_spare1[2]
                   1283:        fs->fs_nindir                   = be32toh(fs->fs_nindir);
                   1284:        fs->fs_inopb                    = be32toh(fs->fs_inopb);
                   1285:        fs->fs_old_nspf                 = be32toh(fs->fs_old_nspf);
                   1286:        fs->fs_optim                    = be32toh(fs->fs_optim);
                   1287:        fs->fs_old_npsect               = be32toh(fs->fs_old_npsect);
                   1288:        fs->fs_old_interleave   = be32toh(fs->fs_old_interleave);
                   1289:        fs->fs_old_trackskew    = be32toh(fs->fs_old_trackskew);
                   1290:        fs->fs_id[0]                    = be32toh(fs->fs_id[0]);
                   1291:        fs->fs_id[1]                    = be32toh(fs->fs_id[1]);
                   1292:        fs->fs_old_csaddr               = be32toh(fs->fs_old_csaddr);
                   1293:        fs->fs_cssize                   = be32toh(fs->fs_cssize);
                   1294:        fs->fs_cgsize                   = be32toh(fs->fs_cgsize);
                   1295:        fs->fs_spare2                   = be32toh(fs->fs_spare2);
                   1296:        fs->fs_old_nsect                = be32toh(fs->fs_old_nsect);
                   1297:        fs->fs_old_spc                  = be32toh(fs->fs_old_spc);
                   1298:        fs->fs_old_ncyl                 = be32toh(fs->fs_old_ncyl);
                   1299:        fs->fs_old_cpg                  = be32toh(fs->fs_old_cpg);
                   1300:        fs->fs_ipg                              = be32toh(fs->fs_ipg);
                   1301:        fs->fs_fpg                              = be32toh(fs->fs_fpg);
                   1302:        //struct csum fs_old_cstotal
                   1303:        //u_char fs_fsmnt[MAXMNTLEN]
                   1304:        //u_char fs_volname[MAXVOLLEN]
                   1305:        fs->fs_swuid                    = be64toh(fs->fs_swuid);
                   1306:        fs->fs_pad                              = be32toh(fs->fs_pad);
                   1307:        fs->fs_cgrotor                  = be32toh(fs->fs_cgrotor);
                   1308:        //void *fs_ocsp[NOCSPTRS]
                   1309:        //struct csum *fs_csp
                   1310:        //uint32_t *fs_maxcluster
                   1311:        //u_char *fs_active
                   1312:        fs->fs_old_cpc                  = be32toh(fs->fs_old_cpc);
                   1313:        fs->fs_maxbsize                 = be32toh(fs->fs_maxbsize);
                   1314:        fs->fs_journal_flags    = be32toh(fs->fs_journal_flags);
                   1315:        //uint64_t fs->fs_journallocs[4]
                   1316:        fs->fs_quota_magic              = be32toh(fs->fs_quota_magic);
                   1317:        //uint64_t fs->fs_quotafile[2]
                   1318:        //uint64_t fs->fs_sparecon64[9]
                   1319:        fs->fs_sblockloc                = be64toh(fs->fs_sblockloc);
                   1320:        //struct csum_total fs_cstotal
                   1321:        fs->fs_time                             = be64toh(fs->fs_time);
                   1322:        fs->fs_size                             = be64toh(fs->fs_size);
                   1323:        fs->fs_dsize                    = be64toh(fs->fs_dsize);
                   1324:        fs->fs_csaddr                   = be64toh(fs->fs_csaddr);
                   1325:        fs->fs_pendingblocks    = be64toh(fs->fs_pendingblocks);
                   1326:        fs->fs_pendinginodes    = be32toh(fs->fs_pendinginodes);
                   1327:        // uint32_t fs->fs_snapinum[FSMAXSNAP]
                   1328:        fs->fs_avgfilesize              = be32toh(fs->fs_avgfilesize);
                   1329:        fs->fs_avgfpdir                 = be32toh(fs->fs_avgfpdir);
                   1330:        fs->fs_save_cgsize              = be32toh(fs->fs_save_cgsize);
                   1331:        // uint32_t fs->fs_sparecon32[26]
                   1332:        fs->fs_flags                    = be32toh(fs->fs_flags);
                   1333:        fs->fs_contigsumsize    = be32toh(fs->fs_contigsumsize);
                   1334:        fs->fs_maxsymlinklen    = be32toh(fs->fs_maxsymlinklen);
                   1335:        fs->fs_old_inodefmt             = be32toh(fs->fs_old_inodefmt);
                   1336:        fs->fs_maxfilesize              = be64toh(fs->fs_maxfilesize);
                   1337:        fs->fs_qbmask                   = be64toh(fs->fs_qbmask);
                   1338:        fs->fs_qfmask                   = be64toh(fs->fs_qfmask);
                   1339:        fs->fs_state                    = be32toh(fs->fs_state);
                   1340:        fs->fs_old_postblformat = be32toh(fs->fs_old_postblformat);
                   1341:        fs->fs_old_nrpos                = be32toh(fs->fs_old_nrpos);
                   1342:        // uint32_t fs->fs_spare5[2]
                   1343:        fs->fs_magic                    = be32toh(fs->fs_magic);
                   1344: 
                   1345:        // マジック
                   1346:        if (fs->fs_magic != FS_UFS1_MAGIC) {
                   1347:                errstr = string_format("Bad superblock magic 0x%08x (!= 0x%08x)",
                   1348:                        fs->fs_magic, FS_UFS1_MAGIC);
                   1349:                return false;
                   1350:        }
                   1351: 
                   1352:        // なんとなく主要なパラメータを表示してみるか
                   1353:        if (parent->loglevel >= 2) {
                   1354:                uint32 sblkno = fs->fs_sblkno;          // super block in filesys
                   1355:                uint32 cblkno = fs->fs_cblkno;          // cylinder group block in filesys
                   1356:                uint32 iblkno = fs->fs_iblkno;          // inode block in filesys
                   1357:                uint32 dblkno = fs->fs_dblkno;          // data block in filesys
                   1358:                uint32 bsize  = fs->fs_bsize;           // size of basic blocks
                   1359:                uint32 ipg    = fs->fs_ipg;                     // inodes per group
                   1360:                uint32 fpg    = fs->fs_fpg;                     // blocks per group x fs_frag
                   1361:                uint32 old_cgoffset = fs->fs_old_cgoffset;      // cg. offset in cyl.
                   1362: 
                   1363:                parent->putmsg("%s fs.fs_sblkno=0x%x (0x%x)",
                   1364:                        __func__, sblkno, sblkno * 512);
                   1365:                parent->putmsg("%s fs.fs_cblkno=0x%x (0x%x)",
                   1366:                        __func__, cblkno, cblkno * 512);
                   1367:                parent->putmsg("%s fs.fs_dblkno=0x%x (0x%x)",
                   1368:                        __func__, dblkno, dblkno * 512);
                   1369:                parent->putmsg("%s fs.fs_iblkno=0x%x (0x%x)",
                   1370:                        __func__, iblkno, iblkno * 512);
                   1371:                parent->putmsg("%s fs.fs_bsize=0x%x", __func__, bsize);
                   1372:                parent->putmsg("%s fs.fs_ipg=0x%x", __func__, ipg);
                   1373:                parent->putmsg("%s fs.fs_fpg=0x%x", __func__, fpg);
                   1374:                parent->putmsg("%s fs.fs_old_cgoffset=0x%x", __func__, old_cgoffset);
                   1375:        }
                   1376: 
                   1377:        return true;
                   1378: }
                   1379: 
                   1380: // inode.ino で指定された disk inode 情報を inode.di に返す
                   1381: bool
                   1382: Filesys::Readi(inodefile& inode)
                   1383: {
                   1384:        // di は inode のディスク上の記録構造で 128 バイト長。
                   1385:        // 詳細は <ufs/ufs/dinode.h> の ufs1_dinode 参照。
                   1386:        // 基本的には inode ブロックにこの dinode が配列のように並んでいるが
                   1387:        // シリンダグループを越えるためには謎のマクロを使う。
                   1388:        // sys/lib/libsa/ufs.c 参照。
                   1389:        //
                   1390:        // dinode のうち、ここで関係するかも知れないのは
                   1391:        //  di_mode (のうちファイルモード)
                   1392:        //  di_size (ファイルサイズ)
                   1393:        //  di_db[] (直接ブロック)
                   1394:        //  di_ib[] (間接ブロック)
                   1395:        //  di_blocks (ブロック数)
                   1396:        // くらいか。
                   1397: 
                   1398:        uint32 ino = inode.ino;
                   1399:        struct ufs1_dinode *di = &inode.di;
                   1400: 
                   1401:        // ino が含まれるブロックを読み込む
1.1.1.2   root     1402:        std::vector<char> buf(fs->fs_bsize);
1.1       root     1403:        uint32 ino_sector = FFS_FSBTODB(fs, ino_to_fsba(fs, ino));
1.1.1.2   root     1404:        hd->PeekImage(&buf[0], part_start + ino_sector * 512, buf.size());
1.1       root     1405: 
                   1406:        // ino で示される inode を取得
1.1.1.2   root     1407:        *di = ((ufs1_dinode *)(&buf[0]))[ino_to_fsbo(fs, ino)];
1.1       root     1408:        uint16 di_mode   = be16toh(di->di_mode);
                   1409:        uint16 di_nlink  = be16toh(di->di_nlink);
                   1410:        uint64 di_size   = be64toh(di->di_size);
                   1411:        parent->putmsg(2, "%s di[%d].di_mode=%05o di_nlink=%d di_size=%" PRIu64,
                   1412:                __func__, ino, di_mode, di_nlink, di_size);
                   1413: 
                   1414:        return true;
                   1415: }
                   1416: 
                   1417: // inode.di で指定されたファイル(またはディレクトリ)の本文を
                   1418: // inode.data に返す
                   1419: bool
                   1420: Filesys::ReadData(inodefile& inode)
                   1421: {
                   1422:        // di (ufs1_dinode) にはこの inode (ファイルまたはディレクトリ)の
                   1423:        // データの格納ブロックが記録されている。ディレクトリとは中身が
                   1424:        // ディレクトリエントリであるファイルと同じ構造のもの。
                   1425:        //  di_db[] (直接ブロック)
                   1426:        //  di_ib[] (間接ブロック)
                   1427:        //  di_blocks (実際に使用しているブロック数)
                   1428:        //
                   1429:        // 直接ブロック di_db[] は12要素の配列で、データブロックの位置が
                   1430:        // 記録されている (未使用なら 0 のようだ)。
                   1431:        // データブロックは fs->fs_bsize でたぶん基本 4KB のやつ。
                   1432:        // これもパーティション先頭からのセクタ番号で表記される。なので
                   1433:        // ディスク上で連続しているファイルなら di_db[N] と di_db[N + 1] は
                   1434:        // 8 ずつ増えてるのが見えるはず。
                   1435:        // 例えば以下のサンプル断片は、直接ブロック2つでセクタ 100 から
                   1436:        // セクタ 115 までの連続する 16KB を所有している様子を示している。
                   1437:        //
                   1438:        //                        #100   #101   #102          #107
                   1439:        //                      +------+------+------+- .. -+------+
                   1440:        // di_db[0] = 100  ---> | Data | Data | Data |      | Data |
                   1441:        //                      +------+------+------+- .. -+------+
                   1442:        //
                   1443:        //                        #108                        #115
                   1444:        //                      +------+------+------+- .. -+------+
                   1445:        // di_db[1] = 108  ---> | Data | Data | Data |      | Data |
                   1446:        //                      +------+------+------+- .. -+------+
                   1447:        //
                   1448:        // 間接ブロック di_ib[0], [1], [2] はそれぞれ一次、二次、三次の
                   1449:        // 間接記録になっている。一次間接だとこういう感じ。
                   1450:        //
                   1451:        //                        #120
                   1452:        //                      +--------+           +------+- ..
                   1453:        // di_ib[0] = 120  ---> | #200  ------> #200 | Data |
                   1454:        //                      |        |           +------+- ..
                   1455:        //                      | #208  ------> #208 | Data |
                   1456:        //                      +--------+           +------+- ..
                   1457:        //
                   1458: 
                   1459:        uint32 ino = inode.ino;
                   1460:        struct ufs1_dinode *di = &inode.di;
                   1461:        std::vector<uint8>& data = inode.data;
                   1462:        uint64 bsize64 = (uint64)fs->fs_bsize;
                   1463: 
                   1464:        uint64 di_size   = be64toh(di->di_size);
                   1465:        uint32 di_blocks = be32toh(di->di_blocks);
                   1466:        // di->di_db[] にファイル(またはディレクトリ)の内容の位置が並んでいる
                   1467:        if (parent->loglevel >= 2) {
                   1468:                parent->putmsg("%s di[%d].di_blocks=%u", __func__, ino, di_blocks);
                   1469: 
                   1470:                std::string dbstr;
                   1471:                for (int i = 0; i < UFS_NDADDR; i++) {
                   1472:                        dbstr += string_format(" %u", be32toh(di->di_db[i]));
                   1473:                }
                   1474:                parent->putmsg("%s di[%d].di_db[]=%s",
                   1475:                        __func__, ino, dbstr.c_str() + 1);
                   1476: 
                   1477:                std::string distr;
                   1478:                for (int i = 0; i < UFS_NIADDR; i++) {
                   1479:                        distr += string_format(" %u", be32toh(di->di_ib[i]));
                   1480:                }
                   1481:                parent->putmsg("%s di[%d].di_ib[]=%s",
                   1482:                        __func__, ino, distr.c_str() + 1);
                   1483:        }
                   1484: 
                   1485:        uint64 offset = 0;      // 次に読み込む位置 (ここまでに読み込んだバイト数)
                   1486: 
                   1487:        // サイズが分かっているのであらかじめ確保しておく
                   1488:        data.resize(di_size);
                   1489: 
                   1490:        // 直接ブロック
                   1491:        for (int i = 0; i < countof(di->di_db); i++) {
                   1492:                uint64 remain = di_size - offset;       // 残りバイト数
                   1493:                uint32 nbytes = std::min(remain, bsize64);      // 今回読み込み分
                   1494:                hd->PeekImage(&data[offset], be32toh(di->di_db[i]) * 512, nbytes);
                   1495:                offset += nbytes;
                   1496:                if (offset >= di_size)
                   1497:                        break;
                   1498:        }
                   1499:        // 一次間接ブロック
1.1.1.2   root     1500:        std::vector<uint32> ib0buf(fs->fs_bsize / sizeof(uint32));
                   1501:        hd->PeekImage(&ib0buf[0], be32toh(di->di_ib[0]) * 512,
                   1502:                ib0buf.size() * sizeof(uint32));
1.1       root     1503:        if (parent->loglevel >= 2) {
                   1504:                std::string distr;
1.1.1.2   root     1505:                for (const auto& x : ib0buf) {
                   1506:                        if (x == 0)
1.1       root     1507:                                break;
1.1.1.2   root     1508:                        distr += string_format(" %u", be32toh(x));
1.1       root     1509:                }
                   1510:                parent->putmsg("%s di[%d].di_ib[0]=%s",
                   1511:                        __func__, ino, distr.c_str() + 1);
                   1512:        }
1.1.1.2   root     1513:        for (const auto& x : ib0buf) {
1.1       root     1514:                uint64 remain = di_size - offset;       // 残りバイト数
                   1515:                uint32 nbytes = std::min(remain, bsize64);      // 今回読み込み分
1.1.1.2   root     1516:                hd->PeekImage(&data[offset], be32toh(x) * 512, nbytes);
1.1       root     1517:                offset += nbytes;
                   1518:                if (offset >= di_size)
                   1519:                        break;
                   1520:        }
                   1521: 
                   1522:        // 二次、三次ブロックは未対応
                   1523:        if (offset < di_size) {
                   1524:                PANIC("di_ib[1] not supported");
                   1525:        }
                   1526: 
                   1527:        return true;
                   1528: }
                   1529: 
                   1530: // ディレクトリエントリ dirbuf から name で指定されるファイル名に対応する
                   1531: // inode 番号を返す。見付からなければ 0 を返す。
                   1532: uint32
                   1533: inodefile::FindFile(const std::string& name)
                   1534: {
                   1535:        // ディレクトリエントリは可変長で並んでいる。
                   1536:        // d->d_reclen がこの1つ分のエントリの長さなので、次のエントリ位置は
                   1537:        // このエントリの頭から d->d_reclen を足したところになる。
                   1538:        // 最終エントリの d_reclen を足すとバッファ末尾になるようになっている
                   1539:        // ようだ。
                   1540:        const char *dp = (const char *)(data.data());
                   1541:        const char *dend = dp + data.size();
                   1542:        uint32 file_ino;
                   1543:        uint16 reclen;
                   1544: 
                   1545:        for (; dp < dend; dp += reclen) {
                   1546:                const struct direct *d = (const struct direct *)dp;
                   1547:                file_ino = be32toh(d->d_fileno);
                   1548:                reclen = be16toh(d->d_reclen);
                   1549: 
                   1550:                std::string str = string_format("ino=%u reclen=%u name=|%s|",
                   1551:                        file_ino, reclen, d->d_name);
                   1552:                if (strcmp(name.c_str(), d->d_name) == 0) {
                   1553:                        parent->putmsg(2, "%s %s found", __func__, str.c_str());
1.1.1.2   root     1554:                        return file_ino;
1.1       root     1555:                } else {
                   1556:                        parent->putmsg(2, "%s %s skip", __func__, str.c_str());
                   1557:                }
                   1558:        }
1.1.1.2   root     1559:        parent->putmsg(2, "%s %s not found", __func__, name.c_str());
                   1560:        return 0;
1.1       root     1561: }

unix.superglobalmegacorp.com

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