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

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

unix.superglobalmegacorp.com

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