VirtualBox

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

Last change on this file since 92892 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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