|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.