xref: /reactos/subsystems/mvdm/ntvdm/io.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       GPL - See COPYING in the top level directory
3  * PROJECT:         ReactOS Virtual DOS Machine
4  * FILE:            subsystems/mvdm/ntvdm/io.c
5  * PURPOSE:         I/O Port Handlers
6  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include "ntvdm.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 #include "emulator.h"
18 #include "io.h"
19 
20 /* PRIVATE VARIABLES **********************************************************/
21 
22 typedef struct _EMULATOR_IO_HANDLERS
23 {
24     EMULATOR_INB_PROC   InB;
25     EMULATOR_INW_PROC   InW;
26     EMULATOR_IND_PROC   InD;
27 
28     EMULATOR_INSB_PROC  InsB;
29     EMULATOR_INSW_PROC  InsW;
30     EMULATOR_INSD_PROC  InsD;
31 
32     EMULATOR_OUTB_PROC  OutB;
33     EMULATOR_OUTW_PROC  OutW;
34     EMULATOR_OUTD_PROC  OutD;
35 
36     EMULATOR_OUTSB_PROC OutsB;
37     EMULATOR_OUTSW_PROC OutsW;
38     EMULATOR_OUTSD_PROC OutsD;
39 } EMULATOR_IO_HANDLERS, *PEMULATOR_IO_HANDLERS;
40 
41 typedef struct _EMULATOR_IOPORT_HANDLERS
42 {
43     HANDLE hVdd; // == NULL if unused,
44                  //    INVALID_HANDLE_VALUE if handled internally,
45                  //    a valid VDD handle   if handled externally.
46     union
47     {
48         /* For Windows compatibility only, not used internally... */
49         VDD_IO_HANDLERS VddIoHandlers;
50 
51         /* ... we use these members internally */
52         EMULATOR_IO_HANDLERS IoHandlers;
53     };
54 } EMULATOR_IOPORT_HANDLERS, *PEMULATOR_IOPORT_HANDLERS;
55 
56 /*
57  * This is the list of registered I/O Port handlers.
58  */
59 EMULATOR_IOPORT_HANDLERS IoPortProc[EMULATOR_MAX_IOPORTS_NUM] = {{NULL}};
60 
61 /* PUBLIC FUNCTIONS ***********************************************************/
62 
63 UCHAR
IOReadB(USHORT Port)64 IOReadB(USHORT Port)
65 {
66     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
67         IoPortProc[Port].IoHandlers.InB)
68     {
69         return IoPortProc[Port].IoHandlers.InB(Port);
70     }
71     else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
72              IoPortProc[Port].VddIoHandlers.inb_handler)
73     {
74         UCHAR Data;
75         ASSERT(Port <= MAXWORD);
76         IoPortProc[Port].VddIoHandlers.inb_handler(Port, &Data);
77         return Data;
78     }
79     else
80     {
81         /* Return an empty port byte value */
82         DPRINT("Read from unknown port: 0x%X\n", Port);
83         return 0xFF;
84     }
85 }
86 
87 VOID
IOReadStrB(USHORT Port,PUCHAR Buffer,ULONG Count)88 IOReadStrB(USHORT Port,
89            PUCHAR Buffer,
90            ULONG  Count)
91 {
92     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
93         IoPortProc[Port].IoHandlers.InsB)
94     {
95         IoPortProc[Port].IoHandlers.InsB(Port, Buffer, Count);
96     }
97     else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
98              IoPortProc[Port].VddIoHandlers.insb_handler)
99     {
100         ASSERT(Port  <= MAXWORD);
101         ASSERT(Count <= MAXWORD);
102         IoPortProc[Port].VddIoHandlers.insb_handler(Port, Buffer, (WORD)Count);
103     }
104     else
105     {
106         while (Count--) *Buffer++ = IOReadB(Port);
107     }
108 }
109 
110 VOID
IOWriteB(USHORT Port,UCHAR Buffer)111 IOWriteB(USHORT Port,
112          UCHAR  Buffer)
113 {
114     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
115         IoPortProc[Port].IoHandlers.OutB)
116     {
117         IoPortProc[Port].IoHandlers.OutB(Port, Buffer);
118     }
119     else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
120              IoPortProc[Port].VddIoHandlers.outb_handler)
121     {
122         ASSERT(Port <= MAXWORD);
123         IoPortProc[Port].VddIoHandlers.outb_handler(Port, Buffer);
124     }
125     else
126     {
127         /* Do nothing */
128         DPRINT("Write to unknown port: 0x%X\n", Port);
129     }
130 }
131 
132 VOID
IOWriteStrB(USHORT Port,PUCHAR Buffer,ULONG Count)133 IOWriteStrB(USHORT Port,
134             PUCHAR Buffer,
135             ULONG  Count)
136 {
137     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
138         IoPortProc[Port].IoHandlers.OutsB)
139     {
140         IoPortProc[Port].IoHandlers.OutsB(Port, Buffer, Count);
141     }
142     else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
143              IoPortProc[Port].VddIoHandlers.outsb_handler)
144     {
145         ASSERT(Port  <= MAXWORD);
146         ASSERT(Count <= MAXWORD);
147         IoPortProc[Port].VddIoHandlers.outsb_handler(Port, Buffer, (WORD)Count);
148     }
149     else
150     {
151         while (Count--) IOWriteB(Port, *Buffer++);
152     }
153 }
154 
155 USHORT
IOReadW(USHORT Port)156 IOReadW(USHORT Port)
157 {
158     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
159         IoPortProc[Port].IoHandlers.InW)
160     {
161         return IoPortProc[Port].IoHandlers.InW(Port);
162     }
163     else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
164              IoPortProc[Port].VddIoHandlers.inw_handler)
165     {
166         USHORT Data;
167         ASSERT(Port <= MAXWORD);
168         IoPortProc[Port].VddIoHandlers.inw_handler(Port, &Data);
169         return Data;
170     }
171     else
172     {
173         UCHAR Low, High;
174 
175         // FIXME: Is it ok on Little endian and Big endian ??
176         Low  = IOReadB(Port);
177         High = IOReadB(Port + sizeof(UCHAR));
178         return MAKEWORD(Low, High);
179     }
180 }
181 
182 VOID
IOReadStrW(USHORT Port,PUSHORT Buffer,ULONG Count)183 IOReadStrW(USHORT  Port,
184            PUSHORT Buffer,
185            ULONG   Count)
186 {
187     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
188         IoPortProc[Port].IoHandlers.InsW)
189     {
190         IoPortProc[Port].IoHandlers.InsW(Port, Buffer, Count);
191     }
192     else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
193              IoPortProc[Port].VddIoHandlers.insw_handler)
194     {
195         ASSERT(Port  <= MAXWORD);
196         ASSERT(Count <= MAXWORD);
197         IoPortProc[Port].VddIoHandlers.insw_handler(Port, Buffer, (WORD)Count);
198     }
199     else
200     {
201         while (Count--) *Buffer++ = IOReadW(Port);
202     }
203 }
204 
205 VOID
IOWriteW(USHORT Port,USHORT Buffer)206 IOWriteW(USHORT Port,
207          USHORT Buffer)
208 {
209     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
210         IoPortProc[Port].IoHandlers.OutW)
211     {
212         IoPortProc[Port].IoHandlers.OutW(Port, Buffer);
213     }
214     else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
215              IoPortProc[Port].VddIoHandlers.outw_handler)
216     {
217         ASSERT(Port <= MAXWORD);
218         IoPortProc[Port].VddIoHandlers.outw_handler(Port, Buffer);
219     }
220     else
221     {
222         // FIXME: Is it ok on Little endian and Big endian ??
223         IOWriteB(Port, LOBYTE(Buffer));
224         IOWriteB(Port + sizeof(UCHAR), HIBYTE(Buffer));
225     }
226 }
227 
228 VOID
IOWriteStrW(USHORT Port,PUSHORT Buffer,ULONG Count)229 IOWriteStrW(USHORT  Port,
230             PUSHORT Buffer,
231             ULONG   Count)
232 {
233     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
234         IoPortProc[Port].IoHandlers.OutsW)
235     {
236         IoPortProc[Port].IoHandlers.OutsW(Port, Buffer, Count);
237     }
238     else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
239              IoPortProc[Port].VddIoHandlers.outsw_handler)
240     {
241         ASSERT(Port  <= MAXWORD);
242         ASSERT(Count <= MAXWORD);
243         IoPortProc[Port].VddIoHandlers.outsw_handler(Port, Buffer, (WORD)Count);
244     }
245     else
246     {
247         while (Count--) IOWriteW(Port, *Buffer++);
248     }
249 }
250 
251 ULONG
IOReadD(USHORT Port)252 IOReadD(USHORT Port)
253 {
254     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
255         IoPortProc[Port].IoHandlers.InD)
256     {
257         return IoPortProc[Port].IoHandlers.InD(Port);
258     }
259     else
260     {
261         USHORT Low, High;
262 
263         // FIXME: Is it ok on Little endian and Big endian ??
264         Low  = IOReadW(Port);
265         High = IOReadW(Port + sizeof(USHORT));
266         return MAKELONG(Low, High);
267     }
268 }
269 
270 VOID
IOReadStrD(USHORT Port,PULONG Buffer,ULONG Count)271 IOReadStrD(USHORT Port,
272            PULONG Buffer,
273            ULONG  Count)
274 {
275     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
276         IoPortProc[Port].IoHandlers.InsD)
277     {
278         IoPortProc[Port].IoHandlers.InsD(Port, Buffer, Count);
279     }
280     else
281     {
282         while (Count--) *Buffer++ = IOReadD(Port);
283     }
284 }
285 
286 VOID
IOWriteD(USHORT Port,ULONG Buffer)287 IOWriteD(USHORT Port,
288          ULONG  Buffer)
289 {
290     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
291         IoPortProc[Port].IoHandlers.OutD)
292     {
293         IoPortProc[Port].IoHandlers.OutD(Port, Buffer);
294     }
295     else
296     {
297         // FIXME: Is it ok on Little endian and Big endian ??
298         IOWriteW(Port, LOWORD(Buffer));
299         IOWriteW(Port + sizeof(USHORT), HIWORD(Buffer));
300     }
301 }
302 
303 VOID
IOWriteStrD(USHORT Port,PULONG Buffer,ULONG Count)304 IOWriteStrD(USHORT Port,
305             PULONG Buffer,
306             ULONG  Count)
307 {
308     if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
309         IoPortProc[Port].IoHandlers.OutsD)
310     {
311         IoPortProc[Port].IoHandlers.OutsD(Port, Buffer, Count);
312     }
313     else
314     {
315         while (Count--) IOWriteD(Port, *Buffer++);
316     }
317 }
318 
319 
RegisterIoPort(USHORT Port,EMULATOR_INB_PROC InHandler,EMULATOR_OUTB_PROC OutHandler)320 VOID RegisterIoPort(USHORT Port,
321                     EMULATOR_INB_PROC  InHandler,
322                     EMULATOR_OUTB_PROC OutHandler)
323 {
324     if (IoPortProc[Port].IoHandlers.InB == NULL)
325         IoPortProc[Port].IoHandlers.InB = InHandler;
326     else
327         DPRINT1("IoPortProc[0x%X].IoHandlers.InB already registered\n", Port);
328 
329     if (IoPortProc[Port].IoHandlers.OutB == NULL)
330         IoPortProc[Port].IoHandlers.OutB = OutHandler;
331     else
332         DPRINT1("IoPortProc[0x%X].IoHandlers.OutB already registered\n", Port);
333 
334     /* We hold the I/O port internally */
335     IoPortProc[Port].hVdd = INVALID_HANDLE_VALUE;
336 }
337 
UnregisterIoPort(USHORT Port)338 VOID UnregisterIoPort(USHORT Port)
339 {
340     /*
341      * Put automagically all the fields to zero:
342      * the hVdd gets unregistered as well as all the handlers.
343      */
344     // IoPortProc[Port] = {NULL};
345     RtlZeroMemory(&IoPortProc[Port], sizeof(IoPortProc[Port]));
346 }
347 
348 VOID FASTCALL
EmulatorReadIo(PFAST486_STATE State,USHORT Port,PVOID Buffer,ULONG DataCount,UCHAR DataSize)349 EmulatorReadIo(PFAST486_STATE State,
350                USHORT Port,
351                PVOID Buffer,
352                ULONG DataCount,
353                UCHAR DataSize)
354 {
355     UNREFERENCED_PARAMETER(State);
356 
357     if (DataSize == 0 || DataCount == 0) return;
358 
359     if (DataSize == sizeof(UCHAR))
360     {
361         if (DataCount == 1)
362             *(PUCHAR)Buffer = IOReadB(Port);
363         else
364             IOReadStrB(Port, Buffer, DataCount);
365     }
366     else if (DataSize == sizeof(USHORT))
367     {
368         if (DataCount == 1)
369             *(PUSHORT)Buffer = IOReadW(Port);
370         else
371             IOReadStrW(Port, Buffer, DataCount);
372     }
373     else if (DataSize == sizeof(ULONG))
374     {
375         if (DataCount == 1)
376             *(PULONG)Buffer = IOReadD(Port);
377         else
378             IOReadStrD(Port, Buffer, DataCount);
379     }
380     else
381     {
382         PUCHAR Address = (PUCHAR)Buffer;
383 
384         while (DataCount--)
385         {
386             ULONG CurrentPort = Port;
387             ULONG Count;
388             UCHAR NewDataSize = DataSize;
389 
390             /* Read dword */
391             Count       = NewDataSize >> 2; // NewDataSize / sizeof(ULONG);
392             NewDataSize = NewDataSize  & 3; // NewDataSize % sizeof(ULONG);
393             while (Count--)
394             {
395                 *(PULONG)Address = IOReadD(CurrentPort);
396                 CurrentPort += sizeof(ULONG);
397                 Address     += sizeof(ULONG);
398             }
399 
400             /* Read word */
401             Count       = NewDataSize >> 1; // NewDataSize / sizeof(USHORT);
402             NewDataSize = NewDataSize  & 1; // NewDataSize % sizeof(USHORT);
403             while (Count--)
404             {
405                 *(PUSHORT)Address = IOReadW(CurrentPort);
406                 CurrentPort += sizeof(USHORT);
407                 Address     += sizeof(USHORT);
408             }
409 
410             /* Read byte */
411             Count       = NewDataSize; // NewDataSize / sizeof(UCHAR);
412             // NewDataSize = NewDataSize % sizeof(UCHAR);
413             while (Count--)
414             {
415                 *(PUCHAR)Address = IOReadB(CurrentPort);
416                 CurrentPort += sizeof(UCHAR);
417                 Address     += sizeof(UCHAR);
418             }
419         }
420     }
421 }
422 
423 VOID FASTCALL
EmulatorWriteIo(PFAST486_STATE State,USHORT Port,PVOID Buffer,ULONG DataCount,UCHAR DataSize)424 EmulatorWriteIo(PFAST486_STATE State,
425                 USHORT Port,
426                 PVOID Buffer,
427                 ULONG DataCount,
428                 UCHAR DataSize)
429 {
430     UNREFERENCED_PARAMETER(State);
431 
432     if (DataSize == 0 || DataCount == 0) return;
433 
434     if (DataSize == sizeof(UCHAR))
435     {
436         if (DataCount == 1)
437             IOWriteB(Port, *(PUCHAR)Buffer);
438         else
439             IOWriteStrB(Port, Buffer, DataCount);
440     }
441     else if (DataSize == sizeof(USHORT))
442     {
443         if (DataCount == 1)
444             IOWriteW(Port, *(PUSHORT)Buffer);
445         else
446             IOWriteStrW(Port, Buffer, DataCount);
447     }
448     else if (DataSize == sizeof(ULONG))
449     {
450         if (DataCount == 1)
451             IOWriteD(Port, *(PULONG)Buffer);
452         else
453             IOWriteStrD(Port, Buffer, DataCount);
454     }
455     else
456     {
457         PUCHAR Address = (PUCHAR)Buffer;
458 
459         while (DataCount--)
460         {
461             ULONG CurrentPort = Port;
462             ULONG Count;
463             UCHAR NewDataSize = DataSize;
464 
465             /* Write dword */
466             Count       = NewDataSize >> 2; // NewDataSize / sizeof(ULONG);
467             NewDataSize = NewDataSize  & 3; // NewDataSize % sizeof(ULONG);
468             while (Count--)
469             {
470                 IOWriteD(CurrentPort, *(PULONG)Address);
471                 CurrentPort += sizeof(ULONG);
472                 Address     += sizeof(ULONG);
473             }
474 
475             /* Write word */
476             Count       = NewDataSize >> 1; // NewDataSize / sizeof(USHORT);
477             NewDataSize = NewDataSize  & 1; // NewDataSize % sizeof(USHORT);
478             while (Count--)
479             {
480                 IOWriteW(CurrentPort, *(PUSHORT)Address);
481                 CurrentPort += sizeof(USHORT);
482                 Address     += sizeof(USHORT);
483             }
484 
485             /* Write byte */
486             Count       = NewDataSize; // NewDataSize / sizeof(UCHAR);
487             // NewDataSize = NewDataSize % sizeof(UCHAR);
488             while (Count--)
489             {
490                 IOWriteB(CurrentPort, *(PUCHAR)Address);
491                 CurrentPort += sizeof(UCHAR);
492                 Address     += sizeof(UCHAR);
493             }
494         }
495     }
496 }
497 
498 
499 
500 BOOL
501 WINAPI
VDDInstallIOHook(IN HANDLE hVdd,IN WORD cPortRange,IN PVDD_IO_PORTRANGE pPortRange,IN PVDD_IO_HANDLERS IoHandlers)502 VDDInstallIOHook(IN HANDLE            hVdd,
503                  IN WORD              cPortRange,
504                  IN PVDD_IO_PORTRANGE pPortRange,
505                  IN PVDD_IO_HANDLERS  IoHandlers)
506 {
507     WORD i;
508 
509     /* Check validity of the VDD handle */
510     if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
511     {
512         SetLastError(ERROR_INVALID_PARAMETER);
513         return FALSE;
514     }
515 
516     /* Loop for each range of I/O ports */
517     while (cPortRange--)
518     {
519         /* Register the range of I/O ports */
520         for (i = pPortRange->First; i <= pPortRange->Last; ++i)
521         {
522             /*
523              * Don't do anything if the I/O port is already
524              * handled internally or externally.
525              */
526             if (IoPortProc[i].hVdd != NULL)
527             {
528                 DPRINT1("IoPortProc[0x%X] already registered\n", i);
529                 continue;
530             }
531 
532             /* Register wrt. the VDD */
533             IoPortProc[i].hVdd = hVdd;
534 
535             /* Disable the internal handlers */
536             IoPortProc[i].IoHandlers.InB = NULL;
537             IoPortProc[i].IoHandlers.InW = NULL;
538             IoPortProc[i].IoHandlers.InD = NULL;
539 
540             IoPortProc[i].IoHandlers.InsB = NULL;
541             IoPortProc[i].IoHandlers.InsW = NULL;
542             IoPortProc[i].IoHandlers.InsD = NULL;
543 
544             IoPortProc[i].IoHandlers.OutB = NULL;
545             IoPortProc[i].IoHandlers.OutW = NULL;
546             IoPortProc[i].IoHandlers.OutD = NULL;
547 
548             IoPortProc[i].IoHandlers.OutsB = NULL;
549             IoPortProc[i].IoHandlers.OutsW = NULL;
550             IoPortProc[i].IoHandlers.OutsD = NULL;
551 
552             /* Save our handlers */
553             IoPortProc[i].VddIoHandlers = *IoHandlers;
554         }
555 
556         /* Go to the next range */
557         ++pPortRange;
558     }
559 
560     return TRUE;
561 }
562 
563 VOID
564 WINAPI
VDDDeInstallIOHook(IN HANDLE hVdd,IN WORD cPortRange,IN PVDD_IO_PORTRANGE pPortRange)565 VDDDeInstallIOHook(IN HANDLE            hVdd,
566                    IN WORD              cPortRange,
567                    IN PVDD_IO_PORTRANGE pPortRange)
568 {
569     WORD i;
570 
571     /* Check validity of the VDD handle */
572     if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
573     {
574         SetLastError(ERROR_INVALID_PARAMETER);
575         return;
576     }
577 
578     /* Loop for each range of I/O ports */
579     while (cPortRange--)
580     {
581         /* Unregister the range of I/O ports */
582         for (i = pPortRange->First; i <= pPortRange->Last; ++i)
583         {
584             /*
585              * Don't do anything if we don't own the I/O port.
586              */
587             if (IoPortProc[i].hVdd != hVdd)
588             {
589                 DPRINT1("IoPortProc[0x%X] owned by somebody else\n", i);
590                 continue;
591             }
592 
593             /*
594              * Put automagically all the fields to zero:
595              * the hVdd gets unregistered as well as all the handlers.
596              */
597             // IoPortProc[i] = {NULL};
598             RtlZeroMemory(&IoPortProc[i], sizeof(IoPortProc[i]));
599         }
600 
601         /* Go to the next range */
602         ++pPortRange;
603     }
604 }
605 
606 /* EOF */
607