VirtualBox

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

Last change on this file since 65145 was 62484, checked in by vboxsync, 8 years ago

(C) 2016

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