-
Notifications
You must be signed in to change notification settings - Fork 551
/
IOPort.cs
301 lines (272 loc) · 9.71 KB
/
IOPort.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
using IL2CPU.API.Attribs;
namespace Cosmos.Core
{
/// <summary>
/// IOPortBase abstract class.
/// </summary>
public abstract class IOPortBase
{
//TODO Make it that IO port classes are exclusive to each port. For example
// only one IOPort class can be created per port number. This will prevent
// two instances of an IOPort from using the same port.
// A locking mechanism is not necessary as the creator can control access
// to the instance.
// We are not threaded yet anyways, but when we are will assume the caller
// or owner handles any concurrency issues so as to minimize overhead in this
// class. Or maybe some base support can be added to this class, but its functionality
// is optional and only used by classes that need concurrency control like ATA.
/// <summary>
/// Port.
/// </summary>
protected readonly ushort Port;
// all ctors are internal - Only Core ring can create it.. but hardware ring can use it.
/// <summary>
/// Create new instance of the <see cref="IOPortBase"/> class.
/// </summary>
/// <param name="aPort">A port.</param>
protected IOPortBase(ushort aPort)
{
Port = aPort;
}
/// <summary>
/// Create new instance of the <see cref="IOPortBase"/> class.
/// </summary>
/// <param name="aBase">A base port.</param>
/// <param name="aOffset">A offset from the base port.</param>
protected IOPortBase(ushort aBase, ushort aOffset)
{
// C# math promotes things to integers, so we have this constructor
// to relieve the use from having to do so many casts
Port = (ushort)(aBase + aOffset);
}
//TODO: Reads and writes can use this to get port instead of argument
/// <summary>
/// Write byte to port.
/// Plugged.
/// </summary>
/// <param name="aPort">A port to write to.</param>
/// <param name="aData">A data.</param>
[PlugMethod(PlugRequired = true)]
static protected void Write8(ushort aPort, byte aData) => throw null;
/// <summary>
/// Write Word to port.
/// Plugged.
/// </summary>
/// <param name="aPort">A port to write to.</param>
/// <param name="aData">A data.</param>
[PlugMethod(PlugRequired = true)]
static protected void Write16(ushort aPort, ushort aData) => throw null;
/// <summary>
/// Write DWord to port.
/// Plugged.
/// </summary>
/// <param name="aPort">A port to write to.</param>
/// <param name="aData">A data.</param>
[PlugMethod(PlugRequired = true)]
static protected void Write32(ushort aPort, uint aData) => throw null;
/// <summary>
/// Read byte from port.
/// Plugged.
/// </summary>
/// <param name="aPort">A port to read from.</param>
/// <returns>byte value.</returns>
[PlugMethod(PlugRequired = true)]
static protected byte Read8(ushort aPort) => throw null;
/// <summary>
/// Read Word from port.
/// Plugged.
/// </summary>
/// <param name="aPort">A port to read from.</param>
/// <returns>ushort value.</returns>
[PlugMethod(PlugRequired = true)]
static protected ushort Read16(ushort aPort) => throw null;
/// <summary>
/// Read DWord from port.
/// Plugged.
/// </summary>
/// <param name="aPort">A port to read from.</param>
/// <returns>uint value.</returns>
[PlugMethod(PlugRequired = true)]
static protected uint Read32(ushort aPort) => throw null;
//TODO: Plug these Reads with asm to read directly to RAM
// REP INSW
/// <summary>
/// Read byte from base port.
/// </summary>
/// <param name="aData">Output data array.</param>
/// <exception cref="System.OverflowException">Thrown if aData lenght is greater than Int32.MaxValue.</exception>
public void Read8(byte[] aData)
{
for (int i = 0; i < aData.Length / 2; i++)
{
var xValue = Read16(Port);
aData[i * 2] = (byte)xValue;
aData[i * 2 + 1] = (byte)(xValue >> 8);
}
}
/// <summary>
/// Read Word from base port.
/// </summary>
/// <param name="aData">Output data array.</param>
/// <exception cref="System.OverflowException">Thrown if aData lenght is greater than Int32.MaxValue.</exception>
public void Read16(ushort[] aData)
{
for (int i = 0; i < aData.Length; i++)
{
aData[i] = Read16(Port);
}
}
/// <summary>
/// Read DWord from base port.
/// </summary>
/// <param name="aData">Output data array.</param>
/// <exception cref="System.OverflowException">Thrown if aData lenght is greater than Int32.MaxValue.</exception>
public void Read32(uint[] aData)
{
for (int i = 0; i < aData.Length; i++)
{
aData[i] = Read32(Port);
}
}
}
/// <summary>
/// IOPort class. Used to read and write to IO port.
/// </summary>
public class IOPort : IOPortBase
{
/// <summary>
/// Create new instance of the <see cref="IOPort"/> class.
/// </summary>
/// <param name="aPort">A port.</param>
public IOPort(ushort aPort)
: base(aPort)
{
}
/// <summary>
/// Create new instance of the <see cref="IOPort"/> class.
/// </summary>
/// <param name="aBase">A base port.</param>
/// <param name="aOffset">Offset from the base port.</param>
public IOPort(ushort aBase, ushort aOffset)
: base(aBase, aOffset)
{
}
/// <summary>
/// Wait for the previous IO read/write to complete.
/// </summary>
static public void Wait()
{
// Write to an unused port. This assures whatever we were waiting on for a previous
// IO read/write has completed.
// Port 0x80 is unused after BIOS POST.
// 0x22 is just a random byte.
// Since IO is slow - its just a dummy sleep to wait long enough for the previous operation
// to have effect on the target.
Write8(0x80, 0x22);
}
/// <summary>
/// Get and set Byte value in IO port.
/// </summary>
public byte Byte
{
get => Read8(Port);
set => Write8(Port, value);
}
/// <summary>
/// Get and set Word value in IO port.
/// </summary>
public ushort Word
{
get => Read16(Port);
set => Write16(Port, value);
}
/// <summary>
/// Get and set DWord value in IO port.
/// </summary>
public uint DWord
{
get => Read32(Port);
set => Write32(Port, value);
}
}
// I split these instead of adding CanRead/CanWrite because this enforces
// at build time, and its also faster at runtime. Finally it allows future optimizations better
// than checking at runtime.
/// <summary>
/// IOPortRead class. Used to read to IO port. See also: <seealso cref="IOPortBase"/>.
/// </summary>
public class IOPortRead : IOPortBase
{
/// <summary>
/// Create new instance of <see cref="IOPortRead"/> class.
/// </summary>
/// <param name="aPort">A port.</param>
public IOPortRead(ushort aPort)
: base(aPort)
{
}
/// <summary>
/// Create new instance of <see cref="IOPortRead"/> class.
/// </summary>
/// <param name="aBase">A base port address.</param>
/// <param name="aOffset">Offset of the base port.</param>
public IOPortRead(ushort aBase, ushort aOffset)
: base(aBase, aOffset)
{
}
/// <summary>
/// Read byte to the port.
/// </summary>
public byte Byte => Read8(Port);
/// <summary>
/// Read Word to the port.
/// </summary>
public ushort Word => Read16(Port);
/// <summary>
/// Read DWord to the port.
/// </summary>
public uint DWord => Read32(Port);
}
/// <summary>
/// IOPortWrite class. Used to write to IO port. See also: <seealso cref="IOPortBase"/>.
/// </summary>
public class IOPortWrite : IOPortBase
{
/// <summary>
/// Create new instance of <see cref="IOPortWrite"/> class.
/// </summary>
/// <param name="aPort">A port.</param>
public IOPortWrite(ushort aPort) : base(aPort)
{
}
/// <summary>
/// Create new instance of <see cref="IOPortWrite"/> class.
/// </summary>
/// <param name="aBase">A base port address.</param>
/// <param name="aOffset">Offset of the base port.</param>
public IOPortWrite(ushort aBase, ushort aOffset) : base(aBase, aOffset)
{
}
/// <summary>
/// Write byte to the port.
/// </summary>
public byte Byte
{
set => Write8(Port, value);
}
/// <summary>
/// Write Word to the port.
/// </summary>
public ushort Word
{
set => Write16(Port, value);
}
/// <summary>
/// Write DWord to the port.
/// </summary>
public uint DWord
{
set => Write32(Port, value);
}
}
}