Annotation of nono/vm/v68kio.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 の 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.5   root       46: #include "buserr.h"
1.1.1.2   root       47: #include "busio.h"
1.1       root       48: #include "config.h"
                     49: #include "goldfish_pic.h"
                     50: #include "goldfish_rtc.h"
                     51: #include "goldfish_timer.h"
                     52: #include "goldfish_tty.h"
                     53: #include "qemusysctlr.h"
                     54: #include "romemu_virt68k.h"
                     55: #include "virtio_base.h"
                     56: #include "virtio_block.h"
1.1.1.2   root       57: #include "virtio_entropy.h"
1.1       root       58: #include "virtio_net.h"
1.1.1.4   root       59: #include "virtio_scsi.h"
1.1       root       60: #include "vm.h"
                     61: 
                     62: // コンストラクタ
                     63: V68kIODevice::V68kIODevice()
                     64:        : inherited(OBJ_V68KIO)
                     65: {
                     66:        NEWDV(PROM, new Virt68kROMEmuDevice());
1.1.1.2   root       67:        NEWDV(GFPIC1, new BusIO_L<GFPICDevice>(1));
                     68:        NEWDV(GFPIC2, new BusIO_L<GFPICDevice>(2));
                     69:        NEWDV(GFPIC3, new BusIO_L<GFPICDevice>(3));
                     70:        NEWDV(GFPIC4, new BusIO_L<GFPICDevice>(4));
                     71:        NEWDV(GFPIC5, new BusIO_L<GFPICDevice>(5));
                     72:        NEWDV(GFPIC6, new BusIO_L<GFPICDevice>(6));
                     73:        NEWDV(GFRTC, new BusIO_L<GFRTCDevice>());               // required by GFTimer
                     74:        NEWDV(GFTimer, new BusIO_L<GFTimerDevice>());
                     75:        NEWDV(GFTTY, new BusIO_L<GFTTYDevice>());
                     76:        NEWDV(QemuSysCtlr, new BusIO_L<QemuSysCtlrDevice>());
                     77:        NEWDV(VirtIONone, new BusIO_L<VirtIONoneDevice>());
1.1       root       78: 
                     79:        buserr = GetBusErrDevice();
                     80: 
                     81:        // まず全域をバスエラーで埋める。
                     82:        for (int i = 0; i < table.size(); i++) {
                     83:                table[i] = buserr;
                     84:        }
                     85: 
                     86:        // 少ないので手動で埋めていく。
                     87:        for (int i = 0; i < 0x10; i++) {
                     88:                table[i] = pPROM.get();
                     89:        }
                     90:        table[0x11] = pGFPIC1.get();
                     91:        table[0x12] = pGFPIC2.get();
                     92:        table[0x13] = pGFPIC3.get();
                     93:        table[0x14] = pGFPIC4.get();
                     94:        table[0x15] = pGFPIC5.get();
                     95:        table[0x16] = pGFPIC6.get();
                     96:        table[0x20] = pGFTimer.get();
                     97:        table[0x21] = pGFRTC.get();
                     98:        table[0x30] = pGFTTY.get();
                     99:        table[0x40] = pQemuSysCtlr.get();
                    100: 
                    101:        // VirtIO 用は、設定によるので後で代入する。
                    102:        // ここはバスエラーではない。
                    103:        for (int i = 0; i < viotable.size(); i++) {
                    104:                viotable[i] = pVirtIONone.get();
                    105:        }
                    106: }
                    107: 
                    108: // デストラクタ
                    109: V68kIODevice::~V68kIODevice()
                    110: {
                    111: }
                    112: 
                    113: // 動的なコンストラクション
                    114: bool
                    115: V68kIODevice::Create()
                    116: {
1.1.1.2   root      117:        uint slot;
1.1       root      118: 
1.1.1.2   root      119:        // (QEMU virt-m68k の?)
1.1       root      120:        // virtio はスロットによって割り込み先を固定してあるようだ。
                    121:        // スロット  0 .. 31 は PIC2(Lv2) の IRQ1..32、
                    122:        // スロット 32 .. 63 は PIC3(Lv3) の IRQ1..32、
                    123:        // スロット 64 .. 95 は PIC4(Lv4) の IRQ1..32、
                    124:        // スロット 96 ..127 は PIC5(Lv5) の IRQ1..32 となる。
                    125:        //
1.1.1.2   root      126:        // VirtIO* はとりあえず先例にならって Lv5 につなぐことにしてみる。
1.1       root      127:        slot = 96;
                    128: 
                    129:        // Net
1.1.1.6 ! root      130:        if (gConfig->Find("virtio-net").AsBool()) {
1.1.1.4   root      131:                try {
                    132:                        pVirtIO[slot].reset(new BusIO_L<VirtIONetDevice>(slot));
                    133:                } catch (...) { }
1.1.1.2   root      134:                if ((bool)pVirtIO[slot] == false) {
1.1.1.4   root      135:                        warnx("Failed to initialize VirtIONetDevice at %s", __method__);
1.1.1.2   root      136:                        return false;
                    137:                }
                    138:                viotable[slot] = pVirtIO[slot].get();
                    139:                slot++;
                    140:        }
                    141: 
                    142:        // Entropy
1.1.1.6 ! root      143:        if (gConfig->Find("virtio-entropy").AsBool()) {
1.1.1.4   root      144:                try {
                    145:                        pVirtIO[slot].reset(new BusIO_L<VirtIOEntropyDevice>(slot));
                    146:                } catch (...) { }
1.1       root      147:                if ((bool)pVirtIO[slot] == false) {
1.1.1.4   root      148:                        warnx("Failed to initialize VirtIOEntropyDevice at %s", __method__);
1.1       root      149:                        return false;
                    150:                }
                    151:                viotable[slot] = pVirtIO[slot].get();
                    152:                slot++;
                    153:        }
                    154: 
                    155:        // Block (とりあえず8個まで)
                    156:        for (int id = 0; id < 8; id++) {
1.1.1.2   root      157:                const std::string key = string_format("virtio-block%u-image", id);
1.1       root      158:                const ConfigItem& item = gConfig->Find(key);
                    159:                const std::string& image = item.AsString();
                    160: 
                    161:                // 空ならデバイスなし
                    162:                if (image.empty()) {
                    163:                        // 未接続部分のパラメータは減らしておくか。
                    164:                        // --show-config するとさすがに無駄に多くて邪魔なので。
1.1.1.2   root      165:                        gConfig->Delete(string_format("virtio-block%u-writeignore", id));
1.1       root      166:                        continue;
                    167:                }
                    168: 
1.1.1.4   root      169:                try {
                    170:                        pVirtIO[slot].reset(new BusIO_L<VirtIOBlockDevice>(slot, id));
                    171:                } catch (...) { }
1.1       root      172:                if ((bool)pVirtIO[slot] == false) {
1.1.1.4   root      173:                        warnx("Failed to initialize VirtIOBlockDevice(%u) at %s",
                    174:                                id, __method__);
                    175:                        return false;
                    176:                }
                    177:                viotable[slot] = pVirtIO[slot].get();
                    178:                slot++;
                    179:        }
                    180: 
                    181:        // SCSI
1.1.1.6 ! root      182:        if (gConfig->Find("virtio-scsi").AsBool()) {
1.1.1.4   root      183:                pVirtIO[slot].reset(new BusIO_L<VirtIOSCSIDevice>(slot));
                    184:                if ((bool)pVirtIO[slot] == false) {
                    185:                        warnx("Failed to initialize VirtIOSCSIDevice at %s", __method__);
1.1       root      186:                        return false;
                    187:                }
                    188:                viotable[slot] = pVirtIO[slot].get();
                    189:                slot++;
                    190:        }
                    191: 
                    192:        return true;
                    193: }
                    194: 
                    195: inline IODevice *
                    196: V68kIODevice::SearchDevice(uint32 addr) const
                    197: {
                    198:        if (__predict_true(addr < 0xff07'0000)) {
                    199:                // FF0X'X000
                    200:                uint32 idx = (addr >> 12) & 0x7f;
                    201:                return table[idx];
                    202:        } else if (__predict_true(addr < 0xff08'0000)) {
                    203:                // FF07'XX00
                    204:                uint32 idx = (addr >> 9) & 0x7f;
                    205:                return viotable[idx];
                    206:        } else {
                    207:                return buserr;
                    208:        }
                    209: }
                    210: 
                    211: busdata
1.1.1.2   root      212: V68kIODevice::Read(busaddr addr)
1.1       root      213: {
1.1.1.2   root      214:        IODevice *d = SearchDevice(addr.Addr());
                    215:        return d->Read(addr);
1.1       root      216: }
                    217: 
                    218: busdata
1.1.1.2   root      219: V68kIODevice::Write(busaddr addr, uint32 data)
1.1       root      220: {
1.1.1.2   root      221:        IODevice *d = SearchDevice(addr.Addr());
                    222:        return d->Write(addr, data);
1.1       root      223: }
                    224: 
                    225: busdata
1.1.1.2   root      226: V68kIODevice::Peek1(uint32 addr)
1.1       root      227: {
                    228:        IODevice *d = SearchDevice(addr);
1.1.1.2   root      229:        return d->Peek1(addr);
1.1       root      230: }
                    231: 
                    232: bool
1.1.1.2   root      233: V68kIODevice::Poke1(uint32 addr, uint32 data)
1.1       root      234: {
                    235:        IODevice *d = SearchDevice(addr);
1.1.1.2   root      236:        return d->Poke1(addr, data);
1.1       root      237: }

unix.superglobalmegacorp.com

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