Annotation of nono/vm/v68kio.cpp, revision 1.1.1.4

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 の I/O 空間担当
1.1       root        9: //
                     10: 
                     11: // メモリマップ。
1.1.1.2   root       12: // virt-m68k は $ff00'0000 以降が I/O 空間で、デバイス配置は
1.1       root       13: // ブートローダ (実質 BIOS) からカーネルにパラメータとして渡される。
                     14: // 各デバイスの先頭番地こそ自由だが、同種のデバイスが連続する場合
                     15: // 配置間隔がデバイスによって異なっておりその長さはハードコードのようだ。
                     16: // GF* は 0x1000 番地ずつ、VirtIO は 0x200 番地ずつとなっている。
                     17: //
                     18: // メモリマップはこんな感じにする。
                     19: //
                     20: // $ff00'0000-$ff00'ffff PROM
                     21: // $ff01'xxxx            Goldfish Interrupt(PIC) #1..#6
                     22: // $ff01'1000-$ff01'1fff  Lv1
                     23: // $ff01'2000-$ff01'2fff  Lv2
                     24: // $ff01'3000-$ff01'3fff  Lv3
                     25: // $ff01'4000-$ff01'4fff  Lv4
                     26: // $ff01'5000-$ff01'5fff  Lv5
                     27: // $ff01'6000-$ff01'6fff  Lv6
                     28: // $ff02'xxxx            Goldfish RTC+Timer
                     29: // $ff02'0000-$ff02'0fff  Timer
                     30: // $ff02'1000-$ff02'1fff  RTC
                     31: // $ff03'0000-$ff03'0fff Goldfish TTY
                     32: // $ff04'0000-$ff04'0fff Qemu Virtual System Controller
                     33: // $ff07'xxxx            VirtIO
                     34: //
                     35: // VirtIO は間隔が違うので最後に置く。
1.1.1.2   root       36: // ここは 1スロット $200 で、最大 128個まで置けるようだ。
1.1       root       37: // デバイスが存在しないスロットはバスエラーではなく、DEVICE_ID = INVALID
                     38: // で応答しなければならない。
                     39: //
1.1.1.2   root       40: // $ff07'0000-$ff07'01ff  VirtIO (slot $00)
                     41: // $ff07'0200-$ff07'03ff  VirtIO (slot $01)
1.1       root       42: //  :
1.1.1.2   root       43: // $ff07'fe00-$ff07'ffff  VirtIO (slot $7f)
1.1       root       44: 
                     45: #include "v68kio.h"
1.1.1.2   root       46: #include "busio.h"
1.1       root       47: #include "config.h"
                     48: #include "goldfish_pic.h"
                     49: #include "goldfish_rtc.h"
                     50: #include "goldfish_timer.h"
                     51: #include "goldfish_tty.h"
                     52: #include "qemusysctlr.h"
                     53: #include "romemu_virt68k.h"
                     54: #include "virtio_base.h"
                     55: #include "virtio_block.h"
