VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bootsector2-common-routines-template-1.mac@ 97576

Last change on this file since 97576 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.7 KB
Line 
1; $Id: bootsector2-common-routines-template-1.mac 96407 2022-08-22 17:43:14Z vboxsync $
2;; @file
3; bootsector2 common routines - template containing code common to related modes.
4;
5
6;
7; Copyright (C) 2007-2022 Oracle and/or its affiliates.
8;
9; This file is part of VirtualBox base platform packages, as
10; available from https://www.virtualbox.org.
11;
12; This program is free software; you can redistribute it and/or
13; modify it under the terms of the GNU General Public License
14; as published by the Free Software Foundation, in version 3 of the
15; License.
16;
17; This program is distributed in the hope that it will be useful, but
18; WITHOUT ANY WARRANTY; without even the implied warranty of
19; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20; General Public License for more details.
21;
22; You should have received a copy of the GNU General Public License
23; along with this program; if not, see <https://www.gnu.org/licenses>.
24;
25; The contents of this file may alternatively be used under the terms
26; of the Common Development and Distribution License Version 1.0
27; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28; in the VirtualBox distribution, in which case the provisions of the
29; CDDL are applicable instead of those of the GPL.
30;
31; You may elect to license modified versions of this file under the
32; terms and conditions of either the GPL or the CDDL or both.
33;
34; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35;
36
37%include "bootsector2-template-header.mac"
38%include "VBox/bios.mac"
39
40ALIGNCODE(32)
41GLOBALNAME TMPL_NM_CMN(g_szMode)
42 db TMPL_MODE_STR, 0
43
44
45;;
46; Shutdown routine.
47;
48; Does not return.
49;
50; @uses N/A
51;
52BEGINPROC TMPL_NM_CMN(Shutdown)
53%ifdef TMPL_16BIT
54 jmp Bs2Shutdown
55%else
56 cli
57 mov bl, 64
58 mov ax, ss
59 mov ds, ax
60 mov dx, VBOX_BIOS_SHUTDOWN_PORT
61 mov ax, VBOX_BIOS_OLD_SHUTDOWN_PORT
62.retry:
63 mov ecx, 8
64 mov esi, .s_szShutdown
65 rep outsb
66 xchg dx, ax ; alternate between the new (VBox) and old (Bochs) ports.
67 dec bl
68 jnz .retry
69 ; Shutdown failed!
70 jmp Bs2Panic
71.s_szShutdown:
72 db 'Shutdown', 0
73%endif
74ENDPROC TMPL_NM_CMN(Shutdown)
75
76
77;;
78; Prints a 32-bit unsigned integer on the screen.
79;
80; @param eax The value to print.
81;
82; @uses nothing
83;
84BEGINPROC TMPL_NM_CMN(PrintU32)
85 push xBP
86 mov xBP, xSP
87 push sAX
88 push sDX
89 push sCX
90 push sBX
91%ifdef TMPL_16BIT
92 push ds
93
94 mov cx, ss
95 mov ds, cx
96%endif
97
98 ; Allocate a stack buffer and terminate it. ds:bx points ot the end.
99 sub xSP, 30h
100 mov xBX, xSP
101 add xBX, 2fh
102 mov byte [xBX], 0
103
104 mov ecx, 10 ; what to divide by
105.next:
106 xor edx, edx
107 div ecx ; edx:eax / ecx -> eax and rest in edx.
108 add dl, '0'
109 dec xBX
110 mov [xBX], dl
111 cmp eax, 0
112 jnz .next
113
114 ; Print the string.
115 mov xAX, xBX
116 call TMPL_NM_CMN(PrintStr)
117
118 add xSP, 30h
119%ifdef TMPL_16BIT
120 pop ds
121%endif
122 pop sBX
123 pop sCX
124 pop sDX
125 pop sAX
126 leave
127 ret
128ENDPROC TMPL_NM_CMN(PrintU32)
129
130
131;;
132; Equivalent to RTPrintf, but a max output length of 1KB.
133;
134; @remarks This uses an entirely STACK BASED CALLING CONVENTION where the
135; caller does the cleanup (cdecl sans volatile regs).
136;
137; @param fpszFormat The format string (far pointer on 16-bit
138; systems). See StrFormatV for format details.
139; @param ... Zero or more format string arguments.
140; @uses nothing
141;
142BEGINPROC TMPL_NM_CMN(PrintF)
143 push xBP
144 mov xBP, xSP
145 push sAX
146 push xDX
147 push xCX
148 push xBX
149%ifdef TMPL_16BIT
150 push ds
151 push es
152 push fs
153%endif
154 sub xSP, 0400h ; string buffer (1024 bytes)
155
156 ;
157 ; Format the failure string and call TestFailed.
158 ;
159%ifdef TMPL_16BIT
160 mov ax, ss ; buffer address.
161 mov ds, ax
162 mov ax, sp
163 mov xDX, 0400h ; buffer size.
164 les cx, [bp + 4] ; format string
165 mov bx, ss ; argument list
166 mov fs, bx
167 mov bx, bp
168 add bx, 8
169%else
170 mov xAX, xSP ; buffer address
171 mov xDX, 0400h ; buffer size
172 mov xCX, [xBP + xCB * 2] ; format string
173 lea xBX, [xBP + xCB * 3] ; argument list.
174%endif
175 call TMPL_NM_CMN(StrFormatV)
176 call TMPL_NM_CMN(PrintStr)
177
178 add xSP, 0400h
179%ifdef TMPL_16BIT
180 pop fs
181 pop es
182 pop ds
183%endif
184 pop xBX
185 pop xCX
186 pop xDX
187 pop sAX
188 leave
189 ret
190ENDPROC TMPL_NM_CMN(PrintF)
191
192
193;;
194; Print a string followed by a semicolon and at least one space.
195;
196; @param ds:ax The string to print.
197; @param dx The desired minimum length of the output. That is
198; string + colon + spaces.
199; @uses nothing.
200;
201BEGINPROC TMPL_NM_CMN(PrintStrColonSpaces)
202 push xBP
203 mov xBP, xSP
204 push xAX
205 push xCX
206
207 call TMPL_NM_CMN(PrintStr)
208 call TMPL_NM_CMN(StrLen)
209 mov cx, ax
210 mov al, ':'
211 call TMPL_NM_CMN(PrintChr)
212 inc cx
213 mov al, ' '
214.next_space:
215 call TMPL_NM_CMN(PrintChr)
216 inc cx
217 cmp cx, dx
218 jb .next_space
219
220 pop xCX
221 pop xAX
222 leave
223 ret
224ENDPROC TMPL_NM_CMN(PrintStrColonSpaces)
225
226
227;;
228; Print a string followed by a 0+ spaces, a semicolon and a space.
229;
230; @param ds:ax The string to print.
231; @param dx The desired minimum length of the output. That is
232; string + spaces + colon + space.
233; @uses nothing.
234;
235BEGINPROC TMPL_NM_CMN(PrintStrSpacesColonSpace)
236 push xBP
237 mov xBP, xSP
238 push xAX
239 push xCX
240
241 call TMPL_NM_CMN(PrintStr)
242 call TMPL_NM_CMN(StrLen)
243 mov cx, ax
244 inc cx
245 mov al, ' '
246.next_space:
247 inc cx
248 cmp cx, dx
249 jae .done_spaces
250 call TMPL_NM_CMN(PrintChr)
251 jmp .next_space
252.done_spaces:
253 mov al, ':'
254 call TMPL_NM_CMN(PrintChr)
255 mov al, ' '
256 call TMPL_NM_CMN(PrintChr)
257
258 pop xCX
259 pop xAX
260 leave
261 ret
262ENDPROC TMPL_NM_CMN(PrintStrSpacesColonSpace)
263
264
265;;
266; Store the current nanosecond timestamp in [ax] (qword).
267;
268; @param ds:ax Where to store the 64-bit timestamp.
269;
270; @uses nothing
271;
272BEGINPROC TMPL_NM_CMN(GetNanoTS)
273 push sAX
274 push sCX
275 push xDX
276%ifdef TMPL_16BIT
277 movzx ecx, ax
278%else
279 mov xCX, xAX
280%endif
281
282 mov dx, VMMDEV_TESTING_IOPORT_TS_LOW
283 in eax, dx
284 mov [sCX], eax
285
286 mov dx, VMMDEV_TESTING_IOPORT_TS_HIGH
287 in eax, dx
288 mov [sCX + 4], eax
289
290 pop xDX
291 pop sCX
292 pop sAX
293 ret
294ENDPROC TMPL_NM_CMN(GetNanoTS)
295
296
297
298;;
299; Calculates the time elapsed since [ax] (qword), storing it at [ax] (qword).
300;
301; @param ds:ax Where to get the start timestamp (input) and where
302; to store the time elapsed (output). qword
303;
304; @uses nothing
305;
306BEGINPROC TMPL_NM_CMN(GetElapsedNanoTS)
307 push sAX
308 push sCX
309 push xDX
310%ifdef TMPL_16BIT
311 movzx ecx, ax
312%else
313 mov xCX, xAX
314%endif
315
316 mov dx, VMMDEV_TESTING_IOPORT_TS_LOW
317 in eax, dx
318 sub eax, [sCX]
319 mov [sCX], eax
320
321 mov dx, VMMDEV_TESTING_IOPORT_TS_HIGH
322 in eax, dx
323 sbb eax, [sCX + 4]
324 mov [sCX + 4], eax
325
326 pop xDX
327 pop sCX
328 pop sAX
329 ret
330ENDPROC TMPL_NM_CMN(GetElapsedNanoTS)
331
332
333;;
334; Sends a command to VMMDev followed by a single string.
335;
336; If the VMMDev is not present or is not being used, this function will
337; do nothing.
338;
339; @param eax The command.
340; @param ds:dx The string (zero terminated).
341; @uses nothing
342; @internal
343;
344BEGINPROC TMPL_NM_CMN(testSendStrCmd)
345 push xBP
346 mov xBP, xSP
347 push sAX
348 push xBX
349 push xDX
350
351 cmp byte [g_fbBs2VMMDevTesting], 0
352 je .no_vmmdev
353
354 mov dx, VMMDEV_TESTING_IOPORT_CMD
355 out dx, eax
356
357 mov dx, VMMDEV_TESTING_IOPORT_DATA
358 pop xBX
359 push xBX
360 dec xBX
361.next_char:
362 inc xBX
363 mov al, [xBX]
364 out dx, al
365 test al, al
366 jnz .next_char
367
368.no_vmmdev:
369 pop xDX
370 pop xBX
371 pop sAX
372 leave
373 ret
374ENDPROC TMPL_NM_CMN(testSendStrCmd)
375
376
377;;
378; Equivalent to RTTestCreate + RTTestBanner
379;
380; @param DS16:xAX Pointer to a zero terminated string naming the
381; test. Must be a global constant.
382; @uses nothing
383;
384BEGINPROC TMPL_NM_CMN(TestInit)
385 push xBP
386 mov xBP, xSP
387 push sAX
388 push xDX
389
390 ; Initialize the globals.
391 mov [g_npszBs2Test], xAX
392 xor eax, eax
393 mov [g_uscBs2TestErrors], ax
394 mov [g_npszBs2SubTest], eax
395 mov [g_uscBs2SubTestAtErrors], ax
396 mov byte [g_fbBs2SubTestReported], 1
397 mov [g_uscBs2SubTests], ax
398 mov [g_uscBs2SubTestsFailed], ax
399
400 ; Print the name. RTTestBanner
401 mov xAX, [g_npszBs2Test]
402 call TMPL_NM_CMN(PrintStr)
403 mov xAX, .s_szTesting
404 call TMPL_NM_CMN(PrintStr)
405
406 ; Report it to the VMMDev.
407 mov eax, VMMDEV_TESTING_CMD_INIT
408 mov xDX, [g_npszBs2Test]
409 call TMPL_NM_CMN(testSendStrCmd)
410
411 pop xDX
412 pop sAX
413 leave
414 ret
415.s_szTesting:
416 db ': TESTING...', 13, 10, 0
417ENDPROC TMPL_NM_CMN(TestInit)
418
419
420;;
421; rtTestSubTestReport
422; @uses nothing
423; @internal
424BEGINPROC TMPL_NM_CMN(testSubTestReport)
425 push xBP
426 mov xBP, xSP
427 push sAX
428 push sCX
429 push xDX
430
431 ; Check if there is anything to do.
432 cmp byte [g_fbBs2SubTestReported], 0
433 jne .done
434 xor xAX, xAX ; load the sub test name pointer for later
435 mov xAX, [g_npszBs2SubTest]
436 test xAX, xAX
437 jz .done
438
439 ; Start the printing.
440 mov dx, 48
441 call TMPL_NM_CMN(PrintStrSpacesColonSpace)
442
443 mov byte [g_fbBs2SubTestReported], 1
444 mov cx, [g_uscBs2TestErrors]
445 sub cx, [g_uscBs2SubTestAtErrors]
446 and ecx, 0ffffh
447 jnz .failed
448
449 ; passed
450 mov xAX, .s_szPassed
451 call TMPL_NM_CMN(PrintStr)
452 jmp .vmmdev
453
454 ; failed
455.failed:
456 mov xAX, .s_szFailure
457 call TMPL_NM_CMN(PrintStr)
458 mov eax, ecx
459 call TMPL_NM_CMN(PrintU32)
460 mov xAX, .s_szFailureEnd
461 call TMPL_NM_CMN(PrintStr)
462
463 ; report to VMMDev
464.vmmdev:
465 cmp byte [g_fbBs2VMMDevTesting], 0
466 je .no_vmmdev
467
468 mov dx, VMMDEV_TESTING_IOPORT_CMD
469 mov eax, VMMDEV_TESTING_CMD_SUB_DONE
470 out dx, eax
471
472 mov dx, VMMDEV_TESTING_IOPORT_DATA
473 mov eax, ecx
474 out dx, eax
475
476.no_vmmdev:
477.done:
478 pop xDX
479 pop sCX
480 pop sAX
481 leave
482 ret
483.s_szPassed:
484 db 'PASSED', 13, 10, 0
485.s_szFailure:
486 db 'FAILED (', 0
487.s_szFailureEnd:
488 db ' errors)', 13, 10, 0
489ENDPROC TMPL_NM_CMN(testSubTestReport)
490
491
492;;
493; rtTestSubCleanup
494; @uses nothing
495; @internal
496BEGINPROC TMPL_NM_CMN(testSubCleanup)
497 push xBP
498 mov xBP, xSP
499
500 cmp dword [g_npszBs2SubTest], 0
501 je .cleaned_up
502
503 call TMPL_NM_CMN(testSubTestReport)
504 mov dword [g_npszBs2SubTest], 0
505 mov byte [g_fbBs2SubTestReported], 0
506
507.cleaned_up:
508 leave
509 ret
510ENDPROC TMPL_NM_CMN(testSubCleanup)
511
512
513;;
514; Equivalent to RTTestSub.
515;
516; @param ds:xAX Pointer to a zero terminated string naming the sub test.
517; @uses nothing
518;
519BEGINPROC TMPL_NM_CMN(TestSub)
520 push xBP
521 mov xBP, xSP
522 push sAX
523 push xDX
524
525 ; Complete and cleanup any current sub test.
526 call TMPL_NM_CMN(testSubCleanup)
527
528 ; Start a new sub test.
529 inc word [g_uscBs2SubTests]
530 mov dx, [g_uscBs2TestErrors]
531 mov [g_uscBs2SubTestAtErrors], dx
532 mov [g_npszBs2SubTest], xAX
533 mov byte [g_fbBs2SubTestReported], 0
534
535 ; Report it to the VMMDev.
536 mov xDX, xAX
537 mov eax, VMMDEV_TESTING_CMD_SUB_NEW
538 call TMPL_NM_CMN(testSendStrCmd)
539
540 pop xDX
541 pop sAX
542 leave
543 ret
544ENDPROC TMPL_NM_CMN(TestSub)
545
546
547;;
548; Calculates the error count for the current sub test.
549;
550; @returns ax Error count for the current sub test.
551; @uses ax
552;
553BEGINPROC TMPL_NM_CMN(TestSubErrorCount)
554 pushf
555
556 mov ax, [g_uscBs2TestErrors]
557 sub ax, [g_uscBs2SubTestAtErrors]
558
559 popf
560 ret
561ENDPROC TMPL_NM_CMN(TestSubErrorCount)
562
563
564
565;;
566; Equivalent to RTTestValue.
567;
568; @param ds:ax The value name.
569; @param edx The 32-bit value to report.
570; @param cl The unit (VMMDEV_TESTING_UNIT_XXX).
571; @uses nothing
572;
573BEGINPROC TMPL_NM_CMN(TestValueU32)
574 push xBP
575 mov xBP, xSP
576 push sDX
577 push sCX
578 push sAX
579 push sSI
580 pushf
581 cld
582
583 mov xSI, xAX ; xSI = name
584
585 ; Print it.
586 mov dx, 48
587 call TMPL_NM_CMN(PrintStrSpacesColonSpace)
588 mov eax, [xBP - sCB]
589 call TMPL_NM_CMN(PrintU32)
590 mov al, ' '
591 call TMPL_NM_CMN(PrintChr)
592 movzx sAX, cl ; ASSUMES correct input.
593 mov edx, eax ; edx = unit
594 shl xAX, 4 ; * 16
595 add xAX, g_aszBs2TestUnitNames
596 call TMPL_NM_CMN(PrintStr)
597 mov al, 13
598 call TMPL_NM_CMN(PrintChr)
599 mov al, 10
600 call TMPL_NM_CMN(PrintChr)
601
602 ; Report it to the host.
603 cmp byte [g_fbBs2VMMDevTesting], 0
604 je .no_vmmdev
605 mov ecx, edx ; ecx = unit
606
607 mov dx, VMMDEV_TESTING_IOPORT_CMD
608 mov eax, VMMDEV_TESTING_CMD_VALUE
609 out dx, eax
610
611 mov dx, VMMDEV_TESTING_IOPORT_DATA
612 mov eax, [xBP - sCB]
613 out dx, eax ; value - low dword
614 xor eax, eax
615 out dx, eax ; value - high dword
616 mov eax, ecx
617 out dx, eax ; unit
618.next_char:
619 lodsb
620 out dx, al
621 test al, al
622 jnz .next_char
623
624.no_vmmdev:
625 popf
626 pop sSI
627 pop sAX
628 pop sCX
629 pop sDX
630 leave
631 ret
632ENDPROC TMPL_NM_CMN(TestValueU32)
633
634
635;;
636; RTTestValue + DBGFR3RegNmQueryU64.
637;
638; @param ds:ax The value name and register name separated by a colon.
639; @uses nothing
640;
641BEGINPROC TMPL_NM_CMN(TestValueReg)
642 push xBP
643 mov xBP, xSP
644 push sDX
645 push sAX
646 push sSI
647 pushf
648 cld
649
650 mov xSI, xAX ; xSI = name
651
652 ; Report it to the host.
653 cmp byte [g_fbBs2VMMDevTesting], 0
654 je .no_vmmdev
655
656 mov dx, VMMDEV_TESTING_IOPORT_CMD
657 mov eax, VMMDEV_TESTING_CMD_VALUE_REG
658 out dx, eax
659
660 mov dx, VMMDEV_TESTING_IOPORT_DATA
661.next_char:
662 lodsb
663 out dx, al
664 test al, al
665 jnz .next_char
666
667.no_vmmdev:
668 popf
669 pop sSI
670 pop sAX
671 pop sDX
672 leave
673 ret
674ENDPROC TMPL_NM_CMN(TestValueReg)
675
676
677;;
678; Equivalent to RTTestFailed("%s", ds:xAX).
679;
680; @param ds:xAX Failure explanation.
681; @uses nothing
682;
683BEGINPROC TMPL_NM_CMN(TestFailed)
684 push xBP
685 mov xBP, xSP
686 push sAX
687 push xDX
688
689 ; Increment the error count.
690 inc word [g_uscBs2TestErrors]
691
692 ; Print failure message.
693 call TMPL_NM_CMN(PrintStr)
694
695 ; Report it to the VMMDev.
696 mov xDX, xAX
697 mov eax, VMMDEV_TESTING_CMD_FAILED
698 call TMPL_NM_CMN(testSendStrCmd)
699
700 pop xDX
701 pop sAX
702 leave
703 ret
704ENDPROC TMPL_NM_CMN(TestFailed)
705
706
707;;
708; Equivalent to RTTestFailed.
709;
710; @remarks This uses an entirely STACK BASED CALLING CONVENTION where the
711; caller does the cleanup (cdecl sans volatile regs).
712;
713; @param fpszFormat The format string (far pointer on 16-bit
714; systems). See StrFormatV for format details.
715; @param ... Zero or more format string arguments.
716; @uses nothing
717;
718BEGINPROC TMPL_NM_CMN(TestFailedF)
719 push xBP
720 mov xBP, xSP
721 push sAX
722 push xDX
723 push xCX
724 push xBX
725%ifdef TMPL_16BIT
726 push ds
727 push es
728 push fs
729%endif
730 sub xSP, 0400h ; string buffer (1024 bytes)
731
732 ;
733 ; Format the failure string and call TestFailed.
734 ;
735%ifdef TMPL_16BIT
736 mov ax, ss ; buffer address.
737 mov ds, ax
738 mov ax, sp
739 mov xDX, 0400h ; buffer size.
740 les cx, [bp + 4] ; format string
741 mov bx, ss ; argument list
742 mov fs, bx
743 mov bx, bp
744 add bx, 8
745%else
746 mov xAX, xSP ; buffer address
747 mov xDX, 0400h ; buffer size
748 mov xCX, [xBP + xCB * 2] ; format string
749 lea xBX, [xBP + xCB * 3] ; argument list.
750%endif
751 call TMPL_NM_CMN(StrFormatV)
752 call TMPL_NM_CMN(TestFailed)
753
754 add xSP, 0400h
755%ifdef TMPL_16BIT
756 pop fs
757 pop es
758 pop ds
759%endif
760 pop xBX
761 pop xCX
762 pop xDX
763 pop sAX
764 leave
765 ret
766ENDPROC TMPL_NM_CMN(TestFailedF)
767
768
769;;
770; Equivalent to RTTestSkipped("%s", ds:xAX).
771;
772; @param ds:xAX Explanation.
773; @uses nothing
774;
775BEGINPROC TMPL_NM_CMN(TestSkipped)
776 push xBP
777 mov xBP, xSP
778 push sAX
779 push xDX
780
781 ; Print reason.
782 call TMPL_NM_CMN(PrintStr)
783
784 ; Report it to the VMMDev.
785 mov xDX, xAX
786 mov eax, VMMDEV_TESTING_CMD_SKIPPED
787 call TMPL_NM_CMN(testSendStrCmd)
788
789 pop xDX
790 pop sAX
791 leave
792 ret
793ENDPROC TMPL_NM_CMN(TestSkipped)
794
795
796
797;;
798; Equivalent to RTTestSubDone.
799;
800; @uses nothing
801;
802BEGINPROC TMPL_NM_CMN(TestSubDone)
803 jmp TMPL_NM_CMN(testSubCleanup)
804ENDPROC TMPL_NM_CMN(TestSubDone)
805
806
807;;
808; Equivalent to RTTestSummaryAndDestroy, does not return.
809;
810BEGINPROC TMPL_NM_CMN(TestTerm)
811 push xBP
812 mov xBP, xSP
813 push sAX
814 push sCX
815 push xDX
816
817 ; Complete and cleanup any current sub test.
818 call TMPL_NM_CMN(testSubCleanup)
819
820 ; Print test summary.
821 mov xAX, [g_npszBs2Test]
822 call TMPL_NM_CMN(PrintStr)
823
824 mov cx, [g_uscBs2TestErrors]
825 and ecx, 0ffffh
826 jnz .failure
827
828 ; success
829 mov xAX, .s_szSuccess
830 call TMPL_NM_CMN(PrintStr)
831 jmp .vmmdev
832
833 ; failure
834.failure:
835 mov xAX, .s_szFailure
836 call TMPL_NM_CMN(PrintStr)
837 mov eax, ecx
838 call TMPL_NM_CMN(PrintU32)
839 mov xAX, .s_szFailureEnd
840 call TMPL_NM_CMN(PrintStr)
841
842 ; report to VMMDev
843.vmmdev:
844 cmp byte [g_fbBs2VMMDevTesting], 0
845 je .no_vmmdev
846
847 mov dx, VMMDEV_TESTING_IOPORT_CMD
848 mov eax, VMMDEV_TESTING_CMD_TERM
849 out dx, eax
850
851 mov dx, VMMDEV_TESTING_IOPORT_DATA
852 mov eax, ecx
853 out dx, eax
854.no_vmmdev:
855
856 ; Shut down the VM by default.
857 call TMPL_NM_CMN(Shutdown)
858
859 pop xDX
860 pop sCX
861 pop sAX
862 leave
863 ret
864.s_szSuccess:
865 db ': SUCCESS', 13, 10, 0
866.s_szFailure:
867 db ': FAILURE - ', 0
868.s_szFailureEnd:
869 db ' errors', 13, 10, 0
870ENDPROC TMPL_NM_CMN(TestTerm)
871
872
873
874
875;;
876; Report a result (elapsed time).
877;
878; @param ds:ax Pointer to the elapsed time.
879; @param edx The number of tests executed.
880; @param ds:cx The test description.
881;
882; @users nothing
883;
884BEGINPROC TMPL_NM_CMN(ReportResult)
885 push xBP
886 mov xBP, xSP
887 push sAX
888 push sDX
889 push xCX
890
891%if 0
892 push sDX
893 push xCX
894 push sDX
895 mov edx, [sAX]
896 push sDX
897 mov edx, [sAX + 4]
898 push sDX
899 push .szDbg
900 call TMPL_NM_CMN(PrintF)
901 add xSP, 4 * sCB + xCB
902 pop sDX
903 jmp .end_debug
904.szDbg:
905 db 'ReportResult(%RX32.%RX32, %RX32, %s)', 13, 10, 0
906.end_debug:
907%endif
908
909 call TMPL_NM_CMN(CalcTestPerSecond)
910 mov edx, eax
911 mov xAX, xCX
912 mov cl, VMMDEV_TESTING_UNIT_INSTRS_PER_SEC
913 call TMPL_NM_CMN(TestValueU32)
914
915 pop xCX
916 pop sDX
917 pop sAX
918 leave
919 ret
920ENDPROC TMPL_NM_CMN(ReportResult)
921
922
923%ifdef BS2_WITH_TRAPS
924;;
925; Checks a trap, complains if not the expected one.
926;
927; @param al The expected trap number.
928; @param sDX The expected trap error code.
929; @param sCX The expected fault eip.
930; @param sBX The expected fault address.
931; @returns al=1 and ZF=0 on success.
932; @returns al=0 and ZF=1 on failure
933; @uses Nothing.
934;
935BEGINPROC TMPL_NM_CMN(TestCheckTrap)
936 push xBP
937 mov xBP, xSP
938%define a_u8ExpectedTrapNo byte [xBP - xCB]
939 push xAX
940%define a_uExpectedErr sPRE [xBP - xCB - sCB*1]
941 push sDX
942%define a_uExpectedFaultPC sPRE [xBP - xCB - sCB*2]
943 push sCX
944%define a_uExpectedFaultAddr sPRE [xBP - xCB - sCB*3]
945 push sBX
946
947 ; Any traps at all?
948 cmp dword [g_u32cTraps], 0
949 jne .trapped
950 mov xAX, .s_szNoTrap
951 jmp .failed
952.trapped:
953
954 ; Exactly one trap.
955 cmp dword [g_u32cTraps], 1
956 je .one_trap
957 mov xAX, .s_szToManyTraps
958 jmp .failed
959.one_trap:
960
961 ; The right trap.
962 cmp byte [g_u8LastTrapNo], al
963 je .right_trap_no
964 mov xAX, .s_szWrongTrapNo
965 jmp .failed
966.right_trap_no:
967
968 ; The right error code.
969 cmp [g_u64LastTrapErr], sDX
970%ifndef TMPL_64BIT
971 jne .bad_err_cd
972 cmp dword [g_u64LastTrapErr + 4], 0
973%endif
974 je .right_err_cd
975.bad_err_cd:
976 mov xAX, .s_szWrongErrCd
977 jmp .failed
978.right_err_cd:
979
980 ; The fault PC.
981 cmp [g_LastTrapRegs + BS2REGS.rip], sCX
982%ifndef TMPL_64BIT
983 jne .bad_pc
984 cmp dword [g_LastTrapRegs + BS2REGS.rip + 4], 0
985%endif
986 je .right_pc
987.bad_pc:
988 mov xAX, .s_szWrongPc
989 jmp .failed
990.right_pc:
991
992
993 ; The fault address (PF only).
994 cmp al, 0eh
995 jne .right_fault_address
996 cmp [g_LastTrapRegs + BS2REGS.cr2], sBX
997%ifndef TMPL_64BIT
998 jne .bad_fault_address
999 cmp dword [g_LastTrapRegs + BS2REGS.cr2 + 4], 0
1000%endif
1001 je .right_fault_address
1002.bad_fault_address:
1003 mov xAX, .s_szWrongFaultAddress
1004 jmp .failed
1005.right_fault_address:
1006
1007 pop sBX
1008 pop sCX
1009 pop sDX
1010 pop xAX
1011 leave
1012 mov al, 1
1013 test al, al
1014 ret
1015
1016 ;
1017 ; Reportfailure
1018 ;
1019.failed:
1020 mov xDX, xSP ; save xSP - lazy bird.
1021 cmp a_u8ExpectedTrapNo, 0eh
1022 jne .not_pf2
1023%ifndef TMPL_64BIT
1024 push dword 0
1025%endif
1026 push a_uExpectedFaultAddr
1027.not_pf1:
1028%ifndef TMPL_64BIT
1029 push dword 0
1030%endif
1031 push a_uExpectedErr
1032%ifndef TMPL_64BIT
1033 push dword 0
1034%endif
1035 push a_uExpectedFaultPC
1036 movzx xBX, a_u8ExpectedTrapNo
1037 push xBX
1038 ; line break
1039 cmp a_u8ExpectedTrapNo, 0eh
1040 jne .not_pf2
1041%ifndef TMPL_64BIT
1042 push dword [g_LastTrapRegs + BS2REGS.cr2 + 4]
1043%endif
1044 push sPRE [g_LastTrapRegs + BS2REGS.cr2]
1045.not_pf2:
1046%ifndef TMPL_64BIT
1047 push dword [g_u64LastTrapErr + 4]
1048%endif
1049 push sPRE [g_u64LastTrapErr]
1050%ifndef TMPL_64BIT
1051 push dword [g_LastTrapRegs + BS2REGS.rip + 4]
1052%endif
1053 push sPRE [g_LastTrapRegs + BS2REGS.rip]
1054 movzx xBX, byte [g_u8LastTrapNo]
1055 push xBX
1056 push xAX ; msg
1057 mov xAX, .s_szFailureMsg
1058 cmp a_u8ExpectedTrapNo, 0eh
1059 jne .not_pf3
1060 mov xAX, .s_szFailurePfMsg
1061.not_pf3:
1062 push xAX ; format string
1063 call TMPL_NM_CMN(TestFailedF)
1064 mov xSP, xDX ; clean up call frame
1065
1066.done:
1067 pop sBX
1068 pop sCX
1069 pop sDX
1070 pop xAX
1071 leave
1072 xor al, al
1073 ret
1074
1075.s_szFailureMsg:
1076 db '%s', 13, 10
1077 db ' got trap %RX8 pc=%RX64 err=%RX64', 13, 10
1078 db ' expected %RX8 pc=%RX64 err=%RX64', 13, 10, 0
1079.s_szFailurePfMsg:
1080 db '%s', 13, 10
1081 db ' got trap %RX8 pc=%RX64 err=%RX64 cr2=%RX64', 13, 10,
1082 db ' expected %RX8 pc=%RX64 err=%RX64 cr2=%RX64', 13, 10, 0
1083.s_szNoTrap:
1084 db 'no traps', 0
1085.s_szToManyTraps:
1086 db 'too many traps', 0
1087.s_szWrongTrapNo:
1088 db 'wrong trap number', 0
1089.s_szWrongErrCd:
1090 db 'wrong error code', 0
1091.s_szWrongPc:
1092 db 'wrong xIP', 0
1093.s_szWrongFaultAddress:
1094 db 'wrong fault address', 0
1095%undef a_u8ExpectedTrapNo
1096%undef a_u32ExpectedErr
1097%undef a_u32ExpectedFaultPC
1098%undef a_u32ExpectedFaultAddr
1099ENDPROC TMPL_NM_CMN(TestCheckTrap)
1100%endif ; BS2_WITH_TRAPS
1101
1102
1103%ifdef BS2_WITH_TRAPS
1104;;
1105; Installs the active list of trap records (BS2TRAPREC).
1106;
1107; @param sAX Flat address of the trap records (BS2TRAPREC).
1108; Assumes that DS is FLAT.
1109; @param edx The number of trap records.
1110; @param sCX Flat image base address, i.e. what BS2TRAPREC.offWhere
1111; is relative to.
1112; @returns al=1 and ZF=0 on success.
1113; @returns al=0 and ZF=1 on failure
1114;
1115; @uses sAX (return value)
1116;
1117BEGINPROC TMPL_NM_CMN(TestInstallTrapRecs)
1118 push xBP
1119 mov xBP, xSP
1120 push sDX
1121 push sBX
1122 push sCX
1123 push sDI
1124 push sSI
1125
1126 ; Make sure the record array is within limits.
1127 cmp edx, _4M
1128 jae .nok
1129
1130 ; Scan the trap records.
1131 mov sDI, sAX
1132 mov esi, edx
1133 or esi, esi
1134 jnz .ok
1135.next:
1136 cmp dword [sDI + BS2TRAPREC.offWhere], _2G
1137 jae .nok
1138
1139 cmp dword [sDI + BS2TRAPREC.offResumeAddend], 0
1140 je .nok
1141 cmp dword [sDI + BS2TRAPREC.offResumeAddend], 0xff
1142 je .nok
1143
1144 cmp dword [sDI + BS2TRAPREC.u8TrapNo], X86_XCPT_LAST
1145 ja .nok
1146
1147 ; next.
1148 add sDI, BS2TRAPREC_size
1149 dec esi
1150 jnz .next
1151
1152 ; Set the global variables.
1153.ok:
1154 xor esi, esi
1155 mov [g_paTrapRecs + 4], esi
1156 mov [g_paTrapRecs], sAX
1157 mov [g_cTrapRecs], edx
1158 mov [g_iTrapRecLast], esi
1159 mov [g_pTrapRecBase + 4], esi
1160 mov [g_pTrapRecBase], sCX
1161 mov eax, 1
1162 or eax, eax
1163
1164.done:
1165 pop sSI
1166 pop sDI
1167 pop sBX
1168 pop sCX
1169 pop sDX
1170 leave
1171 ret
1172
1173.nok:
1174 xor eax, eax
1175 jmp .done
1176ENDPROC TMPL_NM_CMN(TestInstallTrapRecs)
1177%endif ; BS2_WITH_TRAPS
1178
1179
1180;;
1181; Calculate the number of tests executed per second.
1182;
1183; @param ds:ax Pointer to the elapsed time.
1184; @param edx The number of tests executed.
1185; @returns The tests per second in eax.
1186;
1187; @uses eax (return value)
1188;
1189BEGINPROC TMPL_NM_CMN(CalcTestPerSecond)
1190 push xBP
1191 mov xBP, xSP
1192 push sDX
1193 push sCX
1194%ifdef TMPL_16BIT
1195 movzx eax, ax
1196%endif
1197
1198 ; Calc NS per test.
1199 mov ecx, edx
1200 cmp ecx, 0
1201 jz .div_zero
1202 movzx eax, ax
1203 mov edx, [sAX + 4]
1204 cmp edx, ecx
1205 jae .div_overflow
1206 mov eax, [sAX]
1207 shld edx, eax, 10
1208 shl eax,10
1209 div ecx ; eax = NS per test
1210
1211 ; Calc tests per second.
1212 mov ecx, eax
1213 cmp ecx, 0
1214 jz .div_zero
1215 mov edx, 0xee
1216 mov eax, 0x6b280000 ; 1024G
1217 div ecx ; eax = tests per second
1218
1219.done:
1220 pop sCX
1221 pop sDX
1222 leave
1223 ret
1224
1225.div_zero:
1226 mov eax, 0
1227 jmp .done
1228
1229.div_overflow:
1230 mov eax, 4242424242
1231 jmp .done
1232ENDPROC TMPL_NM_CMN(CalcTestPerSecond)
1233
1234
1235;;
1236; Calculate the number of iterations for a benchmark based on the time a short
1237; calibration run too.
1238;
1239; @param ds:xAX Pointer to the elapsed time.
1240; @param edx The number of tests iterations executed.
1241; @param ecx The desired test length, in seconds.
1242; @returns The tests iterations in eax.
1243;
1244; @uses eax (return value)
1245;
1246BEGINPROC TMPL_NM_CMN(CalcBenchmarkIterations)
1247 push xBP
1248 mov xBP, xSP
1249 push sDX
1250 push sCX
1251%ifdef TMPL_16BIT
1252 movzx eax, ax
1253%endif
1254
1255 ; Calc NS per test.
1256 mov ecx, edx
1257 cmp ecx, 0
1258 jz .div_zero
1259 movzx eax, ax
1260 mov edx, [sAX + 4]
1261 cmp edx, ecx
1262 jae .div_overflow
1263 mov eax, [sAX]
1264 div ecx ; eax = NS per test
1265
1266 ; Calc tests per second.
1267 mov ecx, eax
1268 cmp ecx, 0
1269 jz .div_zero
1270 xor edx, edx
1271 mov eax, 1000000000 ; 1G
1272 div ecx ; eax = tests per second
1273
1274 ; Multiply this up to the desired number of seconds.
1275 mov edx, [xBP - xCB*2]
1276 mul edx
1277 test edx, edx
1278 jnz .mult_32bit_overflow
1279 cmp eax, _64K
1280 jle .too_small
1281
1282.done:
1283 pop sCX
1284 pop sDX
1285 leave
1286 ret
1287
1288.too_small:
1289 mov eax, _64K
1290 jmp .done
1291
1292.mult_32bit_overflow:
1293 mov eax, 0ffff0000h
1294 jmp .done
1295
1296.div_zero:
1297 mov eax, [xBP - xCB]
1298 shl eax, 8
1299 jmp .fudge
1300
1301.div_overflow:
1302 mov eax, [xBP - xCB]
1303 shr eax, 4
1304.fudge:
1305 add eax, 10
1306 jmp .done
1307ENDPROC TMPL_NM_CMN(CalcBenchmarkIterations)
1308
1309
1310;;
1311; Prints a string on the screen.
1312;
1313; @param ds:ax The string to find the length of.
1314; @returns The string length in ax.
1315;
1316; @uses ax (return value)
1317;
1318BEGINPROC TMPL_NM_CMN(StrLen)
1319 push xBP
1320 mov xBP, xSP
1321 push xBX
1322
1323 mov xBX, xAX
1324 dec xBX
1325.next:
1326 inc xBX
1327 cmp byte [xBX], byte 0
1328 jnz .next
1329
1330 xchg xAX, xBX
1331 sub xAX, xBX
1332
1333 pop xBX
1334 leave
1335 ret
1336ENDPROC TMPL_NM_CMN(StrLen)
1337
1338
1339
1340;;
1341; Simple string format, taking an argument list.
1342;
1343; Implemented:
1344; - %RX8
1345; - %RX16
1346; - %RX32
1347; - %RX64
1348; - %s
1349;
1350; Planned:
1351; - %RU8
1352; - %RU16
1353; - %RU32
1354; - %RU64
1355; - %RI8
1356; - %RI16
1357; - %RI32
1358; - %RI64
1359;
1360; @param ds:xAX The buffer address.
1361; @param xDX The buffer size.
1362; @param es:xCX The format string.
1363; @param fs:xBX The argument list.
1364; @uses nothing
1365;
1366BEGINPROC TMPL_NM_CMN(StrFormatV)
1367 push xBP
1368 mov xBP, xSP
1369 push sAX
1370 push sDX
1371 push sCX
1372 push sBX
1373 push sDI
1374 push sSI
1375 pushf
1376 cld
1377%ifdef TMPL_16BIT
1378 push ds
1379 push es
1380 push fs
1381 push gs
1382
1383 mov si, ds
1384 mov di, es
1385 mov ds, di
1386 mov es, si
1387 mov di, ax ; es:di -> output buffer.
1388 mov si, cx ; ds:si -> format string.
1389%define a_pArgs [fs:bx]
1390%define a_pu32ArgsHighDW dword [fs:bx + 4]
1391%else
1392 mov xDI, xAX ; (es:)xDI -> output buffer.
1393 mov xSI, xCX ; (ds:)xSI -> format string.
1394%define a_pArgs [xBX]
1395%define a_pu32ArgsHighDW dword [xBX + 4]
1396%endif
1397 xchg xCX, xDX ; xCX=buffer size.
1398
1399 ;
1400 ; Make sure we've got space for a terminator char in the output buffer.
1401 ;
1402 test xCX, xCX
1403 jz .return
1404 dec xCX
1405 jz .done
1406
1407 ;
1408 ; In this loop we're free to use sDX and (with some caution) sAX.
1409 ;
1410.format_loop:
1411 lodsb
1412 test al, al
1413 jz .done
1414 cmp al, '%'
1415 je .switch
1416
1417 ; Emit the character in al if there is room for it.
1418.emit_al:
1419 test xCX, xCX
1420 jz .done
1421 stosb
1422 dec xCX
1423 jmp .format_loop
1424
1425 ; Try recognize the format specifier.
1426.switch:
1427 lodsb
1428 cmp al, 's'
1429 je .switch_case_string
1430 cmp al, 'c'
1431 je .switch_case_char
1432 cmp al, 'R'
1433 jne .switch_default
1434 lodsb
1435 cmp al, 'X'
1436 jne .switch_case_number
1437 cmp al, 'U'
1438 jne .switch_case_number
1439 cmp al, 'I'
1440 jne .switch_case_number
1441
1442.switch_default:
1443 test al, al
1444 jz .done
1445 mov al, '!'
1446 jmp .emit_al
1447
1448 ; parse the number part.
1449.switch_case_number:
1450 mov ah, al ; ah = {X,U,I}
1451 lodsb
1452 cmp al, '8'
1453 je .switch_case_number_8bit
1454 cmp al, '1'
1455 je .switch_case_number_16bit
1456 cmp al, '3'
1457 je .switch_case_number_32bit
1458 cmp al, '6'
1459 je .switch_case_number_64bit
1460 jmp .switch_default
1461
1462
1463 ;
1464 ; Common code for 8-bit, 16-bit and 32-bit.
1465 ;
1466 ; The first part load the value into edx, ah={X,U,I},
1467 ; al=(max-hex, max-unsigned-dec).
1468 ;
1469.switch_case_number_8bit:
1470 mov al, (2 << 4) | 2
1471 movzx edx, byte a_pArgs
1472 add xBX, xCB
1473 cmp ah, 'I'
1474 jne .switch_case_number_common_32bit_hex_or_unsigned
1475 movsx edx, dl
1476 jmp .switch_case_number_common_32bit_signed
1477
1478.switch_case_number_16bit:
1479 lodsb
1480 cmp al, '6'
1481 jne .switch_default
1482 mov al, (4 << 4) | 5
1483 movzx edx, word a_pArgs
1484 add xBX, xCB
1485 cmp ah, 'I'
1486 jne .switch_case_number_common_32bit_hex_or_unsigned
1487 movsx edx, dx
1488 jmp .switch_case_number_common_32bit_signed
1489
1490.switch_case_number_32bit:
1491 lodsb
1492 cmp al, '2'
1493 jne .switch_default
1494 mov al, (8 << 4) | 10
1495 mov edx, dword a_pArgs
1496 add xBX, sCB
1497 cmp ah, 'I'
1498 je .switch_case_number_common_32bit_signed
1499
1500.switch_case_number_common_32bit_hex_or_unsigned:
1501 cmp ah, 'X'
1502 jne .switch_case_number_common_32bit_unsigned
1503 shr al, 4
1504 and xAX, 0fh
1505 cmp xCX, xAX
1506 jb .switch_case_number_bad_buf
1507 call .format_32bit_hex_subroutine
1508 jmp .format_loop
1509
1510.switch_case_number_common_32bit_unsigned:
1511 and xAX, 0fh
1512 cmp xCX, xAX
1513 jb .switch_case_number_bad_buf
1514 call .format_32bit_dec_subroutine
1515 jmp .format_loop
1516
1517.switch_case_number_common_32bit_signed:
1518 cmp edx, 0
1519 jge .switch_case_number_common_32bit_unsigned
1520 and xAX, 0fh
1521 inc xAX ; sign char
1522 cmp xCX, xAX
1523 jb .switch_case_number_bad_buf
1524 ; Emit the minus sign, invert the value and join the unsigned formatting.
1525 push xAX
1526 mov al, '-'
1527 stosb
1528 dec xCX
1529 pop xAX
1530 neg edx
1531 call .format_32bit_dec_subroutine
1532 jmp .format_loop
1533
1534
1535 ;
1536 ; 64-bit is special, to simplify we treat all formats as hex...
1537 ;
1538.switch_case_number_64bit:
1539 lodsb
1540 cmp al, '4'
1541 jne .switch_default
1542 cmp ah, 'X'
1543 je .switch_case_number_64bit_hex
1544 cmp ah, 'I'
1545 je .switch_case_number_64bit_signed
1546 jmp .switch_case_number_64bit_unsigned
1547
1548.switch_case_number_64bit_hex:
1549 mov eax, dword a_pArgs
1550 mov edx, a_pu32ArgsHighDW
1551 add xBX, 8
1552 cmp xCX, 8+1+8
1553 jb .switch_case_number_bad_buf
1554 ; Simple, format it as two 32-bit hex values.
1555 push sAX
1556 mov eax, 8
1557 call .format_32bit_hex_subroutine
1558 mov al, 27h ; '\'' - how do we escape this with yasm?
1559 stosb
1560 dec xCX
1561 pop sDX
1562 mov eax, 8
1563 call .format_32bit_hex_subroutine
1564 jmp .format_loop
1565
1566.switch_case_number_64bit_unsigned:
1567 cmp xCX, 19
1568 jb .switch_case_number_bad_buf
1569.switch_case_number_64bit_unsigned_format_it:
1570 ;; @todo implement me
1571 jmp .switch_case_number_64bit_hex
1572
1573.switch_case_number_64bit_signed:
1574 mov eax, dword a_pArgs
1575 mov edx, a_pu32ArgsHighDW
1576 add xBX, 8
1577 cmp xCX, 20
1578 jb .switch_case_number_bad_buf
1579 test edx, 080000000h
1580 jz .switch_case_number_64bit_unsigned_format_it
1581 ; Emit the minus sign, invert the value and join the unsigned formatting.
1582 push xAX
1583 mov al, '-'
1584 stosb
1585 dec xCX
1586 pop xAX
1587 neg eax
1588 neg edx
1589 jmp .switch_case_number_64bit_unsigned_format_it
1590
1591
1592 ; The remaining buffer is too small to hold the number.
1593.switch_case_number_bad_buf:
1594 mov al, '^'
1595 jmp .emit_al
1596
1597
1598 ;
1599 ; Emit a string.
1600 ;
1601.switch_case_string:
1602%ifdef TMPL_16BIT
1603 lgs dx, a_pArgs
1604 add xBX, 4
1605%else
1606 mov xDX, a_pArgs
1607 add xBX, xCB
1608%endif
1609 test xCX, xCX
1610.switch_case_string_loop:
1611 jz .done
1612%ifdef TMPL_16BIT
1613 mov al, [gs:edx]
1614%else
1615 mov al, [xDX]
1616%endif
1617 test al, al
1618 jz .format_loop
1619 inc xDX
1620 stosb
1621 dec xCX
1622 jmp .switch_case_string_loop
1623
1624 ;
1625 ; Emit a char.
1626 ;
1627.switch_case_char:
1628 mov al, byte a_pArgs
1629 add xBX, xCB
1630 jmp .emit_al
1631
1632
1633 ;
1634 ; Done, just emit the terminator char.
1635 ;
1636.done:
1637 xor al, al
1638 stosb
1639
1640.return:
1641%ifdef TMPL_16BIT
1642 pop gs
1643 pop fs
1644 pop es
1645 pop ds
1646%endif
1647 popf
1648 pop sSI
1649 pop sDI
1650 pop sBX
1651 pop sCX
1652 pop sDX
1653 pop sAX
1654 leave
1655 ret
1656%undef a_pArgs
1657%undef a_pu32ArgsHighDW
1658
1659;;
1660; Internal subroutine for formatting a hex number into the buffer.
1661; @param al The precision (2, 4, 8).
1662; @param edx The value.
1663;
1664; @uses ecx, edi
1665;
1666.format_32bit_hex_subroutine:
1667 push xAX
1668 push sDX
1669 push xBX
1670
1671 ; Rotate edx into position.
1672 mov ebx, 8
1673 sub bl, al
1674 shl bl, 2
1675 xchg cl, bl
1676 rol edx, cl
1677 xchg bl, cl
1678
1679 mov bl, al ; Width counter
1680.format_32bit_hex_subroutine_next:
1681 rol edx, 4
1682 mov eax, edx
1683 and eax, 0fh
1684 add sAX, g_achHex
1685 mov al, [cs:sAX]
1686 stosb
1687 dec xCX
1688 dec bl
1689 jnz .format_32bit_hex_subroutine_next
1690
1691 pop xBX
1692 pop sDX
1693 pop xAX
1694 ret
1695
1696
1697;;
1698; Internal subroutine for formatting a hex number into the buffer.
1699; @param al The max precision (2, 5, 10).
1700; @param edx The value.
1701; @param xCX Counter register to decrement as characters are emited.
1702; @param es:xDI Where to write the output, xDI is updated.
1703;
1704; @uses xCX, xDI
1705;
1706.format_32bit_dec_subroutine:
1707%if 0 ;; @todo implement this
1708 sub xSP, 20h
1709 ; Format in reverse order into a stack buffer.
1710
1711 ; Append the stack buffer to the string, reversing it in the process.
1712
1713 add xSP, 20h
1714%else
1715 call .format_32bit_hex_subroutine
1716%endif
1717 ret
1718
1719ENDPROC TMPL_NM_CMN(StrFormatV)
1720
1721
1722;;
1723; Very limited RTStrPrintf version.
1724;
1725; @remarks This uses an entirely STACK BASED CALLING CONVENTION where the
1726; caller does the cleanup (cdecl sans volatile regs).
1727;
1728; @param fpszBuf The output buffer.
1729; @param cbBuf The output buffer size (natural size).
1730; @param fpszFormat The format string (far pointer in 16-bit).
1731; See StrFormatV for format.
1732; @param ... Zero or more format string arguments.
1733; @uses nothing
1734;
1735BEGINPROC TMPL_NM_CMN(StrFormatF)
1736 push xBP
1737 mov xBP, xSP
1738 push xAX
1739 push xDX
1740 push xCX
1741 push xBX
1742%ifdef TMPL_16BIT
1743 push ds
1744 push es
1745 push fs
1746
1747 lds xAX, [bp + 04h]
1748 mov dx, [bp + 08h]
1749 les xCX, [bp + 0ah]
1750 mov bx, ss
1751 mov fs, bx
1752 mov bx, bp
1753 add bx, 0eh
1754%else
1755 mov xAX, [xBP + xCB * 2]
1756 mov xDX, [xBP + xCB * 3]
1757 mov xCX, [xBP + xCB * 4]
1758 lea xBX, [xBP + xCB * 5]
1759%endif
1760 call TMPL_NM_CMN(StrFormatV)
1761
1762%ifdef TMPL_16BIT
1763 pop fs
1764 pop es
1765 pop ds
1766%endif
1767 pop xBX
1768 pop xCX
1769 pop xDX
1770 pop xAX
1771 leave
1772 ret
1773ENDPROC TMPL_NM_CMN(StrFormatF)
1774
1775
1776;;
1777; Dumps the CPU registers.
1778;
1779; @uses Nothing.
1780;
1781BEGINPROC TMPL_NM_CMN(TestDumpCurrentRegisters)
1782%ifndef TMPL_64BIT
1783 push xBP
1784 mov xBP, xSP
1785 push eax
1786 pushfd
1787
1788 push dword [xBP - sCB - 4] ; eflags
1789 mov eax, cr2
1790 push eax
1791 xor eax, eax
1792 mov eax, gs
1793 push eax
1794 mov eax, fs
1795 push eax
1796 mov eax, es
1797 push eax
1798 mov eax, ds
1799 push eax
1800 mov eax, cs
1801 push eax
1802
1803 mov eax, cr4
1804 push eax
1805 mov eax, cr3
1806 push eax
1807 mov eax, cr0
1808 push eax
1809 mov eax, ebp ; return EBP
1810 mov xAX, [xBP]
1811 push eax
1812
1813 mov eax, ebp ; return ESP
1814 add xAX, xCB
1815 push eax
1816
1817 mov xAX, [xBP + xCB] ; return EIP
1818 %ifdef TMPL_16BIT
1819 movzx eax, ax
1820 %endif
1821 push eax
1822
1823 push edi
1824 push esi
1825 push edx
1826 push ecx
1827 push ebx
1828 push dword [xBP - sCB] ; eax
1829
1830 %ifdef TMPL_16BIT
1831 push cs
1832 %endif
1833 push .s_szRegFmt
1834 call TMPL_NM_CMN(PrintF)
1835
1836 popfd
1837 pop eax
1838 leave
1839 ret
1840
1841.s_szRegFmt:
1842 db 'eax=%RX32 ebx=%RX32 ecx=%RX32 edx=%RX32 esi=%RX32 edi=%RX32', 13, 10
1843 db 'eip=%RX32 esp=%RX32 ebp=%RX32 cr0=%RX32 cr3=%RX32 cr4=%RX32', 13, 10
1844 db 'cs=%RX16 ds=%RX16 es=%RX16 fs=%RX16 gs=%RX16 ss=%RX16 cr2=%RX32 eflags=%RX32', 13, 10, 0
1845
1846%else ; 64-bit
1847 push .s_szRegFmt
1848 call TMPL_NM_CMN(PrintF)
1849 ret
1850
1851.s_szRegFmt:
1852 db 'TestDumpCurrentRegisters not implemented', 13, 10, 0
1853
1854%endif ; 64-bit
1855ENDPROC TMPL_NM_CMN(TestDumpCurrentRegisters)
1856
1857
1858
1859;;
1860; Dumps the CPU registers.
1861;
1862; @param ds:xAX Pointer to the register frame to dump.
1863; @uses Nothing.
1864;
1865BEGINPROC TMPL_NM_CMN(TestDumpRegisters)
1866 push xBP
1867 mov xBP, xSP
1868 pushf
1869 push sDX
1870 push sBX
1871 mov xBX, xAX
1872
1873 cmp byte [xBX + BS2REGS.cBits], 64
1874 je .dump_64bit_regs
1875
1876 push -1 ; sanity
1877 mov edx, [xBX + BS2REGS.rflags]
1878 push sDX
1879 mov edx, [xBX + BS2REGS.cr2]
1880 push sDX
1881 xor edx, edx
1882 mov dx, [xBX + BS2REGS.ss]
1883 push xDX
1884 mov dx, [xBX + BS2REGS.gs]
1885 push xDX
1886 mov dx, [xBX + BS2REGS.fs]
1887 push xDX
1888 mov dx, [xBX + BS2REGS.es]
1889 push xDX
1890 mov dx, [xBX + BS2REGS.ds]
1891 push xDX
1892 mov dx, [xBX + BS2REGS.cs]
1893 push xDX
1894
1895 mov edx, [xBX + BS2REGS.cr4]
1896 push sDX
1897 mov edx, [xBX + BS2REGS.cr3]
1898 push sDX
1899 mov edx, [xBX + BS2REGS.cr0]
1900 push sDX
1901 mov edx, [xBX + BS2REGS.rbp]
1902 push sDX
1903 mov edx, [xBX + BS2REGS.rsp]
1904 push sDX
1905 mov edx, [xBX + BS2REGS.rip]
1906 push sDX
1907
1908 mov edx, [xBX + BS2REGS.rdi]
1909 push sDX
1910 mov edx, [xBX + BS2REGS.rsi]
1911 push sDX
1912 mov edx, [xBX + BS2REGS.rdx]
1913 push sDX
1914 mov edx, [xBX + BS2REGS.rcx]
1915 push sDX
1916 mov edx, [xBX + BS2REGS.rbx]
1917 push sDX
1918 mov edx, [xBX + BS2REGS.rax]
1919 push sDX
1920
1921%ifdef TMPL_16BIT
1922 push cs
1923%endif
1924 push .s_szReg32Fmt
1925 call TMPL_NM_CMN(PrintF)
1926 jmp .return
1927
1928.dump_64bit_regs:
1929%ifdef TMPL_16BIT
1930 push cs
1931%endif
1932 push .s_szReg64Fmt
1933 call TMPL_NM_CMN(PrintF)
1934
1935.return:
1936 lea xSP, [xBP - sCB*2 - xCB]
1937 pop sBX
1938 pop sDX
1939 popf
1940 leave
1941 ret
1942
1943.s_szReg32Fmt:
1944 db 'eax=%RX32 ebx=%RX32 ecx=%RX32 edx=%RX32 esi=%RX32 edi=%RX32', 13, 10
1945 db 'eip=%RX32 esp=%RX32 ebp=%RX32 cr0=%RX32 cr3=%RX32 cr4=%RX32', 13, 10
1946 db 'cs=%RX16 ds=%RX16 es=%RX16 fs=%RX16 gs=%RX16 ss=%RX16 cr2=%RX32 eflags=%RX32', 13, 10
1947 db 0
1948
1949.s_szReg64Fmt:
1950 db 'TestDumpCurrentRegisters not implemented', 13, 10, 0
1951ENDPROC TMPL_NM_CMN(TestDumpRegisters)
1952
1953
1954;;
1955; Saves the CPU registers.
1956;
1957; @param ds:xAX Pointer to the register frame to dump.
1958; @uses Nothing.
1959;
1960BEGINPROC TMPL_NM_CMN(TestSaveRegisters)
1961 push xBP
1962 mov xBP, xSP
1963%ifdef TMPL_16BIT
1964 pushfd
1965%else
1966 pushf ; - 1*sCB
1967%endif
1968 push sBX ; - 2*sCB
1969 push sAX ; - 3*sCB
1970 push sDX ; - 4*sCB
1971
1972 xor edx, edx ; zero register.
1973 mov xBX, xAX ; xBX for addressing, xAX for scratch.
1974
1975%ifdef TMPL_64BIT
1976 mov rax, [xSP + sCB*1]
1977 mov [xBX + BS2REGS.rax], rax
1978 mov rax, [xSP + sCB*2]
1979 mov [xBX + BS2REGS.rbx], rax
1980 mov [xBX + BS2REGS.rcx], rcx
1981 mov rax, [xSP]
1982 mov [xBX + BS2REGS.rdx], rax
1983 mov [xBX + BS2REGS.rdi], rdi
1984 mov [xBX + BS2REGS.rsi], rsi
1985 mov rax, [xBP]
1986 mov [xBX + BS2REGS.rbp], rax
1987 lea rax, [xBP + 16]
1988 mov [xBX + BS2REGS.rsp], rax
1989 mov rax, [xBP + 8]
1990 mov [xBX + BS2REGS.rip], rax
1991 mov [xBX + BS2REGS.r8], r8
1992 mov [xBX + BS2REGS.r9], r9
1993 mov [xBX + BS2REGS.r10], r10
1994 mov [xBX + BS2REGS.r11], r11
1995 mov [xBX + BS2REGS.r12], r12
1996 mov [xBX + BS2REGS.r13], r13
1997 mov [xBX + BS2REGS.r14], r14
1998 mov [xBX + BS2REGS.r15], r15
1999 mov rax, [xBP - sCB]
2000 mov [xBX + BS2REGS.rflags], rax
2001 mov ax, cs
2002 mov [xBX + BS2REGS.cs], ax
2003 mov ax, ds
2004 mov [xBX + BS2REGS.ds], ax
2005 mov ax, es
2006 mov [xBX + BS2REGS.es], ax
2007 mov ax, fs
2008 mov [xBX + BS2REGS.fs], ax
2009 mov ax, gs
2010 mov [xBX + BS2REGS.gs], ax
2011 mov ax, ss
2012 mov [xBX + BS2REGS.ss], ax
2013 mov byte [xBX + BS2REGS.cBits], 64
2014 mov [xBX + BS2REGS.pad ], dl
2015 mov [xBX + BS2REGS.pad + 1], dx
2016 mov rax, cr0
2017 mov [xBX + BS2REGS.cr0], rax
2018 mov rax, cr2
2019 mov [xBX + BS2REGS.cr2], rax
2020 mov rax, cr3
2021 mov [xBX + BS2REGS.cr3], rax
2022 mov rax, cr4
2023 mov [xBX + BS2REGS.cr4], rax
2024 mov rax, cr8
2025 mov [xBX + BS2REGS.cr8], rax
2026%else ; !TMPL_64
2027 mov eax, [xBP - sCB*3]
2028 mov dword [xBX + BS2REGS.rax], eax
2029 mov dword [xBX + BS2REGS.rax + 4], edx
2030 mov eax, [xBP - sCB*2]
2031 mov dword [xBX + BS2REGS.rbx], eax
2032 mov dword [xBX + BS2REGS.rbx + 4], edx
2033 mov dword [xBX + BS2REGS.rcx], ecx
2034 mov dword [xBX + BS2REGS.rcx + 4], edx
2035 mov eax, [xBP - sCB*4]
2036 mov dword [xBX + BS2REGS.rdx], eax
2037 mov dword [xBX + BS2REGS.rdx + 4], edx
2038 mov dword [xBX + BS2REGS.rdi], edi
2039 mov dword [xBX + BS2REGS.rdi + 4], edx
2040 mov dword [xBX + BS2REGS.rsi], esi
2041 mov dword [xBX + BS2REGS.rsi + 4], edx
2042 mov eax, ebp
2043 mov ax, [xBP]
2044 mov dword [xBX + BS2REGS.rbp], eax
2045 mov dword [xBX + BS2REGS.rbp + 4], edx
2046 %ifdef TMPL_16BIT
2047 mov eax, esp
2048 mov ax, bp
2049 sub ax, 4
2050 %else
2051 lea eax, [ebp + 8]
2052 %endif
2053 mov dword [xBX + BS2REGS.rsp], eax
2054 mov dword [xBX + BS2REGS.rsp + 4], edx
2055 %ifdef TMPL_16BIT
2056 movzx eax, word [xBP + 2]
2057 %else
2058 mov eax, [xBP + 4]
2059 %endif
2060 mov dword [xBX + BS2REGS.rip], eax
2061 mov dword [xBX + BS2REGS.rip + 4], edx
2062 mov dword [xBX + BS2REGS.r8 ], edx
2063 mov dword [xBX + BS2REGS.r8 + 4], edx
2064 mov dword [xBX + BS2REGS.r9 ], edx
2065 mov dword [xBX + BS2REGS.r9 + 4], edx
2066 mov dword [xBX + BS2REGS.r10 ], edx
2067 mov dword [xBX + BS2REGS.r10 + 4], edx
2068 mov dword [xBX + BS2REGS.r11 ], edx
2069 mov dword [xBX + BS2REGS.r11 + 4], edx
2070 mov dword [xBX + BS2REGS.r12 ], edx
2071 mov dword [xBX + BS2REGS.r12 + 4], edx
2072 mov dword [xBX + BS2REGS.r13 ], edx
2073 mov dword [xBX + BS2REGS.r13 + 4], edx
2074 mov dword [xBX + BS2REGS.r14 ], edx
2075 mov dword [xBX + BS2REGS.r14 + 4], edx
2076 mov dword [xBX + BS2REGS.r15 ], edx
2077 mov dword [xBX + BS2REGS.r15 + 4], edx
2078 mov eax, [xBP - sCB]
2079 mov dword [xBX + BS2REGS.rflags], eax
2080 mov dword [xBX + BS2REGS.rflags + 4], edx
2081 mov ax, cs
2082 mov [xBX + BS2REGS.cs], ax
2083 mov ax, ds
2084 mov [xBX + BS2REGS.ds], ax
2085 mov ax, es
2086 mov [xBX + BS2REGS.es], ax
2087 mov ax, fs
2088 mov [xBX + BS2REGS.fs], ax
2089 mov ax, gs
2090 mov [xBX + BS2REGS.gs], ax
2091 mov ax, ss
2092 mov [xBX + BS2REGS.ss], ax
2093 %ifdef TMPL_16BIT
2094 mov byte [xBX + BS2REGS.cBits], 16
2095 %else
2096 mov byte [xBX + BS2REGS.cBits], 32
2097 %endif
2098 mov [xBX + BS2REGS.pad ], dl
2099 mov [xBX + BS2REGS.pad + 1], dx
2100 mov eax, cr0
2101 mov dword [xBX + BS2REGS.cr0], eax
2102 mov dword [xBX + BS2REGS.cr0 + 4], edx
2103 mov eax, cr2
2104 mov dword [xBX + BS2REGS.cr2], eax
2105 mov dword [xBX + BS2REGS.cr2 + 4], edx
2106 mov eax, cr3
2107 mov dword [xBX + BS2REGS.cr3], eax
2108 mov dword [xBX + BS2REGS.cr3 + 4], edx
2109 mov eax, cr4
2110 mov dword [xBX + BS2REGS.cr4], eax
2111 mov dword [xBX + BS2REGS.cr4 + 4], edx
2112 mov dword [xBX + BS2REGS.cr8], edx
2113 mov dword [xBX + BS2REGS.cr8 + 4], edx
2114%endif ; !TMPL_64
2115
2116.return:
2117 pop sDX
2118 pop sAX
2119 pop sBX
2120%ifdef TMPL_16BIT
2121 popfd
2122%else
2123 popf
2124%endif
2125 leave
2126 ret
2127ENDPROC TMPL_NM_CMN(TestSaveRegisters)
2128
2129
2130;;
2131; Restores the CPU registers, except for rsp, rip, cs, ss and ds.
2132;
2133; @param ds:xAX Pointer to the register frame to dump.
2134; @uses All, but RSP, RIP, CS, SS and DS.
2135;
2136BEGINPROC TMPL_NM_CMN(TestRestoreRegisters)
2137 push xBP
2138 mov xBP, xSP
2139%ifdef TMPL_16BIT
2140 pushfd
2141%else
2142 pushf ; - 1*sCB
2143%endif
2144 push sBX ; - 2*sCB
2145 push sAX ; - 3*sCB
2146
2147 mov xBX, xAX ; xBX for addressing, xAX for scratch.
2148
2149 mov sAX, [xBX + BS2REGS.rax]
2150 mov [xBP - 3*sCB], sAX
2151 mov sAX, [xBX + BS2REGS.rbx]
2152 mov [xBP - 2*sCB], sAX
2153 mov sCX, [xBX + BS2REGS.rcx]
2154 mov sDX, [xBX + BS2REGS.rdx]
2155 mov sDI, [xBX + BS2REGS.rdi]
2156 mov sSI, [xBX + BS2REGS.rsi]
2157 ; skip rsp, rbp or rip.
2158%ifdef TMPL_64BIT
2159 mov r8, [xBX + BS2REGS.r8]
2160 mov r9, [xBX + BS2REGS.r9]
2161 mov r10, [xBX + BS2REGS.r10]
2162 mov r11, [xBX + BS2REGS.r11]
2163 mov r12, [xBX + BS2REGS.r12]
2164 mov r13, [xBX + BS2REGS.r13]
2165 mov r14, [xBX + BS2REGS.r14]
2166 mov r15, [xBX + BS2REGS.r15]
2167%endif
2168 mov sAX, [xBX + BS2REGS.rflags]
2169 mov [xBP - sCB], sAX
2170 ; skip cs & ds.
2171 mov ax, [xBX + BS2REGS.es]
2172 mov es, ax
2173 mov ax, [xBX + BS2REGS.fs]
2174 mov fs, ax
2175 mov ax, [xBX + BS2REGS.gs]
2176 mov gs, ax
2177 ; skip ss
2178 mov sAX, [xBX + BS2REGS.cr0]
2179 mov cr0, sAX
2180 mov sAX, [xBX + BS2REGS.cr2]
2181 mov cr2, sAX
2182 mov sAX, [xBX + BS2REGS.cr3]
2183 mov cr3, sAX
2184 mov sAX, [xBX + BS2REGS.cr4]
2185 mov cr4, sAX
2186
2187.return:
2188 pop sAX
2189 pop sBX
2190%ifdef TMPL_16BIT
2191 popfd
2192%else
2193 popf
2194%endif
2195 leave
2196 ret
2197ENDPROC TMPL_NM_CMN(TestRestoreRegisters)
2198
2199
2200;;
2201; Enables the A20 gate.
2202;
2203; @uses Nothing.
2204;
2205BEGINPROC TMPL_NM_CMN(Bs2EnableA20)
2206 call TMPL_NM_CMN(Bs2EnableA20ViaPortA)
2207; call TMPL_NM_CMN(Bs2EnableA20ViaKbd)
2208 ret
2209ENDPROC TMPL_NM_CMN(Bs2EnableA20)
2210
2211
2212;;
2213; Disables the A20 gate.
2214;
2215; @uses Nothing.
2216;
2217BEGINPROC TMPL_NM_CMN(Bs2DisableA20)
2218 ; Must call both because they may be ORed together on real HW.
2219 call TMPL_NM_CMN(Bs2DisableA20ViaKbd)
2220 call TMPL_NM_CMN(Bs2DisableA20ViaPortA)
2221 ret
2222ENDPROC TMPL_NM_CMN(Bs2DisableA20)
2223
2224
2225;;
2226; Waits for the keyboard controller to become ready.
2227;
2228; @uses Nothing
2229;
2230BEGINPROC TMPL_NM_CMN(Bs2KbdWait)
2231 push xAX
2232
2233.check_status:
2234 in al, 64h
2235 test al, 1 ; KBD_STAT_OBF
2236 jnz .read_data_and_status
2237 test al, 2 ; KBD_STAT_IBF
2238 jnz .check_status
2239
2240 pop xAX
2241 ret
2242
2243.read_data_and_status:
2244 in al, 60h
2245 jmp .check_status
2246ENDPROC TMPL_NM_CMN(Bs2KbdWait)
2247
2248
2249;;
2250; Sends a read command to the keyboard controller and gets the result.
2251;
2252; The caller is responsible for making sure the keyboard controller is ready
2253; for a command (call Bs2KbdWait if unsure).
2254;
2255; @param al The read command.
2256; @returns The value read is returned.
2257; @uses al (obviously)
2258;
2259BEGINPROC TMPL_NM_CMN(Bs2KbdRead)
2260 out 64h, al ; Write the command.
2261
2262.check_status:
2263 in al, 64h
2264 test al, 1 ; KBD_STAT_OBF
2265 jz .check_status
2266
2267 in al, 60h ; Read the data.
2268 ret
2269ENDPROC TMPL_NM_CMN(Bs2KbdRead)
2270
2271
2272;;
2273; Sends a write command to the keyboard controller and then sends the data.
2274;
2275; The caller is responsible for making sure the keyboard controller is ready
2276; for a command (call Bs2KbdWait if unsure).
2277;
2278; @param al The write command.
2279; @param ah The data to write.
2280; @uses Nothing.
2281;
2282; @todo Return status?
2283;
2284BEGINPROC TMPL_NM_CMN(Bs2KbdWrite)
2285 out 64h, al ; Write the command.
2286 call TMPL_NM_CMN(Bs2KbdWait)
2287
2288 xchg al, ah
2289 out 60h, al ; Write the data.
2290 call TMPL_NM_CMN(Bs2KbdWait)
2291 xchg al, ah
2292
2293 ret
2294ENDPROC TMPL_NM_CMN(Bs2KbdWrite)
2295
2296
2297;;
2298; Enables the A20 gate via the keyboard controller.
2299;
2300; @uses Nothing.
2301;
2302BEGINPROC TMPL_NM_CMN(Bs2EnableA20ViaKbd)
2303 push xAX
2304 pushf
2305 cli
2306
2307 call TMPL_NM_CMN(Bs2KbdWait)
2308 mov al, 0d0h ; KBD_CCMD_READ_OUTPORT
2309 call TMPL_NM_CMN(Bs2KbdRead)
2310
2311 mov ah, 002h
2312 or ah, al
2313 mov al, 0d1h ; KBD_CCMD_WRITE_OUTPORT
2314 call TMPL_NM_CMN(Bs2KbdWrite)
2315
2316 mov al, 0ffh ; KBD_CMD_RESET
2317 out 64h, al
2318 call TMPL_NM_CMN(Bs2KbdWait)
2319
2320 popf
2321 pop xAX
2322 ret
2323ENDPROC TMPL_NM_CMN(Bs2EnableA20ViaKbd)
2324
2325
2326;;
2327; Disables the A20 gate via the keyboard controller.
2328;
2329; @uses Nothing.
2330;
2331BEGINPROC TMPL_NM_CMN(Bs2DisableA20ViaKbd)
2332 push xAX
2333 pushf
2334 cli
2335
2336 call TMPL_NM_CMN(Bs2KbdWait)
2337 mov al, 0d0h ; KBD_CCMD_READ_OUTPORT
2338 call TMPL_NM_CMN(Bs2KbdRead)
2339
2340 mov ah, 0fdh ; ~2
2341 and ah, al
2342 mov al, 0d1h ; KBD_CCMD_WRITE_OUTPORT
2343 call TMPL_NM_CMN(Bs2KbdWrite)
2344
2345 mov al, 0ffh ; KBD_CMD_RESET
2346 out 64h, al
2347 call TMPL_NM_CMN(Bs2KbdWait)
2348
2349 popf
2350 pop xAX
2351 ret
2352ENDPROC TMPL_NM_CMN(Bs2DisableA20ViaKbd)
2353
2354
2355;;
2356; Enables the A20 gate via control port A (PS/2 style).
2357;
2358; @uses Nothing.
2359;
2360BEGINPROC TMPL_NM_CMN(Bs2EnableA20ViaPortA)
2361 push xAX
2362
2363 ; Use Control port A, assuming a PS/2 style system.
2364 in al, 092h
2365 test al, 02h
2366 jnz .done ; avoid trouble writing back the same value.
2367 or al, 2 ; enable the A20 gate.
2368 out 092h, al
2369
2370.done:
2371 pop xAX
2372 ret
2373ENDPROC TMPL_NM_CMN(Bs2EnableA20ViaPortA)
2374
2375
2376;;
2377; Disables the A20 gate via control port A (PS/2 style).
2378;
2379; @uses Nothing.
2380;
2381BEGINPROC TMPL_NM_CMN(Bs2DisableA20ViaPortA)
2382 push xAX
2383
2384 ; Use Control port A, assuming a PS/2 style system.
2385 in al, 092h
2386 test al, 02h
2387 jz .done ; avoid trouble writing back the same value.
2388 and al, 0fdh ; disable the A20 gate.
2389 out 092h, al
2390
2391.done:
2392 pop xAX
2393 ret
2394ENDPROC TMPL_NM_CMN(Bs2DisableA20ViaPortA)
2395
2396
2397;;
2398; Checks if the no-execution bit is supported.
2399;
2400; @returns AL=1 and ZF=0 if supported.
2401; @returns AL=0 and ZF=1 if not.
2402; @uses al
2403;
2404BEGINPROC TMPL_NM_CMN(Bs2IsNXSupported)
2405 push xBP
2406 mov xBP, xSP
2407 push sBX
2408 push sDX
2409 push sCX
2410 push sAX
2411
2412 mov eax, 080000000h
2413 cpuid
2414 cmp eax, 080000001h
2415 jb .not_supported
2416 cmp eax, 080001000h
2417 jae .not_supported
2418
2419 mov eax, 080000001h
2420 cpuid
2421 test edx, X86_CPUID_EXT_FEATURE_EDX_NX
2422 jz .not_supported
2423
2424 ; supported
2425 pop sAX
2426 mov al, 1
2427
2428.return:
2429 pop sCX
2430 pop sDX
2431 pop sBX
2432 leave
2433 ret
2434.not_supported:
2435 pop sAX
2436 xor al, al
2437 jmp .return
2438ENDPROC TMPL_NM_CMN(Bs2IsNXSupported)
2439
2440
2441;;
2442; Sets EFER.NXE=al if NXE is supported.
2443;
2444; @param al 0 if NXE should be disabled, non-zero if it should
2445; be enabled.
2446; @uses nothing.
2447;
2448BEGINPROC TMPL_NM_CMN(Bs2SetupNX)
2449 push xBP
2450 mov xBP, xSP
2451 push sAX
2452 push sDX
2453 push sCX
2454
2455 call TMPL_NM_CMN(Bs2IsNXSupported)
2456 jz .done
2457
2458 mov ecx, MSR_K6_EFER
2459 rdmsr
2460 test byte [xBP - sCB], 0ffh
2461 jz .disable_it
2462 or eax, MSR_K6_EFER_NXE
2463 jmp .set_it
2464.disable_it:
2465 and eax, ~MSR_K6_EFER_NXE
2466.set_it:
2467 wrmsr
2468
2469.done:
2470 pop sCX
2471 pop sDX
2472 pop sAX
2473 leave
2474 ret
2475ENDPROC TMPL_NM_CMN(Bs2SetupNX)
2476
2477
2478;;
2479; Disables NX if supported.
2480;
2481; @uses nothing.
2482;
2483BEGINPROC TMPL_NM_CMN(Bs2DisableNX)
2484 push xBP
2485 mov xBP, xSP
2486 push xAX
2487
2488 xor al, al
2489 call TMPL_NM_CMN(Bs2SetupNX)
2490
2491 pop xAX
2492 leave
2493 ret
2494ENDPROC TMPL_NM_CMN(Bs2DisableNX)
2495
2496
2497;;
2498; Enables NX if supported.
2499;
2500; @uses nothing.
2501;
2502BEGINPROC TMPL_NM_CMN(Bs2EnableNX)
2503 push xBP
2504 mov xBP, xSP
2505 push xAX
2506
2507 mov al, 1
2508 call TMPL_NM_CMN(Bs2SetupNX)
2509
2510 pop xAX
2511 leave
2512 ret
2513ENDPROC TMPL_NM_CMN(Bs2EnableNX)
2514
2515
2516;;
2517; Panics if the testing feature of the VMMDev is missing.
2518;
2519; A message will be printed.
2520;
2521; @uses Nothing.
2522;
2523BEGINPROC TMPL_NM_CMN(Bs2PanicIfVMMDevTestingIsMissing)
2524 push xDX
2525 push sAX
2526
2527 xor eax, eax
2528 mov dx, VMMDEV_TESTING_IOPORT_NOP
2529 in eax, dx
2530 cmp eax, VMMDEV_TESTING_NOP_RET
2531 je .ok
2532
2533 mov xAX, .s_szMissingVMMDevTesting
2534 call TMPL_NM_CMN(PrintStr)
2535 call Bs2Panic
2536
2537.ok:
2538 pop sAX
2539 pop xDX
2540 ret
2541
2542.s_szMissingVMMDevTesting:
2543 db 'fatal error: The testing feature of the VMMDevVMMDev is not present!', 13, 10, 0
2544ENDPROC TMPL_NM_CMN(Bs2PanicIfVMMDevTestingIsMissing)
2545
2546
2547
2548%ifdef BS2_WITH_TRAPS
2549
2550;;
2551; Switches to ring-0 from whatever the current mode is.
2552;
2553; @uses cs, ss, ds, es, fs, gs
2554;
2555BEGINPROC TMPL_NM_CMN(Bs2ToRing0)
2556 push sAX
2557 mov sAX, BS2_SYSCALL_TO_RING0
2558 int BS2_TRAP_SYSCALL
2559 pop sAX
2560 ret
2561ENDPROC TMPL_NM_CMN(Bs2ToRing0)
2562
2563;;
2564; Switches to ring-1 from whatever the current mode is.
2565;
2566; @uses cs, ss, ds, es, fs, gs
2567;
2568BEGINPROC TMPL_NM_CMN(Bs2ToRing1)
2569 push sAX
2570 mov sAX, BS2_SYSCALL_TO_RING1
2571 int BS2_TRAP_SYSCALL
2572 pop sAX
2573 ret
2574ENDPROC TMPL_NM_CMN(Bs2ToRing1)
2575
2576;;
2577; Switches to ring-0 from whatever the current mode is.
2578;
2579; @uses cs, ss, ds, es, fs, gs
2580;
2581BEGINPROC TMPL_NM_CMN(Bs2ToRing2)
2582 push sAX
2583 mov sAX, BS2_SYSCALL_TO_RING2
2584 int BS2_TRAP_SYSCALL
2585 pop sAX
2586 ret
2587ENDPROC TMPL_NM_CMN(Bs2ToRing2)
2588
2589;;
2590; Switches to ring-3 from whatever the current mode is.
2591;
2592; @uses cs, ss, ds, es, fs, gs
2593;
2594BEGINPROC TMPL_NM_CMN(Bs2ToRing3)
2595 push sAX
2596 mov sAX, BS2_SYSCALL_TO_RING3
2597 int BS2_TRAP_SYSCALL
2598 pop sAX
2599 ret
2600ENDPROC TMPL_NM_CMN(Bs2ToRing3)
2601
2602;;
2603; Switches the given ring from whatever the current mode is.
2604;
2605; @param AL The desired ring.
2606; @uses cs, ss, ds, es, fs, gs
2607;
2608BEGINPROC TMPL_NM_CMN(Bs2ToRingN)
2609 pushf
2610 cmp al, 3
2611 je .ring3
2612 cmp al, 2
2613 je .ring2
2614 cmp al, 1
2615 je .ring1
2616.ring0:
2617 call TMPL_NM_CMN(Bs2ToRing0)
2618.done:
2619 popf
2620 ret
2621
2622.ring1:
2623 call TMPL_NM_CMN(Bs2ToRing1)
2624 jmp .done
2625.ring2:
2626 call TMPL_NM_CMN(Bs2ToRing2)
2627 jmp .done
2628.ring3:
2629 call TMPL_NM_CMN(Bs2ToRing3)
2630 jmp .done
2631ENDPROC TMPL_NM_CMN(Bs2ToRingN)
2632
2633%endif ; BS2_WITH_TRAPS
2634
2635
2636
2637;
2638; Wrapper for dynamically calling the right specific method.
2639; This avoid putting large portions of the code in the 2nd template.
2640;
2641
2642TMPL_NM_CMN(g_pfnPrintStrInternal): TMPL_PTR_DEF 0
2643TMPL_NM_CMN(g_pfnPrintChrInternal): TMPL_PTR_DEF 0
2644
2645BEGINPROC TMPL_NM_CMN(PrintStr)
2646 jmp [TMPL_NM_CMN(g_pfnPrintStrInternal)]
2647ENDPROC TMPL_NM_CMN(PrintStr)
2648
2649BEGINPROC TMPL_NM_CMN(PrintChr)
2650 jmp [TMPL_NM_CMN(g_pfnPrintChrInternal)]
2651ENDPROC TMPL_NM_CMN(PrintChr)
2652
2653
2654%include "bootsector2-template-footer.mac"
2655
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette