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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2024 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
1.1.1.2   root        8: // virt-m68k の IPLROM 相当の何か
1.1       root        9: //
                     10: 
1.1.1.2   root       11: // IODevice
                     12: //  |
                     13: //  +- ROMDevice (LoadROM()、ウェイト、マスク等を持つ)
                     14: //  |   +- PROMDevice    (LUNA* の PROM)
                     15: //  |   +- IPLROM1Device (X680x0 の IPLROM 後半)
                     16: //  |   +- IPLROM2Device (X680x0 の IPLROM 前半)
                     17: //  |   +- CGROMDevice   (X680x0 の CGROM)
                     18: //  |   |
                     19: //  |   +- ROMEmuDevice
                     20: //  |       +- LunaPROMEmuDevice (LUNA PROM エミュレーションの共通部分)
                     21: //  |       |   +- Luna1PROMEmuDevice   (LUNA-I の PROM エミュレーション)
                     22: //  |       |   +- Luna88kPROMEmuDevice (LUNA-88K の PROM エミュレーション)
                     23: //  |       +- NewsROMEmuDevice (NEWS の ROM エミュレーション)
                     24: //  |       +- ROM30EmuDevice   (X68030 の ROM30 エミュレーション)
                     25: //  |       |
                     26: //  |       | +---------------------+
                     27: //  |       +-| Virt68kROMEmuDevice | (virt-m68k の IPLROM 相当の何か)
                     28: //  |         +---------------------+
                     29: //  |
                     30: //  +- PROM0Device   (LUNA* のブートページ切り替え用プロキシ)
                     31: //  +- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ)
                     32: 
1.1       root       33: #include "romemu_virt68k.h"
                     34: #include "autofd.h"
                     35: #include "config.h"
1.1.1.2   root       36: #include "iodevstream.h"
1.1       root       37: #include "mainapp.h"
                     38: #include "mainram.h"
                     39: #include "memorystream.h"
1.1.1.3   root       40: #include "mpu680x0.h"
1.1.1.6 ! root       41: #include "power.h"
1.1       root       42: #include <fcntl.h>
                     43: #include <sys/stat.h>
                     44: #include <sys/mman.h>
                     45: #include <random>
                     46: 
                     47: // コンストラクタ
                     48: Virt68kROMEmuDevice::Virt68kROMEmuDevice()
                     49:        : inherited(OBJ_PROM)
                     50: {
                     51: }
                     52: 
                     53: // デストラクタ
                     54: Virt68kROMEmuDevice::~Virt68kROMEmuDevice()
                     55: {
                     56: }
                     57: 
                     58: // 初期化
                     59: bool
                     60: Virt68kROMEmuDevice::Init()
                     61: {
1.1.1.5   root       62:        // ROM 領域を用意。サイズは適当。
                     63:        if (AllocROM(2048, 0) == false) {
1.1.1.6 ! root       64:                // エラーメッセージは表示済み。
1.1.1.5   root       65:                return false;
                     66:        }
                     67: 
1.1       root       68:        mainram = GetMainRAMDevice();
                     69: 
1.1.1.2   root       70:        MemoryStreamBE roms(imagebuf.get());
                     71:        roms.Write4(0x00001000);        // +00: リセットベクタ SP
                     72:        roms.Write4(0xff000400);        // +04: リセットベクタ PC
1.1       root       73:        // ベクタ
                     74:        for (int i = 2; i < 256; i++) {
1.1.1.2   root       75:                roms.Write4(0);
1.1       root       76:        }
                     77: 
                     78:        // リセット時に実行する命令
1.1.1.2   root       79:        roms.SetOffset(0x400);
                     80:        roms.Write2(0x2039);            //      move.l  (ROMIO_INIT),d0
                     81:        roms.Write4(ROMIO_INIT);
                     82:        roms.Write2(0x0c80);            //      cmpi.l  #0xffffffff,d0
                     83:        roms.Write4(0xffffffff);
                     84:        roms.Write2(0x6704);            //      beq             @f
                     85:        roms.Write2(0x2040);            //      move.l  d0,a0   ; ジャンプ先を a0 にセット
                     86:        roms.Write2(0x4ed0);            //      jmp             (a0)    ; ジャンプ
1.1       root       87:                                                                //@@:
1.1.1.2   root       88:        roms.Write4(0x4e722700);        //      stop    #0x2700
                     89:        roms.Write2(0x67fc);            //      bra             @b
1.1       root       90: 
                     91:        return true;
                     92: }
                     93: 
                     94: void
                     95: Virt68kROMEmuDevice::ResetHard(bool poweron)
                     96: {
                     97:        // 起動時に RAM にリセットベクタを書き込んでおく。(手抜き)
1.1.1.2   root       98:        mainram->WriteMem(0, &imagebuf[0], 8);
1.1       root       99: }
                    100: 
1.1.1.2   root      101: // ROMIO から読み出す。
                    102: // ROMIO が応答すべきでなければ (uint64)-1 を返す。
                    103: uint64
                    104: Virt68kROMEmuDevice::ReadROMIO(busaddr addr)
1.1       root      105: {
1.1.1.2   root      106:        if (addr.GetSize() == 4) {
                    107:                switch (addr.Addr()) {
                    108:                 case ROMIO_INIT:
                    109:                        return ROM_Init();
1.1       root      110: 
1.1.1.2   root      111:                 default:
                    112:                        break;
                    113:                }
1.1       root      114:        }
                    115: 
1.1.1.2   root      116:        return (uint64)-1;
1.1       root      117: }
                    118: 
                    119: uint32
                    120: Virt68kROMEmuDevice::ROM_Init()
                    121: {
                    122:        // -X file で指定されたホストファイルを読み込んでエントリポイント
                    123:        // アドレスをこの Read アクセスの読み出し値として返す。
                    124: 
                    125:        LoadInfo info(gMainApp.exec_file);
                    126:        // QEMU がシンボルテーブルをロードしないので、
                    127:        // カーネル側もそのように想定しているようだ。
                    128:        info.loadsym = false;
                    129: 
1.1.1.5   root      130:        if (BootLoader::LoadExec(mainram, &info) == false) {
1.1.1.6 ! root      131:                // エラーメッセージは表示済み。
        !           132:                auto power = GetPowerDevice();
        !           133:                power->PushPowerButton();
1.1       root      134:                return -1;
                    135:        }
                    136: 
                    137:        if (MakeBootInfo(&info) == false) {
                    138:                return -1;
                    139:        }
                    140: 
                    141:        putmsg(1, "Host program loaded.  Entry point = $%08x", info.entry);
                    142: 
                    143:        return info.entry;
                    144: }
                    145: 
                    146: // ブート情報を便利に扱うためのクラス。
                    147: class BootInfo
                    148: {
                    149:  public:
                    150:        uint16 bi_tag {};                               // タグ
                    151:        std::vector<uint8> bi_data {};  // タグごと決まる可変のデータ
                    152: 
                    153:  public:
                    154:        BootInfo();
                    155: 
                    156:        void Init(uint16 tag_);
                    157:        void Init(uint16 tag_, uint32 val_);
                    158:        void AddWord(uint32 val_);
                    159:        void AddLong(uint32 val_);
1.1.1.3   root      160:        void AddString(const char *val_);
1.1       root      161: 
                    162:        uint32 GetWord(uint32 offset) const;
                    163:        uint32 GetLong(uint32 offset) const;
1.1.1.3   root      164:        const char *GetString() const { return (const char *)bi_data.data(); }
1.1       root      165: };
                    166: 
                    167: // コンストラクタ
                    168: BootInfo::BootInfo()
                    169: {
                    170: }
                    171: 
                    172: // タグだけ指定して初期化。
                    173: void
                    174: BootInfo::Init(uint16 tag_)
                    175: {
                    176:        bi_tag = tag_;
                    177:        bi_data.clear();
                    178: }
                    179: 
                    180: // タグと整数1つを指定して初期化。
                    181: void
                    182: BootInfo::Init(uint16 tag_, uint32 val_)
                    183: {
                    184:        Init(tag_);
                    185:        AddLong(val_);
                    186: }
                    187: 
                    188: // データに 16 ビット整数を1つ追加。
                    189: void
                    190: BootInfo::AddWord(uint32 val_)
                    191: {
                    192:        // bi_data はビッグエンディアン
                    193:        bi_data.push_back(val_ >> 8);
                    194:        bi_data.push_back(val_);
                    195: }
                    196: 
                    197: // データに 32 ビット整数を1つ追加。
                    198: void
                    199: BootInfo::AddLong(uint32 val_)
                    200: {
                    201:        // bi_data はビッグエンディアン
                    202:        bi_data.push_back(val_ >> 24);
                    203:        bi_data.push_back(val_ >> 16);
                    204:        bi_data.push_back(val_ >> 8);
                    205:        bi_data.push_back(val_);
                    206: }
                    207: 
1.1.1.3   root      208: // データに文字列を追加する。
                    209: void
                    210: BootInfo::AddString(const char *val_)
                    211: {
                    212:        for (const char *s = val_; *s; s++) {
                    213:                bi_data.push_back(*s);
                    214:        }
                    215:        bi_data.push_back('\0');
                    216: }
                    217: 
1.1       root      218: // offset の位置からの 16 ビット整数を取得。
                    219: uint32
                    220: BootInfo::GetWord(uint32 offset) const
                    221: {
                    222:        if (offset + 2 > bi_data.size()) {
                    223:                return -1;
                    224:        }
                    225:        uint32 data;
                    226:        data  = bi_data[offset + 0] << 8;
                    227:        data |= bi_data[offset + 1];
                    228:        return data;
                    229: }
                    230: 
                    231: // offset の位置からの 32 ビット整数を取得。
                    232: uint32
                    233: BootInfo::GetLong(uint32 offset) const
                    234: {
                    235:        if (offset + 4 > bi_data.size()) {
                    236:                return -1;
                    237:        }
                    238:        uint32 data;
                    239:        data  = GetWord(offset + 0) << 16;
                    240:        data |= GetWord(offset + 2);
                    241:        return data;
                    242: }
                    243: 
                    244: 
                    245: // BootInfo について。
                    246: //
                    247: // 伝統的な(?) NetBSD アーキテクチャは、ブートローダからカーネルへの
                    248: // パラメータはレジスタ渡しかスタック渡しでアーキテクチャごとに固定の
                    249: // フォーマットになっている。少なくともいくつかの m68k では。
1.1.1.2   root      250: // NetBSD/virt68k では Linux/m68k の方式を採用しているようだが、
                    251: // これは virt-m68k がそういう仕様だから。
