|
|
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.