1.1.1.2   root       56: #include "virtio_entropy.h"
1.1       root       57: #include "virtio_net.h"
1.1.1.4 ! root       58: #include "virtio_scsi.h"
1.1       root       59: #include "vm.h"
                     60: 
                     61: // コンストラクタ
                     62: V68kIODevice::V68kIODevice()
                     63:        : inherited(OBJ_V68KIO)
                     64: {
                     65:        NEWDV(PROM, new Virt68kROMEmuDevice());
1.1.1.2   root       66:        NEWDV(GFPIC1, new BusIO_L<GFPICDevice>(1));
                     67:        NEWDV(GFPIC2, new BusIO_L<GFPICDevice>(2));
                     68:        NEWDV(GFPIC3, new BusIO_L<GFPICDevice>(3));
                     69:        NEWDV(GFPIC4, new BusIO_L<GFPICDevice>(4));
                     70:        NEWDV(GFPIC5, new BusIO_L<GFPICDevice>(5));
                     71:        NEWDV(GFPIC6, new BusIO_L<GFPICDevice>(6));
                     72:        NEWDV(GFRTC, new BusIO_L<GFRTCDevice>());               // required by GFTimer
                     73:        NEWDV(GFTimer, new BusIO_L<GFTimerDevice>());
                     74:        NEWDV(GFTTY, new BusIO_L<GFTTYDevice>());
                     75:        NEWDV(QemuSysCtlr, new BusIO_L<QemuSysCtlrDevice>());
                     76:        NEWDV(VirtIONone, new BusIO_L<VirtIONoneDevice>());
1.1       root       77: 
                     78:        buserr = GetBusErrDevice();
                     79: 
                     80:        // まず全域をバスエラーで埋める。
                     81:        for (int i = 0; i < table.size(); i++) {
                     82:                table[i] = buserr;
                     83:        }
                     84: 
                     85:        // 少ないので手動で埋めていく。
                     86:        for (int i = 0; i < 0x10; i++) {
                     87:                table[i] = pPROM.get();
                     88:        }
                     89:        table[0x11] = pGFPIC1.get();
                     90:        table[0x12] = pGFPIC2.get();
                     91:        table[0x13] = pGFPIC3.get();
                     92:        table[0x14] = pGFPIC4.get();
                     93:        table[0x15] = pGFPIC5.get();
                     94:        table[0x16] = pGFPIC6.get();
                     95:        table[0x20] = pGFTimer.get();
                     96:        table[0x21] = pGFRTC.get();
                     97:        table[0x30] = pGFTTY.get();
                     98:        table[0x40] = pQemuSysCtlr.get();
                     99: 
                    100:        // VirtIO 用は、設定によるので後で代入する。
                    101:        // ここはバスエラーではない。
                    102:        for (int i = 0; i < viotable.size(); i++) {
                    103:                viotable[i] = pVirtIONone.get();
                    104:        }
                    105: }
                    106: 
                    107: // デストラクタ
                    108: V68kIODevice::~V68kIODevice()
                    109: {
                    110: }
                    111: 
                    112: // 動的なコンストラクション
                    113: bool
                    114: V68kIODevice::Create()
                    115: {
1.1.1.2   root      116:        uint slot;
1.1       root      117: 
1.1.1.2   root      118:        // (QEMU virt-m68k の?)
1.1       root      119:        // virtio はスロットによって割り込み先を固定してあるようだ。
                    120:        // スロット  0 .. 31 は PIC2(Lv2) の IRQ1..32、
                    121:        // スロット 32 .. 63 は PIC3(Lv3) の IRQ1..32、
                    122:        // スロット 64 .. 95 は PIC4(Lv4) の IRQ1..32、
                    123:        // スロット 96 ..127 は PIC5(Lv5) の IRQ1..32 となる。
                    124:        //
1.1.1.2   root      125:        // VirtIO* はとりあえず先例にならって Lv5 につなぐことにしてみる。
1.1       root      126:        slot = 96;
                    127: 
                    128:        // Net
                    129:        if (true) {
1.1.1.4 ! root      130:                try {
        !           131:                        pVirtIO[slot].reset(new BusIO_L<VirtIONetDevice>(slot));
        !           132:                } catch (...) { }
1.1.1.2   root      133:                if ((bool)pVirtIO[slot] == false) {
1.1.1.4 ! root      134:                        warnx("Failed to initialize VirtIONetDevice at %s", __method__);
1.1.1.2   root      135:                        return false;
                    136:                }
                    137:                viotable[slot] = pVirtIO[slot].get();
                    138:                slot++;
                    139:        }
                    140: 
                    141:        // Entropy
                    142:        if (true) {
1.1.1.4 ! root      143:                try {
        !           144:                        pVirtIO[slot].reset(new BusIO_L<VirtIOEntropyDevice>(slot));
        !           145:                } catch (...) { }
1.1       root      146:                if ((bool)pVirtIO[slot] == false) {
1.1.1.4 ! root      147:                        warnx("Failed to initialize VirtIOEntropyDevice at %s", __method__);
1.1       root      148:                        return false;
                    149:                }
                    150:                viotable[slot] = pVirtIO[slot].get();
                    151:                slot++;
                    152:        }
                    153: 
                    154:        // Block (とりあえず8個まで)
                    155:        for (int id = 0; id < 8; id++) {
1.1.1.2   root      156:                const std::string key = string_format("virtio-block%u-image", id);
1.1       root      157:                const ConfigItem& item = gConfig->Find(key);
                    158:                const std::string& image = item.AsString();
                    159: 
                    160:                // 空ならデバイスなし
                    161:                if (image.empty()) {
                    162:                        // 未接続部分のパラメータは減らしておくか。
                    163:                        // --show-config するとさすがに無駄に多くて邪魔なので。
1.1.1.2   root      164:                        gConfig->Delete(string_format("virtio-block%u-writeignore", id));
1.1       root      165:                        continue;
                    166:                }
                    167: 
1.1.1.4 ! root      168:                try {
        !           169:                        pVirtIO[slot].reset(new BusIO_L<VirtIOBlockDevice>(slot, id));
        !           170:                } catch (...) { }
1.1       root      171:                if ((bool)pVirtIO[slot] == false) {
1.1.1.4 ! root      172:                        warnx("Failed to initialize VirtIOBlockDevice(%u) at %s",
        !           173:                                id, __method__);
        !           174:                        return false;
        !           175:                }
        !           176:                viotable[slot] = pVirtIO[slot].get();
        !           177:                slot++;
        !           178:        }
        !           179: 
        !           180:        // SCSI
        !           181:        if (true) {
        !           182:                pVirtIO[slot].reset(new BusIO_L<VirtIOSCSIDevice>(slot));
        !           183:                if ((bool)pVirtIO[slot] == false) {
        !           184:                        warnx("Failed to initialize VirtIOSCSIDevice at %s", __method__);
1.1       root      185:                        return false;
                    186:                }
                    187:                viotable[slot] = pVirtIO[slot].get();
                    188:                slot++;
                    189:        }
                    190: 
                    191:        return true;
                    192: }
                    193: 
                    194: inline IODevice *
                    195: V68kIODevice::SearchDevice(uint32 addr) const
                    196: {
                    197:        if (__predict_true(addr < 0xff07'0000)) {
                    198:                // FF0X'X000
                    199:                uint32 idx = (addr >> 12) & 0x7f;
                    200:                return table[idx];
                    201:        } else if (__predict_true(addr < 0xff08'0000)) {
                    202:                // FF07'XX00
                    203:                uint32 idx = (addr >> 9) & 0x7f;
                    204:                return viotable[idx];
                    205:        } else {
                    206:                return buserr;
                    207:        }
                    208: }
                    209: 
                    210: busdata
1.1.1.2   root      211: V68kIODevice::Read(busaddr addr)
1.1       root      212: {
1.1.1.2   root      213:        IODevice *d = SearchDevice(addr.Addr());
                    214:        return d->Read(addr);
1.1       root      215: }
                    216: 
                    217: busdata
1.1.1.2   root      218: V68kIODevice::Write(busaddr addr, uint32 data)
1.1       root      219: {
1.1.1.2   root      220:        IODevice *d = SearchDevice(addr.Addr());
                    221:        return d->Write(addr, data);
1.1       root      222: }
                    223: 
                    224: busdata
1.1.1.2   root      225: V68kIODevice::Peek1(uint32 addr)
1.1       root      226: {
                    227:        IODevice *d = SearchDevice(addr);
1.1.1.2   root      228:        return d->Peek1(addr);
1.1       root      229: }
                    230: 
                    231: bool
1.1.1.2   root      232: V68kIODevice::Poke1(uint32 addr, uint32 data)
1.1       root      233: {
                    234:        IODevice *d = SearchDevice(addr);
1.1.1.2   root      235:        return d->Poke1(addr, data);
1.1       root      236: }

unix.superglobalmegacorp.com

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