1.1       root      252: //
                    253: // NetBSD/virt68k のブートパラメータ BootInfo は、カーネルがロードされた
                    254: // セクションの末尾 (リンカによってアドレスが求まる) 以降の次のロングワード
                    255: // 境界から連続して配置する。BootInfo はいわゆる Type-Length-Value (TLV)
                    256: // 形式のデータで、基本フォーマットは次の通り。
                    257: //
                    258: //  struct {
                    259: //    uint16 bi_tag;
                    260: //    uint16 bi_size;
                    261: //    uint8[] bi_data;
                    262: //  };
                    263: //
                    264: // bi_tag がこのパラメータの種別を表し、BI_LAST(=0) のタグで終了する。
                    265: // bi_size はタグとサイズフィールドも含めたバイト数。
                    266: // bi_data は 0 バイト以上の可変長データで、内容はタグによって決まっている。
                    267: // 各パラメータはロングワード境界に整列していること。
                    268: //
                    269: // これによって、ブートローダというかエミュレータ本体から自由度の高い
                    270: // パラメータを受け渡すことが出来る。例えば通常の m68k カーネルが自力で
                    271: // 判別している CPU 種別や FPU 種別、デバイスがどのアドレス・IRQ にあるか
                    272: // といったハードウェア構成情報もすべてブートパラメータで渡す。
                    273: 
                    274: // ブートパラメータを用意。
                    275: bool
                    276: Virt68kROMEmuDevice::MakeBootInfo(LoadInfo *info)
                    277: {
                    278:        IODeviceStream ds(mainram, info->end);
                    279:        BootInfo bi;
1.1.1.3   root      280:        uint32 cpu_type;
                    281:        uint32 mmu_type;
                    282:        uint32 fpu_type;
                    283: 
                    284:        auto mpu680x0 = GetMPU680x0Device(mpu);
                    285:        switch (mpu680x0->GetMPUType()) {
                    286:         case m680x0MPUType::M68030:
                    287:                cpu_type = BI_CPU_68030;
                    288:                mmu_type = BI_MMU_68030;
                    289:                if (mpu680x0->HasFPU()) {
                    290:                        fpu_type = BI_FPU_68881;
                    291:                } else {
                    292:                        fpu_type = 0;
                    293:                }
                    294:                break;
                    295:         case m680x0MPUType::M68040:
                    296:                cpu_type = BI_CPU_68040;
                    297:                mmu_type = BI_MMU_68040;
                    298:                fpu_type = BI_FPU_68040;
                    299:                break;
                    300:         default:
                    301:                assert(false);
                    302:        }
1.1       root      303: 
                    304:        bi.Init(BI_MACHTYPE, BI_MACH_VIRT);
                    305:        WriteBootInfo(ds, bi);
                    306: 
1.1.1.3   root      307:        bi.Init(BI_CPUTYPE, cpu_type);
1.1       root      308:        WriteBootInfo(ds, bi);
                    309: 
1.1.1.3   root      310:        bi.Init(BI_MMUTYPE, mmu_type);
1.1       root      311:        WriteBootInfo(ds, bi);
                    312: 
1.1.1.3   root      313:        if (fpu_type != 0) {
                    314:                bi.Init(BI_FPUTYPE, fpu_type);
                    315:                WriteBootInfo(ds, bi);
                    316:        }
1.1       root      317: 
1.1.1.5   root      318:        uint32 ramsize = (uint32)mainram->GetSize();
1.1       root      319: 
                    320:        // RAMDISK は (あれば) initrd イメージ置き場で、
                    321:        // メモリセグメントとは別セグメントにする必要がある。
                    322:        // そのためここでは MainRAM の末尾に置く。
                    323:        const ConfigItem& initrd_item = gConfig->Find("exec-initrd");
                    324:        const std::string& initrd = initrd_item.AsString();
                    325:        if (initrd.empty() == false) {
                    326:                std::string path = gMainApp.NormalizePath(initrd);
                    327:                const char *cpath = path.c_str();
                    328:                autofd fd;
                    329:                struct stat st;
                    330:                uint8 *mdata;
                    331:                size_t rdsize;
                    332: 
                    333:                fd = open(cpath, O_RDONLY);
                    334:                if (fd == -1) {
1.1.1.6 ! root      335:                        warn("%s \"%s\" open failed", __method__, cpath);
1.1       root      336:                        return false;
                    337:                }
                    338: 
                    339:                if (fstat(fd, &st) == -1) {
1.1.1.6 ! root      340:                        warn("%s \"%s\" fstat failed", __method__, cpath);
1.1       root      341:                        return false;
                    342:                }
                    343: 
                    344:                if (S_ISDIR(st.st_mode)) {
1.1.1.6 ! root      345:                        warnx("%s \"%s\" is a directory", __method__, cpath);
1.1       root      346:                        return false;
                    347:                }
                    348:                rdsize = st.st_size;
                    349: 
                    350:                mdata = (uint8 *)mmap(NULL, rdsize, PROT_READ, MAP_PRIVATE, fd, 0);
                    351:                if (mdata == MAP_FAILED) {
1.1.1.6 ! root      352:                        warnx("%s \"%s\" mmap failed", __method__, cpath);
1.1       root      353:                        return false;
                    354:                }
                    355: 
                    356:                // ロード。
                    357:                LoadInfo rdinfo(cpath, mdata, rdsize);
                    358:                rdinfo.start = (ramsize - rdsize) & ~0xfff;
1.1.1.5   root      359:                bool rv = BootLoader::LoadData(mainram, &rdinfo);
1.1       root      360:                munmap(mdata, rdsize);
                    361:                if (rv == false) {
                    362:                        warnx("** Couldn't load specified initrd.");
                    363:                        return false;
                    364:                }
                    365: 
                    366:                bi.Init(BI_RAMDISK);
                    367:                bi.AddLong(rdinfo.start);       // bi_mem_info.addr
                    368:                bi.AddLong(rdsize);                     // bi_mem_info.size
                    369:                WriteBootInfo(ds, bi);
                    370: 
                    371:                // ここをメモリ上限にする。
                    372:                ramsize = rdinfo.start;
                    373:        }
                    374: 
                    375:        // MEMCHUNK は RAM 配置情報。
                    376:        bi.Init(BI_MEMCHUNK);
                    377:        bi.AddLong(0);                  // bi_mem_info.addr
                    378:        bi.AddLong(ramsize);    // bi_mem_info.size
                    379:        WriteBootInfo(ds, bi);
                    380: 
                    381:        // 乱数シード。QEMU は 32 バイト渡してるようだ。
                    382:        std::random_device rng;
                    383:        const uint32 rng_bytes = 32;
                    384:        bi.Init(BI_RNG_SEED);
                    385:        bi.AddWord(rng_bytes);  // bi_data.data_length
                    386:        for (int i = 0; i < rng_bytes / 4; i++) {
                    387:                bi.AddLong(rng());      // bi_data.data_bytes
                    388:        }
                    389:        WriteBootInfo(ds, bi);
                    390: 
                    391:        // GFPIC
                    392:        // 先頭のデバイスのアドレスとベース IRQ だけ指定する。
                    393:        // アドレスを +$1000 番地、IRQ は +1 ずつずらして計 6個あるというのは
                    394:        // カーネル側にハードコードしてあるようだ。
                    395:        //  $ff01'1000 IRQ=1 : GFPIC1
                    396:        //  $ff01'2000 IRQ=2 : GFPIC2
                    397:        //  $ff01'3000 IRQ=3 : GFPIC3
                    398:        //  $ff01'4000 IRQ=4 : GFPIC4
                    399:        //  $ff01'5000 IRQ=5 : GFPIC5
                    400:        //  $ff01'6000 IRQ=6 : GFPIC6
                    401:        bi.Init(BI_GFPIC);
                    402:        bi.AddLong(0xff011000); // addr
                    403:        bi.AddLong(1);                  // irq
                    404:        WriteBootInfo(ds, bi);
                    405: 
                    406:        // GFRTC
                    407:        // 先頭アドレスと IRQ だけ指定する。
                    408:        // アドレスを +$1000 番地したところに GFRTC があるというのは
                    409:        // カーネル側にハードコードしてあるようだ。
                    410:        //  $ff02'0000 IRQ=PIC6:IRQ1 : GFTimer
                    411:        //  $ff02'1000               : GFRTC
                    412:        bi.Init(BI_GFRTC);
                    413:        bi.AddLong(0xff020000);                         // addr
                    414:        bi.AddLong(8 + (6 - 1) * 32 + 0);       // irq
                    415:        WriteBootInfo(ds, bi);
                    416: 
                    417:        // GFTTY
                    418:        // IRQ は PIC1:IRQ32
                    419:        bi.Init(BI_GFTTY);
                    420:        bi.AddLong(0xff030000);                         // addr
                    421:        bi.AddLong(8 + (1 - 1) * 32 + 31);      // irq
                    422:        WriteBootInfo(ds, bi);
                    423: 
                    424:        // QemuSysCtlr
                    425:        bi.Init(BI_CTRL);
                    426:        bi.AddLong(0xff040000);                         // addr
                    427:        bi.AddLong(0);                                          // irq
                    428:        WriteBootInfo(ds, bi);
                    429: 
                    430:        // VirtIO
                    431:        bi.Init(BI_VIRTIO);
                    432:        bi.AddLong(0xff070000);                         // addr
                    433:        bi.AddLong(8 + (2 - 1) * 32 + 0);       // base irq
                    434:        WriteBootInfo(ds, bi);
                    435: 
1.1.1.3   root      436:        // ブートパラメータ
                    437:        const ConfigItem& bootparam_item = gConfig->Find("exec-bootparam");
                    438:        const std::string& bootparam = bootparam_item.AsString();
                    439:        if (bootparam.empty() == false) {
                    440:                bi.Init(BI_COMMANDLINE);
                    441:                bi.AddString(bootparam.c_str());
                    442:                WriteBootInfo(ds, bi);
                    443:        }
                    444: 
1.1       root      445:        bi.Init(BI_LAST);
                    446:        WriteBootInfo(ds, bi);
                    447: 
                    448:        return true;
                    449: }
                    450: 
                    451: #define ENTRY(x)       { (x),  #x }
                    452: /*static*/ const std::pair<uint32, const char *>
                    453: Virt68kROMEmuDevice::tag_str[] = {
                    454:        ENTRY(BI_LAST),
                    455:        ENTRY(BI_MACHTYPE),
                    456:        ENTRY(BI_CPUTYPE),
                    457:        ENTRY(BI_FPUTYPE),
                    458:        ENTRY(BI_MMUTYPE),
                    459:        ENTRY(BI_MEMCHUNK),
                    460:        ENTRY(BI_RAMDISK),
                    461:        ENTRY(BI_COMMANDLINE),
                    462:        ENTRY(BI_RNG_SEED),
                    463: 
                    464:        ENTRY(BI_QEMU_VER),
                    465:        ENTRY(BI_GFPIC),
                    466:        ENTRY(BI_GFRTC),
                    467:        ENTRY(BI_GFTTY),
                    468:        ENTRY(BI_VIRTIO),
                    469:        ENTRY(BI_CTRL),
                    470: };
                    471: 
                    472: /*static*/ const std::pair<uint32, const char *>
                    473: Virt68kROMEmuDevice::mach_str[] = {
                    474:        ENTRY(BI_MACH_VIRT),
                    475: };
                    476: 
                    477: /*static*/ const std::pair<uint32, const char *>
                    478: Virt68kROMEmuDevice::cpu_str[] = {
                    479:        ENTRY(BI_CPU_68020),
                    480:        ENTRY(BI_CPU_68030),
                    481:        ENTRY(BI_CPU_68040),
                    482:        ENTRY(BI_CPU_68060),
                    483: };
                    484: 
                    485: /*static*/ const std::pair<uint32, const char *>
                    486: Virt68kROMEmuDevice::fpu_str[] = {
                    487:        ENTRY(BI_FPU_68881),
                    488:        ENTRY(BI_FPU_68882),
                    489:        ENTRY(BI_FPU_68040),
                    490:        ENTRY(BI_FPU_68060),
                    491: };
                    492: 
                    493: /*static*/ const std::pair<uint32, const char *>
                    494: Virt68kROMEmuDevice::mmu_str[] = {
                    495:        ENTRY(BI_MMU_68851),
                    496:        ENTRY(BI_MMU_68030),
                    497:        ENTRY(BI_MMU_68040),
                    498:        ENTRY(BI_MMU_68060),
                    499: };
                    500: #undef ENTRY
                    501: 
                    502: #define GetStr(array, v)       GetStr1(array, countof(array), v)
                    503: static std::string
                    504: GetStr1(const std::pair<uint32, const char *> *map, uint mapcount, uint32 v)
                    505: {
                    506:        for (int i = 0; i < mapcount; i++) {
                    507:                if (map[i].first == v) {
                    508:                        return map[i].second;
                    509:                }
                    510:        }
                    511:        return string_format("(%u)", v);
                    512: }
                    513: 
                    514: // BootInfo を stream に書き出す。
                    515: void
                    516: Virt68kROMEmuDevice::WriteBootInfo(IODeviceStream& stream, BootInfo& bi)
                    517: {
                    518:        // ロングワード境界にパディング。
                    519:        uint16 size = 2 + 2 + bi.bi_data.size();
                    520:        for (; (size % 4) != 0; size++) {
                    521:                bi.bi_data.push_back(0);
                    522:        }
                    523: 
                    524:        // デバッグ表示。
                    525:        if (__predict_false(loglevel >= 1)) {
                    526:                std::string tagname = GetStr(tag_str, bi.bi_tag);
                    527:                std::string buf;
                    528:                switch (bi.bi_tag) {
                    529:                 case BI_LAST:
                    530:                        break;
                    531:                 case BI_MACHTYPE:
                    532:                        buf = GetStr(mach_str, bi.GetLong(0));
                    533:                        break;
                    534:                 case BI_CPUTYPE:
                    535:                        buf = GetStr(cpu_str, bi.GetLong(0));
                    536:                        break;
                    537:                 case BI_FPUTYPE:
                    538:                        buf = GetStr(fpu_str, bi.GetLong(0));
                    539:                        break;
                    540:                 case BI_MMUTYPE:
                    541:                        buf = GetStr(mmu_str, bi.GetLong(0));
                    542:                        break;
                    543:                 case BI_MEMCHUNK:
                    544:                 case BI_RAMDISK:
                    545:                        buf = string_format("addr=$%08x, len=$%08x",
                    546:                                bi.GetLong(0), bi.GetLong(4));
                    547:                        break;
                    548:                 case BI_GFPIC:
                    549:                 case BI_GFRTC:
                    550:                 case BI_GFTTY:
                    551:                 case BI_VIRTIO:
                    552:                 case BI_CTRL:
                    553:                        buf = string_format("addr=$%08x, irq=$%08x",
                    554:                                bi.GetLong(0), bi.GetLong(4));
                    555:                        break;
                    556:                 case BI_RNG_SEED:
                    557:                        buf = string_format("len=%u", bi.GetWord(0));
                    558:                        break;
1.1.1.3   root      559:                 case BI_COMMANDLINE:
                    560:                        buf = string_format("\"%s\"", bi.GetString());
                    561:                        break;
1.1       root      562:                }
                    563:                putmsg(1, "BootInfo $%08x: %-14s: %s",
1.1.1.5   root      564:                        stream.GetAddr(), tagname.c_str(), buf.c_str());
1.1       root      565:        }
                    566: 
                    567:        // 出力。
1.1.1.2   root      568:        stream.Write2(bi.bi_tag);
                    569:        stream.Write2(size);
1.1       root      570:        for (const auto c : bi.bi_data) {
1.1.1.2   root      571:                stream.Write1(c);
1.1       root      572:        }
                    573: }

unix.superglobalmegacorp.com

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