|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2024 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // ! 8: // virt68k の I/O 空間担当 ! 9: // ! 10: ! 11: // メモリマップ。 ! 12: // NetBSD/virt68k は $ff00'0000 以降が I/O 空間で、デバイス配置は ! 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 は間隔が違うので最後に置く。 ! 36: // ここは 1スロット $200 で、最大 127個まで置けるようだ。 ! 37: // デバイスが存在しないスロットはバスエラーではなく、DEVICE_ID = INVALID ! 38: // で応答しなければならない。 ! 39: // ! 40: // $ff07'0000-$ff07'01ff VirtIO(00) ! 41: // $ff07'0200-$ff07'03ff VirtIO(01) ! 42: // : ! 43: // $ff07'fe00-$ff07'ffff VirtIO(7f) ! 44: ! 45: #include "v68kio.h" ! 46: #include "config.h" ! 47: #include "goldfish_pic.h" ! 48: #include "goldfish_rtc.h" ! 49: #include "goldfish_timer.h" ! 50: #include "goldfish_tty.h" ! 51: #include "mainbus.h" ! 52: #include "qemusysctlr.h" ! 53: #include "romemu_virt68k.h" ! 54: #include "virtio_base.h" ! 55: #include "virtio_block.h" ! 56: #include "virtio_net.h" ! 57: #include "vm.h" ! 58: ! 59: // コンストラクタ ! 60: V68kIODevice::V68kIODevice() ! 61: : inherited(OBJ_V68KIO) ! 62: { ! 63: NEWDV(PROM, new Virt68kROMEmuDevice()); ! 64: NEWDV(GFPIC1, new GFPICDevice(1)); ! 65: NEWDV(GFPIC2, new GFPICDevice(2)); ! 66: NEWDV(GFPIC3, new GFPICDevice(3)); ! 67: NEWDV(GFPIC4, new GFPICDevice(4)); ! 68: NEWDV(GFPIC5, new GFPICDevice(5)); ! 69: NEWDV(GFPIC6, new GFPICDevice(6)); ! 70: NEWDV(GFRTC, new GFRTCDevice()); // required by GFTimer ! 71: NEWDV(GFTimer, new GFTimerDevice()); ! 72: NEWDV(GFTTY, new GFTTYDevice()); ! 73: NEWDV(QemuSysCtlr, new QemuSysCtlrDevice()); ! 74: NEWDV(VirtIONone, new VirtIONoneDevice()); ! 75: ! 76: buserr = GetBusErrDevice(); ! 77: ! 78: // まず全域をバスエラーで埋める。 ! 79: for (int i = 0; i < table.size(); i++) { ! 80: table[i] = buserr; ! 81: } ! 82: ! 83: // 少ないので手動で埋めていく。 ! 84: for (int i = 0; i < 0x10; i++) { ! 85: table[i] = pPROM.get(); ! 86: } ! 87: table[0x11] = pGFPIC1.get(); ! 88: table[0x12] = pGFPIC2.get(); ! 89: table[0x13] = pGFPIC3.get(); ! 90: table[0x14] = pGFPIC4.get(); ! 91: table[0x15] = pGFPIC5.get(); ! 92: table[0x16] = pGFPIC6.get(); ! 93: table[0x20] = pGFTimer.get(); ! 94: table[0x21] = pGFRTC.get(); ! 95: table[0x30] = pGFTTY.get(); ! 96: table[0x40] = pQemuSysCtlr.get(); ! 97: ! 98: // VirtIO 用は、設定によるので後で代入する。 ! 99: // ここはバスエラーではない。 ! 100: for (int i = 0; i < viotable.size(); i++) { ! 101: viotable[i] = pVirtIONone.get(); ! 102: } ! 103: } ! 104: ! 105: // デストラクタ ! 106: V68kIODevice::~V68kIODevice() ! 107: { ! 108: } ! 109: ! 110: // 動的なコンストラクション ! 111: bool ! 112: V68kIODevice::Create() ! 113: { ! 114: int slot; ! 115: ! 116: // (QEMU virt68k の?) ! 117: // virtio はスロットによって割り込み先を固定してあるようだ。 ! 118: // スロット 0 .. 31 は PIC2(Lv2) の IRQ1..32、 ! 119: // スロット 32 .. 63 は PIC3(Lv3) の IRQ1..32、 ! 120: // スロット 64 .. 95 は PIC4(Lv4) の IRQ1..32、 ! 121: // スロット 96 ..127 は PIC5(Lv5) の IRQ1..32 となる。 ! 122: // ! 123: // Block、Net はとりあえず先例にならって Lv5 につなぐことにしてみる。 ! 124: slot = 96; ! 125: ! 126: // Net ! 127: if (true) { ! 128: pVirtIO[slot].reset(new VirtIONetDevice(slot)); ! 129: if ((bool)pVirtIO[slot] == false) { ! 130: return false; ! 131: } ! 132: viotable[slot] = pVirtIO[slot].get(); ! 133: slot++; ! 134: } ! 135: ! 136: // Block (とりあえず8個まで) ! 137: for (int id = 0; id < 8; id++) { ! 138: const std::string key = string_format("virtio-block%d-image", id); ! 139: const ConfigItem& item = gConfig->Find(key); ! 140: const std::string& image = item.AsString(); ! 141: ! 142: // 空ならデバイスなし ! 143: if (image.empty()) { ! 144: // 未接続部分のパラメータは減らしておくか。 ! 145: // --show-config するとさすがに無駄に多くて邪魔なので。 ! 146: gConfig->Delete(string_format("virtio-block%d-writeignore", id)); ! 147: continue; ! 148: } ! 149: ! 150: pVirtIO[slot].reset(new VirtIOBlockDevice(slot, id)); ! 151: if ((bool)pVirtIO[slot] == false) { ! 152: item.Err(); // ? ! 153: return false; ! 154: } ! 155: viotable[slot] = pVirtIO[slot].get(); ! 156: slot++; ! 157: } ! 158: ! 159: return true; ! 160: } ! 161: ! 162: bool ! 163: V68kIODevice::Init() ! 164: { ! 165: if (inherited::Init() == false) { ! 166: return false; ! 167: } ! 168: ! 169: return true; ! 170: } ! 171: ! 172: inline IODevice * ! 173: V68kIODevice::SearchDevice(uint32 addr) const ! 174: { ! 175: if (__predict_true(addr < 0xff07'0000)) { ! 176: // FF0X'X000 ! 177: uint32 idx = (addr >> 12) & 0x7f; ! 178: return table[idx]; ! 179: } else if (__predict_true(addr < 0xff08'0000)) { ! 180: // FF07'XX00 ! 181: uint32 idx = (addr >> 9) & 0x7f; ! 182: return viotable[idx]; ! 183: } else { ! 184: return buserr; ! 185: } ! 186: } ! 187: ! 188: busdata ! 189: V68kIODevice::Read8(uint32 addr) ! 190: { ! 191: IODevice *d = SearchDevice(addr); ! 192: return d->Read8(addr); ! 193: } ! 194: ! 195: busdata ! 196: V68kIODevice::Read16(uint32 addr) ! 197: { ! 198: IODevice *d = SearchDevice(addr); ! 199: return d->Read16(addr); ! 200: } ! 201: ! 202: busdata ! 203: V68kIODevice::Read32(uint32 addr) ! 204: { ! 205: IODevice *d = SearchDevice(addr); ! 206: return d->Read32(addr); ! 207: } ! 208: ! 209: busdata ! 210: V68kIODevice::Write8(uint32 addr, uint32 data) ! 211: { ! 212: IODevice *d = SearchDevice(addr); ! 213: return d->Write8(addr, data); ! 214: } ! 215: ! 216: busdata ! 217: V68kIODevice::Write16(uint32 addr, uint32 data) ! 218: { ! 219: IODevice *d = SearchDevice(addr); ! 220: return d->Write16(addr, data); ! 221: } ! 222: ! 223: busdata ! 224: V68kIODevice::Write32(uint32 addr, uint32 data) ! 225: { ! 226: IODevice *d = SearchDevice(addr); ! 227: return d->Write32(addr, data); ! 228: } ! 229: ! 230: busdata ! 231: V68kIODevice::Peek8(uint32 addr) ! 232: { ! 233: IODevice *d = SearchDevice(addr); ! 234: return d->Peek8(addr); ! 235: } ! 236: ! 237: bool ! 238: V68kIODevice::Poke8(uint32 addr, uint32 data) ! 239: { ! 240: IODevice *d = SearchDevice(addr); ! 241: return d->Poke8(addr, data); ! 242: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.