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

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

unix.superglobalmegacorp.com

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