VirtualBox

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

Last change on this file since 52776 was 52776, checked in by vboxsync, 10 years ago

fix OSE

  • 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 52776 2014-09-17 14:51:43Z vboxsync $
2;; @file
3; bootsector2 common routines - template containing code common to related modes.
4;
5
6;
7; Copyright (C) 2007-2014 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 div ecx ; eax = NS per test
1194
1195 ; Calc tests per second.
1196 mov ecx, eax
1197 cmp ecx, 0
1198 jz .div_zero
1199 xor edx, edx
1200 mov eax, 1000000000 ; 1G
1201 div ecx ; eax = tests per second
1202
1203.done:
1204 pop sCX
1205 pop sDX
1206 leave
1207 ret
1208
1209.div_zero:
1210 mov eax, 0
1211 jmp .done
1212
1213.div_overflow:
1214 mov eax, 4242424242
1215 jmp .done
1216ENDPROC TMPL_NM_CMN(CalcTestPerSecond)
1217
1218
1219;;
1220; Calculate the number of iterations for a benchmark based on the time a short
1221; calibration run too.
1222;
1223; @param ds:xAX Pointer to the elapsed time.
1224; @param edx The number of tests iterations executed.
1225; @param ecx The desired test length, in seconds.
1226; @returns The tests iterations in eax.
1227;
1228; @uses eax (return value)
1229;
1230BEGINPROC TMPL_NM_CMN(CalcBenchmarkIterations)
1231 push xBP
1232 mov xBP, xSP
1233 push sDX
1234 push sCX
1235%ifdef TMPL_16BIT
1236 movzx eax, ax
1237%endif
1238
1239 ; Calc NS per test.
1240 mov ecx, edx
1241 cmp ecx, 0
1242 jz .div_zero
1243 movzx eax, ax
1244 mov edx, [sAX + 4]
1245 cmp edx, ecx
1246 jae .div_overflow
1247 mov eax, [sAX]
1248 div ecx ; eax = NS per test
1249
1250 ; Calc tests per second.
1251 mov ecx, eax
1252 cmp ecx, 0
1253 jz .div_zero
1254 xor edx, edx
1255 mov eax, 1000000000 ; 1G
1256 div ecx ; eax = tests per second
1257
1258 ; Multiply this up to the desired number of seconds.
1259 mov edx, [xBP - xCB*2]
1260 mul edx
1261 test edx, edx
1262 jnz .mult_32bit_overflow
1263 cmp eax, _64K
1264 jle .too_small
1265
1266.done:
1267 pop sCX
1268 pop sDX
1269 leave
1270 ret
1271
1272.too_small:
1273 mov eax, _64K
1274 jmp .done
1275
1276.mult_32bit_overflow:
1277 mov eax, 0ffff0000h
1278 jmp .done
1279
1280.div_zero:
1281 mov eax, [xBP - xCB]
1282 shl eax, 8
1283 jmp .fudge
1284
1285.div_overflow:
1286 mov eax, [xBP - xCB]
1287 shr eax, 4
1288.fudge:
1289 add eax, 10
1290 jmp .done
1291ENDPROC TMPL_NM_CMN(CalcBenchmarkIterations)
1292
1293
1294;;
1295; Prints a string on the screen.
1296;
1297; @param ds:ax The string to find the length of.
1298; @returns The string length in ax.
1299;
1300; @uses ax (return value)
1301;
1302BEGINPROC TMPL_NM_CMN(StrLen)
1303 push xBP
1304 mov xBP, xSP
1305 push xBX
1306
1307 mov xBX, xAX
1308 dec xBX
1309.next:
1310 inc xBX
1311 cmp byte [xBX], byte 0
1312 jnz .next
1313
1314 xchg xAX, xBX
1315 sub xAX, xBX
1316
1317 pop xBX
1318 leave
1319 ret
1320ENDPROC TMPL_NM_CMN(StrLen)
1321
1322
1323
1324;;
1325; Simple string format, taking an argument list.
1326;
1327; Implemented:
1328; - %RX8
1329; - %RX16
1330; - %RX32
1331; - %RX64
1332; - %s
1333;
1334; Planned:
1335; - %RU8
1336; - %RU16
1337; - %RU32
1338; - %RU64
1339; - %RI8
1340; - %RI16
1341; - %RI32
1342; - %RI64
1343;
1344; @param ds:xAX The buffer address.
1345; @param xDX The buffer size.
1346; @param es:xCX The format string.
1347; @param fs:xBX The argument list.
1348; @uses nothing
1349;
1350BEGINPROC TMPL_NM_CMN(StrFormatV)
1351 push xBP
1352 mov xBP, xSP
1353 push sAX
1354 push sDX
1355 push sCX
1356 push sBX
1357 push sDI
1358 push sSI
1359 pushf
1360 cld
1361%ifdef TMPL_16BIT
1362 push ds
1363 push es
1364 push fs
1365 push gs
1366
1367 mov si, ds
1368 mov di, es
1369 mov ds, di
1370 mov es, si
1371 mov di, ax ; es:di -> output buffer.
1372 mov si, cx ; ds:si -> format string.
1373%define a_pArgs [fs:bx]
1374%define a_pu32ArgsHighDW dword [fs:bx + 4]
1375%else
1376 mov xDI, xAX ; (es:)xDI -> output buffer.
1377 mov xSI, xCX ; (ds:)xSI -> format string.
1378%define a_pArgs [xBX]
1379%define a_pu32ArgsHighDW dword [xBX + 4]
1380%endif
1381 xchg xCX, xDX ; xCX=buffer size.
1382
1383 ;
1384 ; Make sure we've got space for a terminator char in the output buffer.
1385 ;
1386 test xCX, xCX
1387 jz .return
1388 dec xCX
1389 jz .done
1390
1391 ;
1392 ; In this loop we're free to use sDX and (with some caution) sAX.
1393 ;
1394.format_loop:
1395 lodsb
1396 test al, al
1397 jz .done
1398 cmp al, '%'
1399 je .switch
1400
1401 ; Emit the character in al if there is room for it.
1402.emit_al:
1403 test xCX, xCX
1404 jz .done
1405 stosb
1406 dec xCX
1407 jmp .format_loop
1408
1409 ; Try recognize the format specifier.
1410.switch:
1411 lodsb
1412 cmp al, 's'
1413 je .switch_case_string
1414 cmp al, 'c'
1415 je .switch_case_char
1416 cmp al, 'R'
1417 jne .switch_default
1418 lodsb
1419 cmp al, 'X'
1420 jne .switch_case_number
1421 cmp al, 'U'
1422 jne .switch_case_number
1423 cmp al, 'I'
1424 jne .switch_case_number
1425
1426.switch_default:
1427 test al, al
1428 jz .done
1429 mov al, '!'
1430 jmp .emit_al
1431
1432 ; parse the number part.
1433.switch_case_number:
1434 mov ah, al ; ah = {X,U,I}
1435 lodsb
1436 cmp al, '8'
1437 je .switch_case_number_8bit
1438 cmp al, '1'
1439 je .switch_case_number_16bit
1440 cmp al, '3'
1441 je .switch_case_number_32bit
1442 cmp al, '6'
1443 je .switch_case_number_64bit
1444 jmp .switch_default
1445
1446
1447 ;
1448 ; Common code for 8-bit, 16-bit and 32-bit.
1449 ;
1450 ; The first part load the value into edx, ah={X,U,I},
1451 ; al=(max-hex, max-unsigned-dec).
1452 ;
1453.switch_case_number_8bit:
1454 mov al, (2 << 4) | 2
1455 movzx edx, byte a_pArgs
1456 add xBX, xCB
1457 cmp ah, 'I'
1458 jne .switch_case_number_common_32bit_hex_or_unsigned
1459 movsx edx, dl
1460 jmp .switch_case_number_common_32bit_signed
1461
1462.switch_case_number_16bit:
1463 lodsb
1464 cmp al, '6'
1465 jne .switch_default
1466 mov al, (4 << 4) | 5
1467 movzx edx, word a_pArgs
1468 add xBX, xCB
1469 cmp ah, 'I'
1470 jne .switch_case_number_common_32bit_hex_or_unsigned
1471 movsx edx, dx
1472 jmp .switch_case_number_common_32bit_signed
1473
1474.switch_case_number_32bit:
1475 lodsb
1476 cmp al, '2'
1477 jne .switch_default
1478 mov al, (8 << 4) | 10
1479 mov edx, dword a_pArgs
1480 add xBX, sCB
1481 cmp ah, 'I'
1482 je .switch_case_number_common_32bit_signed
1483
1484.switch_case_number_common_32bit_hex_or_unsigned:
1485 cmp ah, 'X'
1486 jne .switch_case_number_common_32bit_unsigned
1487 shr al, 4
1488 and xAX, 0fh
1489 cmp xCX, xAX
1490 jb .switch_case_number_bad_buf
1491 call .format_32bit_hex_subroutine
1492 jmp .format_loop
1493
1494.switch_case_number_common_32bit_unsigned:
1495 and xAX, 0fh
1496 cmp xCX, xAX
1497 jb .switch_case_number_bad_buf
1498 call .format_32bit_dec_subroutine
1499 jmp .format_loop
1500
1501.switch_case_number_common_32bit_signed:
1502 cmp edx, 0
1503 jge .switch_case_number_common_32bit_unsigned
1504 and xAX, 0fh
1505 inc xAX ; sign char
1506 cmp xCX, xAX
1507 jb .switch_case_number_bad_buf
1508 ; Emit the minus sign, invert the value and join the unsigned formatting.
1509 push xAX
1510 mov al, '-'
1511 stosb
1512 dec xCX
1513 pop xAX
1514 neg edx
1515 call .format_32bit_dec_subroutine
1516 jmp .format_loop
1517
1518
1519 ;
1520 ; 64-bit is special, to simplify we treat all formats as hex...
1521 ;
1522.switch_case_number_64bit:
1523 lodsb
1524 cmp al, '4'
1525 jne .switch_default
1526 cmp ah, 'X'
1527 je .switch_case_number_64bit_hex
1528 cmp ah, 'I'
1529 je .switch_case_number_64bit_signed
1530 jmp .switch_case_number_64bit_unsigned
1531
1532.switch_case_number_64bit_hex:
1533 mov eax, dword a_pArgs
1534 mov edx, a_pu32ArgsHighDW
1535 add xBX, 8
1536 cmp xCX, 8+1+8
1537 jb .switch_case_number_bad_buf
1538 ; Simple, format it as two 32-bit hex values.
1539 push sAX
1540 mov eax, 8
1541 call .format_32bit_hex_subroutine
1542 mov al, 27h ; '\'' - how do we escape this with yasm?
1543 stosb
1544 dec xCX
1545 pop sDX
1546 mov eax, 8
1547 call .format_32bit_hex_subroutine
1548 jmp .format_loop
1549
1550.switch_case_number_64bit_unsigned:
1551 cmp xCX, 19
1552 jb .switch_case_number_bad_buf
1553.switch_case_number_64bit_unsigned_format_it:
1554 ;; @todo implement me
1555 jmp .switch_case_number_64bit_hex
1556
1557.switch_case_number_64bit_signed:
1558 mov eax, dword a_pArgs
1559 mov edx, a_pu32ArgsHighDW
1560 add xBX, 8
1561 cmp xCX, 20
1562 jb .switch_case_number_bad_buf
1563 test edx, 080000000h
1564 jz .switch_case_number_64bit_unsigned_format_it
1565 ; Emit the minus sign, invert the value and join the unsigned formatting.
1566 push xAX
1567 mov al, '-'
1568 stosb
1569 dec xCX
1570 pop xAX
1571 neg eax
1572 neg edx
1573 jmp .switch_case_number_64bit_unsigned_format_it
1574
1575
1576 ; The remaining buffer is too small to hold the number.
1577.switch_case_number_bad_buf:
1578 mov al, '^'
1579 jmp .emit_al
1580
1581
1582 ;
1583 ; Emit a string.
1584 ;
1585.switch_case_string:
1586%ifdef TMPL_16BIT
1587 lgs dx, a_pArgs
1588 add xBX, 4
1589%else
1590 mov xDX, a_pArgs
1591 add xBX, xCB
1592%endif
1593 test xCX, xCX
1594.switch_case_string_loop:
1595 jz .done
1596%ifdef TMPL_16BIT
1597 mov al, [gs:edx]
1598%else
1599 mov al, [xDX]
1600%endif
1601 test al, al
1602 jz .format_loop
1603 inc xDX
1604 stosb
1605 dec xCX
1606 jmp .switch_case_string_loop
1607
1608 ;
1609 ; Emit a char.
1610 ;
1611.switch_case_char:
1612 mov al, byte a_pArgs
1613 add xBX, xCB
1614 jmp .emit_al
1615
1616
1617 ;
1618 ; Done, just emit the terminator char.
1619 ;
1620.done:
1621 xor al, al
1622 stosb
1623
1624.return:
1625%ifdef TMPL_16BIT
1626 pop gs
1627 pop fs
1628 pop es
1629 pop ds
1630%endif
1631 popf
1632 pop sSI
1633 pop sDI
1634 pop sBX
1635 pop sCX
1636 pop sDX
1637 pop sAX
1638 leave
1639 ret
1640%undef a_pArgs
1641%undef a_pu32ArgsHighDW
1642
1643;;
1644; Internal subroutine for formatting a hex number into the buffer.
1645; @param al The precision (2, 4, 8).
1646; @param edx The value.
1647;
1648; @uses ecx, edi
1649;
1650.format_32bit_hex_subroutine:
1651 push xAX
1652 push sDX
1653 push xBX
1654
1655 ; Rotate edx into position.
1656 mov ebx, 8
1657 sub bl, al
1658 shl bl, 2
1659 xchg cl, bl
1660 rol edx, cl
1661 xchg bl, cl
1662
1663 mov bl, al ; Width counter
1664.format_32bit_hex_subroutine_next:
1665 rol edx, 4
1666 mov eax, edx
1667 and eax, 0fh
1668 add sAX, g_achHex
1669 mov al, [cs:sAX]
1670 stosb
1671 dec xCX
1672 dec bl
1673 jnz .format_32bit_hex_subroutine_next
1674
1675 pop xBX
1676 pop sDX
1677 pop xAX
1678 ret
1679
1680
1681;;
1682; Internal subroutine for formatting a hex number into the buffer.
1683; @param al The max precision (2, 5, 10).
1684; @param edx The value.
1685; @param xCX Counter register to decrement as characters are emited.
1686; @param es:xDI Where to write the output, xDI is updated.
1687;
1688; @uses xCX, xDI
1689;
1690.format_32bit_dec_subroutine:
1691%if 0 ;; @todo implement this
1692 sub xSP, 20h
1693 ; Format in reverse order into a stack buffer.
1694
1695 ; Append the stack buffer to the string, reversing it in the process.
1696
1697 add xSP, 20h
1698%else
1699 call .format_32bit_hex_subroutine
1700%endif
1701 ret
1702
1703ENDPROC TMPL_NM_CMN(StrFormatV)
1704
1705
1706;;
1707; Very limited RTStrPrintf version.
1708;
1709; @remarks This uses an entirely STACK BASED CALLING CONVENTION where the
1710; caller does the cleanup (cdecl sans volatile regs).
1711;
1712; @param fpszBuf The output buffer.
1713; @param cbBuf The output buffer size (natural size).
1714; @param fpszFormat The format string (far pointer in 16-bit).
1715; See StrFormatV for format.
1716; @param ... Zero or more format string arguments.
1717; @uses nothing
1718;
1719BEGINPROC TMPL_NM_CMN(StrFormatF)
1720 push xBP
1721 mov xBP, xSP
1722 push xAX
1723 push xDX
1724 push xCX
1725 push xBX
1726%ifdef TMPL_16BIT
1727 push ds
1728 push es
1729 push fs
1730
1731 lds xAX, [bp + 04h]
1732 mov dx, [bp + 08h]
1733 les xCX, [bp + 0ah]
1734 mov bx, ss
1735 mov fs, bx
1736 mov bx, bp
1737 add bx, 0eh
1738%else
1739 mov xAX, [xBP + xCB * 2]
1740 mov xDX, [xBP + xCB * 3]
1741 mov xCX, [xBP + xCB * 4]
1742 lea xBX, [xBP + xCB * 5]
1743%endif
1744 call TMPL_NM_CMN(StrFormatV)
1745
1746%ifdef TMPL_16BIT
1747 pop fs
1748 pop es
1749 pop ds
1750%endif
1751 pop xBX
1752 pop xCX
1753 pop xDX
1754 pop xAX
1755 leave
1756 ret
1757ENDPROC TMPL_NM_CMN(StrFormatF)
1758
1759
1760;;
1761; Dumps the CPU registers.
1762;
1763; @uses Nothing.
1764;
1765BEGINPROC TMPL_NM_CMN(TestDumpCurrentRegisters)
1766%ifndef TMPL_64BIT
1767 push xBP
1768 mov xBP, xSP
1769 push eax
1770 pushfd
1771
1772 push dword [xBP - sCB - 4] ; eflags
1773 mov eax, cr2
1774 push eax
1775 xor eax, eax
1776 mov eax, gs
1777 push eax
1778 mov eax, fs
1779 push eax
1780 mov eax, es
1781 push eax
1782 mov eax, ds
1783 push eax
1784 mov eax, cs
1785 push eax
1786
1787 mov eax, cr4
1788 push eax
1789 mov eax, cr3
1790 push eax
1791 mov eax, cr0
1792 push eax
1793 mov eax, ebp ; return EBP
1794 mov xAX, [xBP]
1795 push eax
1796
1797 mov eax, ebp ; return ESP
1798 add xAX, xCB
1799 push eax
1800
1801 mov xAX, [xBP + xCB] ; return EIP
1802 %ifdef TMPL_16BIT
1803 movzx eax, ax
1804 %endif
1805 push eax
1806
1807 push edi
1808 push esi
1809 push edx
1810 push ecx
1811 push ebx
1812 push dword [xBP - sCB] ; eax
1813
1814 %ifdef TMPL_16BIT
1815 push cs
1816 %endif
1817 push .s_szRegFmt
1818 call TMPL_NM_CMN(PrintF)
1819
1820 popfd
1821 pop eax
1822 leave
1823 ret
1824
1825.s_szRegFmt:
1826 db 'eax=%RX32 ebx=%RX32 ecx=%RX32 edx=%RX32 esi=%RX32 edi=%RX32', 13, 10
1827 db 'eip=%RX32 esp=%RX32 ebp=%RX32 cr0=%RX32 cr3=%RX32 cr4=%RX32', 13, 10
1828 db 'cs=%RX16 ds=%RX16 es=%RX16 fs=%RX16 gs=%RX16 ss=%RX16 cr2=%RX32 eflags=%RX32', 13, 10, 0
1829
1830%else ; 64-bit
1831 push .s_szRegFmt
1832 call TMPL_NM_CMN(PrintF)
1833 ret
1834
1835.s_szRegFmt:
1836 db 'TestDumpCurrentRegisters not implemented', 13, 10, 0
1837
1838%endif ; 64-bit
1839ENDPROC TMPL_NM_CMN(TestDumpCurrentRegisters)
1840
1841
1842
1843;;
1844; Dumps the CPU registers.
1845;
1846; @param ds:xAX Pointer to the register frame to dump.
1847; @uses Nothing.
1848;
1849BEGINPROC TMPL_NM_CMN(TestDumpRegisters)
1850 push xBP
1851 mov xBP, xSP
1852 pushf
1853 push sDX
1854 push sBX
1855 mov xBX, xAX
1856
1857 cmp byte [xBX + BS2REGS.cBits], 64
1858 je .dump_64bit_regs
1859
1860 push -1 ; sanity
1861 mov edx, [xBX + BS2REGS.rflags]
1862 push sDX
1863 mov edx, [xBX + BS2REGS.cr2]
1864 push sDX
1865 xor edx, edx
1866 mov dx, [xBX + BS2REGS.ss]
1867 push xDX
1868 mov dx, [xBX + BS2REGS.gs]
1869 push xDX
1870 mov dx, [xBX + BS2REGS.fs]
1871 push xDX
1872 mov dx, [xBX + BS2REGS.es]
1873 push xDX
1874 mov dx, [xBX + BS2REGS.ds]
1875 push xDX
1876 mov dx, [xBX + BS2REGS.cs]
1877 push xDX
1878
1879 mov edx, [xBX + BS2REGS.cr4]
1880 push sDX
1881 mov edx, [xBX + BS2REGS.cr3]
1882 push sDX
1883 mov edx, [xBX + BS2REGS.cr0]
1884 push sDX
1885 mov edx, [xBX + BS2REGS.rbp]
1886 push sDX
1887 mov edx, [xBX + BS2REGS.rsp]
1888 push sDX
1889 mov edx, [xBX + BS2REGS.rip]
1890 push sDX
1891
1892 mov edx, [xBX + BS2REGS.rdi]
1893 push sDX
1894 mov edx, [xBX + BS2REGS.rsi]
1895 push sDX
1896 mov edx, [xBX + BS2REGS.rdx]
1897 push sDX
1898 mov edx, [xBX + BS2REGS.rcx]
1899 push sDX
1900 mov edx, [xBX + BS2REGS.rbx]
1901 push sDX
1902 mov edx, [xBX + BS2REGS.rax]
1903 push sDX
1904
1905%ifdef TMPL_16BIT
1906 push cs
1907%endif
1908 push .s_szReg32Fmt
1909 call TMPL_NM_CMN(PrintF)
1910 jmp .return
1911
1912.dump_64bit_regs:
1913%ifdef TMPL_16BIT
1914 push cs
1915%endif
1916 push .s_szReg64Fmt
1917 call TMPL_NM_CMN(PrintF)
1918
1919.return:
1920 lea xSP, [xBP - sCB*2 - xCB]
1921 pop sBX
1922 pop sDX
1923 popf
1924 leave
1925 ret
1926
1927.s_szReg32Fmt:
1928 db 'eax=%RX32 ebx=%RX32 ecx=%RX32 edx=%RX32 esi=%RX32 edi=%RX32', 13, 10
1929 db 'eip=%RX32 esp=%RX32 ebp=%RX32 cr0=%RX32 cr3=%RX32 cr4=%RX32', 13, 10
1930 db 'cs=%RX16 ds=%RX16 es=%RX16 fs=%RX16 gs=%RX16 ss=%RX16 cr2=%RX32 eflags=%RX32', 13, 10
1931 db 0
1932
1933.s_szReg64Fmt:
1934 db 'TestDumpCurrentRegisters not implemented', 13, 10, 0
1935ENDPROC TMPL_NM_CMN(TestDumpRegisters)
1936
1937
1938;;
1939; Saves the CPU registers.
1940;
1941; @param ds:xAX Pointer to the register frame to dump.
1942; @uses Nothing.
1943;
1944BEGINPROC TMPL_NM_CMN(TestSaveRegisters)
1945 push xBP
1946 mov xBP, xSP
1947%ifdef TMPL_16BIT
1948 pushfd
1949%else
1950 pushf ; - 1*sCB
1951%endif
1952 push sBX ; - 2*sCB
1953 push sAX ; - 3*sCB
1954 push sDX ; - 4*sCB
1955
1956 xor edx, edx ; zero register.
1957 mov xBX, xAX ; xBX for addressing, xAX for scratch.
1958
1959%ifdef TMPL_64BIT
1960 mov rax, [xSP + sCB*1]
1961 mov [xBX + BS2REGS.rax], rax
1962 mov rax, [xSP + sCB*2]
1963 mov [xBX + BS2REGS.rbx], rax
1964 mov [xBX + BS2REGS.rcx], rcx
1965 mov rax, [xSP]
1966 mov [xBX + BS2REGS.rdx], rax
1967 mov [xBX + BS2REGS.rdi], rdi
1968 mov [xBX + BS2REGS.rsi], rsi
1969 mov rax, [xBP]
1970 mov [xBX + BS2REGS.rbp], rax
1971 lea rax, [xBP + 16]
1972 mov [xBX + BS2REGS.rsp], rax
1973 mov rax, [xBP + 8]
1974 mov [xBX + BS2REGS.rip], rax
1975 mov [xBX + BS2REGS.r8], r8
1976 mov [xBX + BS2REGS.r9], r9
1977 mov [xBX + BS2REGS.r10], r10
1978 mov [xBX + BS2REGS.r11], r11
1979 mov [xBX + BS2REGS.r12], r12
1980 mov [xBX + BS2REGS.r13], r13
1981 mov [xBX + BS2REGS.r14], r14
1982 mov [xBX + BS2REGS.r15], r15
1983 mov rax, [xBP - sCB]
1984 mov [xBX + BS2REGS.rflags], rax
1985 mov ax, cs
1986 mov [xBX + BS2REGS.cs], ax
1987 mov ax, ds
1988 mov [xBX + BS2REGS.ds], ax
1989 mov ax, es
1990 mov [xBX + BS2REGS.es], ax
1991 mov ax, fs
1992 mov [xBX + BS2REGS.fs], ax
1993 mov ax, gs
1994 mov [xBX + BS2REGS.gs], ax
1995 mov ax, ss
1996 mov [xBX + BS2REGS.ss], ax
1997 mov byte [xBX + BS2REGS.cBits], 64
1998 mov [xBX + BS2REGS.pad ], dl
1999 mov [xBX + BS2REGS.pad + 1], dx
2000 mov rax, cr0
2001 mov [xBX + BS2REGS.cr0], rax
2002 mov rax, cr2
2003 mov [xBX + BS2REGS.cr2], rax
2004 mov rax, cr3
2005 mov [xBX + BS2REGS.cr3], rax
2006 mov rax, cr4
2007 mov [xBX + BS2REGS.cr4], rax
2008 mov rax, cr8
2009 mov [xBX + BS2REGS.cr8], rax
2010%else ; !TMPL_64
2011 mov eax, [xBP - sCB*3]
2012 mov dword [xBX + BS2REGS.rax], eax
2013 mov dword [xBX + BS2REGS.rax + 4], edx
2014 mov eax, [xBP - sCB*2]
2015 mov dword [xBX + BS2REGS.rbx], eax
2016 mov dword [xBX + BS2REGS.rbx + 4], edx
2017 mov dword [xBX + BS2REGS.rcx], ecx
2018 mov dword [xBX + BS2REGS.rcx + 4], edx
2019 mov eax, [xBP - sCB*4]
2020 mov dword [xBX + BS2REGS.rdx], eax
2021 mov dword [xBX + BS2REGS.rdx + 4], edx
2022 mov dword [xBX + BS2REGS.rdi], edi
2023 mov dword [xBX + BS2REGS.rdi + 4], edx
2024 mov dword [xBX + BS2REGS.rsi], esi
2025 mov dword [xBX + BS2REGS.rsi + 4], edx
2026 mov eax, ebp
2027 mov ax, [xBP]
2028 mov dword [xBX + BS2REGS.rbp], eax
2029 mov dword [xBX + BS2REGS.rbp + 4], edx
2030 %ifdef TMPL_16BIT
2031 mov eax, esp
2032 mov ax, bp
2033 sub ax, 4
2034 %else
2035 lea eax, [ebp + 8]
2036 %endif
2037 mov dword [xBX + BS2REGS.rsp], eax
2038 mov dword [xBX + BS2REGS.rsp + 4], edx
2039 %ifdef TMPL_16BIT
2040 movzx eax, word [xBP + 2]
2041 %else
2042 mov eax, [xBP + 4]
2043 %endif
2044 mov dword [xBX + BS2REGS.rip], eax
2045 mov dword [xBX + BS2REGS.rip + 4], edx
2046 mov dword [xBX + BS2REGS.r8 ], edx
2047 mov dword [xBX + BS2REGS.r8 + 4], edx
2048 mov dword [xBX + BS2REGS.r9 ], edx
2049 mov dword [xBX + BS2REGS.r9 + 4], edx
2050 mov dword [xBX + BS2REGS.r10 ], edx
2051 mov dword [xBX + BS2REGS.r10 + 4], edx
2052 mov dword [xBX + BS2REGS.r11 ], edx
2053 mov dword [xBX + BS2REGS.r11 + 4], edx
2054 mov dword [xBX + BS2REGS.r12 ], edx
2055 mov dword [xBX + BS2REGS.r12 + 4], edx
2056 mov dword [xBX + BS2REGS.r13 ], edx
2057 mov dword [xBX + BS2REGS.r13 + 4], edx
2058 mov dword [xBX + BS2REGS.r14 ], edx
2059 mov dword [xBX + BS2REGS.r14 + 4], edx
2060 mov dword [xBX + BS2REGS.r15 ], edx
2061 mov dword [xBX + BS2REGS.r15 + 4], edx
2062 mov eax, [xBP - sCB]
2063 mov dword [xBX + BS2REGS.rflags], eax
2064 mov dword [xBX + BS2REGS.rflags + 4], edx
2065 mov ax, cs
2066 mov [xBX + BS2REGS.cs], ax
2067 mov ax, ds
2068 mov [xBX + BS2REGS.ds], ax
2069 mov ax, es
2070 mov [xBX + BS2REGS.es], ax
2071 mov ax, fs
2072 mov [xBX + BS2REGS.fs], ax
2073 mov ax, gs
2074 mov [xBX + BS2REGS.gs], ax
2075 mov ax, ss
2076 mov [xBX + BS2REGS.ss], ax
2077 %ifdef TMPL_16BIT
2078 mov byte [xBX + BS2REGS.cBits], 16
2079 %else
2080 mov byte [xBX + BS2REGS.cBits], 32
2081 %endif
2082 mov [xBX + BS2REGS.pad ], dl
2083 mov [xBX + BS2REGS.pad + 1], dx
2084 mov eax, cr0
2085 mov dword [xBX + BS2REGS.cr0], eax
2086 mov dword [xBX + BS2REGS.cr0 + 4], edx
2087 mov eax, cr2
2088 mov dword [xBX + BS2REGS.cr2], eax
2089 mov dword [xBX + BS2REGS.cr2 + 4], edx
2090 mov eax, cr3
2091 mov dword [xBX + BS2REGS.cr3], eax
2092 mov dword [xBX + BS2REGS.cr3 + 4], edx
2093 mov eax, cr4
2094 mov dword [xBX + BS2REGS.cr4], eax
2095 mov dword [xBX + BS2REGS.cr4 + 4], edx
2096 mov dword [xBX + BS2REGS.cr8], edx
2097 mov dword [xBX + BS2REGS.cr8 + 4], edx
2098%endif ; !TMPL_64
2099
2100.return:
2101 pop sDX
2102 pop sAX
2103 pop sBX
2104%ifdef TMPL_16BIT
2105 popfd
2106%else
2107 popf
2108%endif
2109 leave
2110 ret
2111ENDPROC TMPL_NM_CMN(TestSaveRegisters)
2112
2113
2114;;
2115; Restores the CPU registers, except for rsp, rip, cs, ss and ds.
2116;
2117; @param ds:xAX Pointer to the register frame to dump.
2118; @uses All, but RSP, RIP, CS, SS and DS.
2119;
2120BEGINPROC TMPL_NM_CMN(TestRestoreRegisters)
2121 push xBP
2122 mov xBP, xSP
2123%ifdef TMPL_16BIT
2124 pushfd
2125%else
2126 pushf ; - 1*sCB
2127%endif
2128 push sBX ; - 2*sCB
2129 push sAX ; - 3*sCB
2130
2131 mov xBX, xAX ; xBX for addressing, xAX for scratch.
2132
2133 mov sAX, [xBX + BS2REGS.rax]
2134 mov [xBP - 3*sCB], sAX
2135 mov sAX, [xBX + BS2REGS.rbx]
2136 mov [xBP - 2*sCB], sAX
2137 mov sCX, [xBX + BS2REGS.rcx]
2138 mov sDX, [xBX + BS2REGS.rdx]
2139 mov sDI, [xBX + BS2REGS.rdi]
2140 mov sSI, [xBX + BS2REGS.rsi]
2141 ; skip rsp, rbp or rip.
2142%ifdef TMPL_64BIT
2143 mov r8, [xBX + BS2REGS.r8]
2144 mov r9, [xBX + BS2REGS.r9]
2145 mov r10, [xBX + BS2REGS.r10]
2146 mov r11, [xBX + BS2REGS.r11]
2147 mov r12, [xBX + BS2REGS.r12]
2148 mov r13, [xBX + BS2REGS.r13]
2149 mov r14, [xBX + BS2REGS.r14]
2150 mov r15, [xBX + BS2REGS.r15]
2151%endif
2152 mov sAX, [xBX + BS2REGS.rflags]
2153 mov [xBP - sCB], sAX
2154 ; skip cs & ds.
2155 mov ax, [xBX + BS2REGS.es]
2156 mov es, ax
2157 mov ax, [xBX + BS2REGS.fs]
2158 mov fs, ax
2159 mov ax, [xBX + BS2REGS.gs]
2160 mov gs, ax
2161 ; skip ss
2162 mov sAX, [xBX + BS2REGS.cr0]
2163 mov cr0, sAX
2164 mov sAX, [xBX + BS2REGS.cr2]
2165 mov cr2, sAX
2166 mov sAX, [xBX + BS2REGS.cr3]
2167 mov cr3, sAX
2168 mov sAX, [xBX + BS2REGS.cr4]
2169 mov cr4, sAX
2170
2171.return:
2172 pop sAX
2173 pop sBX
2174%ifdef TMPL_16BIT
2175 popfd
2176%else
2177 popf
2178%endif
2179 leave
2180 ret
2181ENDPROC TMPL_NM_CMN(TestRestoreRegisters)
2182
2183
2184;;
2185; Enables the A20 gate.
2186;
2187; @uses Nothing.
2188;
2189BEGINPROC TMPL_NM_CMN(Bs2EnableA20)
2190 call TMPL_NM_CMN(Bs2EnableA20ViaPortA)
2191; call TMPL_NM_CMN(Bs2EnableA20ViaKbd)
2192 ret
2193ENDPROC TMPL_NM_CMN(Bs2EnableA20)
2194
2195
2196;;
2197; Disables the A20 gate.
2198;
2199; @uses Nothing.
2200;
2201BEGINPROC TMPL_NM_CMN(Bs2DisableA20)
2202 ; Must call both because they may be ORed together on real HW.
2203 call TMPL_NM_CMN(Bs2DisableA20ViaKbd)
2204 call TMPL_NM_CMN(Bs2DisableA20ViaPortA)
2205 ret
2206ENDPROC TMPL_NM_CMN(Bs2DisableA20)
2207
2208
2209;;
2210; Waits for the keyboard controller to become ready.
2211;
2212; @uses Nothing
2213;
2214BEGINPROC TMPL_NM_CMN(Bs2KbdWait)
2215 push xAX
2216
2217.check_status:
2218 in al, 64h
2219 test al, 1 ; KBD_STAT_OBF
2220 jnz .read_data_and_status
2221 test al, 2 ; KBD_STAT_IBF
2222 jnz .check_status
2223
2224 pop xAX
2225 ret
2226
2227.read_data_and_status:
2228 in al, 60h
2229 jmp .check_status
2230ENDPROC TMPL_NM_CMN(Bs2KbdWait)
2231
2232
2233;;
2234; Sends a read command to the keyboard controller and gets the result.
2235;
2236; The caller is responsible for making sure the keyboard controller is ready
2237; for a command (call Bs2KbdWait if unsure).
2238;
2239; @param al The read command.
2240; @returns The value read is returned.
2241; @uses al (obviously)
2242;
2243BEGINPROC TMPL_NM_CMN(Bs2KbdRead)
2244 out 64h, al ; Write the command.
2245
2246.check_status:
2247 in al, 64h
2248 test al, 1 ; KBD_STAT_OBF
2249 jz .check_status
2250
2251 in al, 60h ; Read the data.
2252 ret
2253ENDPROC TMPL_NM_CMN(Bs2KbdRead)
2254
2255
2256;;
2257; Sends a write command to the keyboard controller and then sends the data.
2258;
2259; The caller is responsible for making sure the keyboard controller is ready
2260; for a command (call Bs2KbdWait if unsure).
2261;
2262; @param al The write command.
2263; @param ah The data to write.
2264; @uses Nothing.
2265;
2266; @todo Return status?
2267;
2268BEGINPROC TMPL_NM_CMN(Bs2KbdWrite)
2269 out 64h, al ; Write the command.
2270 call TMPL_NM_CMN(Bs2KbdWait)
2271
2272 xchg al, ah
2273 out 60h, al ; Write the data.
2274 call TMPL_NM_CMN(Bs2KbdWait)
2275 xchg al, ah
2276
2277 ret
2278ENDPROC TMPL_NM_CMN(Bs2KbdWrite)
2279
2280
2281;;
2282; Enables the A20 gate via the keyboard controller.
2283;
2284; @uses Nothing.
2285;
2286BEGINPROC TMPL_NM_CMN(Bs2EnableA20ViaKbd)
2287 push xAX
2288 pushf
2289 cli
2290
2291 call TMPL_NM_CMN(Bs2KbdWait)
2292 mov al, 0d0h ; KBD_CCMD_READ_OUTPORT
2293 call TMPL_NM_CMN(Bs2KbdRead)
2294
2295 mov ah, 002h
2296 or ah, al
2297 mov al, 0d1h ; KBD_CCMD_WRITE_OUTPORT
2298 call TMPL_NM_CMN(Bs2KbdWrite)
2299
2300 mov al, 0ffh ; KBD_CMD_RESET
2301 out 64h, al
2302 call TMPL_NM_CMN(Bs2KbdWait)
2303
2304 popf
2305 pop xAX
2306 ret
2307ENDPROC TMPL_NM_CMN(Bs2EnableA20ViaKbd)
2308
2309
2310;;
2311; Disables the A20 gate via the keyboard controller.
2312;
2313; @uses Nothing.
2314;
2315BEGINPROC TMPL_NM_CMN(Bs2DisableA20ViaKbd)
2316 push xAX
2317 pushf
2318 cli
2319
2320 call TMPL_NM_CMN(Bs2KbdWait)
2321 mov al, 0d0h ; KBD_CCMD_READ_OUTPORT
2322 call TMPL_NM_CMN(Bs2KbdRead)
2323
2324 mov ah, 0fdh ; ~2
2325 and ah, al
2326 mov al, 0d1h ; KBD_CCMD_WRITE_OUTPORT
2327 call TMPL_NM_CMN(Bs2KbdWrite)
2328
2329 mov al, 0ffh ; KBD_CMD_RESET
2330 out 64h, al
2331 call TMPL_NM_CMN(Bs2KbdWait)
2332
2333 popf
2334 pop xAX
2335 ret
2336ENDPROC TMPL_NM_CMN(Bs2DisableA20ViaKbd)
2337
2338
2339;;
2340; Enables the A20 gate via control port A (PS/2 style).
2341;
2342; @uses Nothing.
2343;
2344BEGINPROC TMPL_NM_CMN(Bs2EnableA20ViaPortA)
2345 push xAX
2346
2347 ; Use Control port A, assuming a PS/2 style system.
2348 in al, 092h
2349 test al, 02h
2350 jnz .done ; avoid trouble writing back the same value.
2351 or al, 2 ; enable the A20 gate.
2352 out 092h, al
2353
2354.done:
2355 pop xAX
2356 ret
2357ENDPROC TMPL_NM_CMN(Bs2EnableA20ViaPortA)
2358
2359
2360;;
2361; Disables the A20 gate via control port A (PS/2 style).
2362;
2363; @uses Nothing.
2364;
2365BEGINPROC TMPL_NM_CMN(Bs2DisableA20ViaPortA)
2366 push xAX
2367
2368 ; Use Control port A, assuming a PS/2 style system.
2369 in al, 092h
2370 test al, 02h
2371 jz .done ; avoid trouble writing back the same value.
2372 and al, 0fdh ; disable the A20 gate.
2373 out 092h, al
2374
2375.done:
2376 pop xAX
2377 ret
2378ENDPROC TMPL_NM_CMN(Bs2DisableA20ViaPortA)
2379
2380
2381;;
2382; Checks if the no-execution bit is supported.
2383;
2384; @returns AL=1 and ZF=0 if supported.
2385; @returns AL=0 and ZF=1 if not.
2386; @uses al
2387;
2388BEGINPROC TMPL_NM_CMN(Bs2IsNXSupported)
2389 push xBP
2390 mov xBP, xSP
2391 push sBX
2392 push sDX
2393 push sCX
2394 push sAX
2395
2396 mov eax, 080000000h
2397 cpuid
2398 cmp eax, 080000001h
2399 jb .not_supported
2400 cmp eax, 080001000h
2401 jae .not_supported
2402
2403 mov eax, 080000001h
2404 cpuid
2405 test edx, X86_CPUID_EXT_FEATURE_EDX_NX
2406 jz .not_supported
2407
2408 ; supported
2409 pop sAX
2410 mov al, 1
2411
2412.return:
2413 pop sCX
2414 pop sDX
2415 pop sBX
2416 leave
2417 ret
2418.not_supported:
2419 pop sAX
2420 xor al, al
2421 jmp .return
2422ENDPROC TMPL_NM_CMN(Bs2IsNXSupported)
2423
2424
2425;;
2426; Sets EFER.NXE=al if NXE is supported.
2427;
2428; @param al 0 if NXE should be disabled, non-zero if it should
2429; be enabled.
2430; @uses nothing.
2431;
2432BEGINPROC TMPL_NM_CMN(Bs2SetupNX)
2433 push xBP
2434 mov xBP, xSP
2435 push sAX
2436 push sDX
2437 push sCX
2438
2439 call TMPL_NM_CMN(Bs2IsNXSupported)
2440 jz .done
2441
2442 mov ecx, MSR_K6_EFER
2443 rdmsr
2444 test byte [xBP - sCB], 0ffh
2445 jz .disable_it
2446 or eax, MSR_K6_EFER_NXE
2447 jmp .set_it
2448.disable_it:
2449 and eax, ~MSR_K6_EFER_NXE
2450.set_it:
2451 wrmsr
2452
2453.done:
2454 pop sCX
2455 pop sDX
2456 pop sAX
2457 leave
2458 ret
2459ENDPROC TMPL_NM_CMN(Bs2SetupNX)
2460
2461
2462;;
2463; Disables NX if supported.
2464;
2465; @uses nothing.
2466;
2467BEGINPROC TMPL_NM_CMN(Bs2DisableNX)
2468 push xBP
2469 mov xBP, xSP
2470 push xAX
2471
2472 xor al, al
2473 call TMPL_NM_CMN(Bs2SetupNX)
2474
2475 pop xAX
2476 leave
2477 ret
2478ENDPROC TMPL_NM_CMN(Bs2DisableNX)
2479
2480
2481;;
2482; Enables NX if supported.
2483;
2484; @uses nothing.
2485;
2486BEGINPROC TMPL_NM_CMN(Bs2EnableNX)
2487 push xBP
2488 mov xBP, xSP
2489 push xAX
2490
2491 mov al, 1
2492 call TMPL_NM_CMN(Bs2SetupNX)
2493
2494 pop xAX
2495 leave
2496 ret
2497ENDPROC TMPL_NM_CMN(Bs2EnableNX)
2498
2499
2500;;
2501; Panics if the testing feature of the VMMDev is missing.
2502;
2503; A message will be printed.
2504;
2505; @uses Nothing.
2506;
2507BEGINPROC TMPL_NM_CMN(Bs2PanicIfVMMDevTestingIsMissing)
2508 push xDX
2509 push sAX
2510
2511 xor eax, eax
2512 mov dx, VMMDEV_TESTING_IOPORT_NOP
2513 in eax, dx
2514 cmp eax, VMMDEV_TESTING_NOP_RET
2515 je .ok
2516
2517 mov xAX, .s_szMissingVMMDevTesting
2518 call TMPL_NM_CMN(PrintStr)
2519 call Bs2Panic
2520
2521.ok:
2522 pop sAX
2523 pop xDX
2524 ret
2525
2526.s_szMissingVMMDevTesting:
2527 db 'fatal error: The testing feature of the VMMDevVMMDev is not present!', 13, 10, 0
2528ENDPROC TMPL_NM_CMN(Bs2PanicIfVMMDevTestingIsMissing)
2529
2530
2531
2532%ifdef BS2_WITH_TRAPS
2533
2534;;
2535; Switches to ring-0 from whatever the current mode is.
2536;
2537; @uses cs, ss, ds, es, fs, gs
2538;
2539BEGINPROC TMPL_NM_CMN(Bs2ToRing0)
2540 push sAX
2541 mov sAX, BS2_SYSCALL_TO_RING0
2542 int BS2_TRAP_SYSCALL
2543 pop sAX
2544 ret
2545ENDPROC TMPL_NM_CMN(Bs2ToRing0)
2546
2547;;
2548; Switches to ring-1 from whatever the current mode is.
2549;
2550; @uses cs, ss, ds, es, fs, gs
2551;
2552BEGINPROC TMPL_NM_CMN(Bs2ToRing1)
2553 push sAX
2554 mov sAX, BS2_SYSCALL_TO_RING1
2555 int BS2_TRAP_SYSCALL
2556 pop sAX
2557 ret
2558ENDPROC TMPL_NM_CMN(Bs2ToRing1)
2559
2560;;
2561; Switches to ring-0 from whatever the current mode is.
2562;
2563; @uses cs, ss, ds, es, fs, gs
2564;
2565BEGINPROC TMPL_NM_CMN(Bs2ToRing2)
2566 push sAX
2567 mov sAX, BS2_SYSCALL_TO_RING2
2568 int BS2_TRAP_SYSCALL
2569 pop sAX
2570 ret
2571ENDPROC TMPL_NM_CMN(Bs2ToRing2)
2572
2573;;
2574; Switches to ring-3 from whatever the current mode is.
2575;
2576; @uses cs, ss, ds, es, fs, gs
2577;
2578BEGINPROC TMPL_NM_CMN(Bs2ToRing3)
2579 push sAX
2580 mov sAX, BS2_SYSCALL_TO_RING3
2581 int BS2_TRAP_SYSCALL
2582 pop sAX
2583 ret
2584ENDPROC TMPL_NM_CMN(Bs2ToRing3)
2585
2586;;
2587; Switches the given ring from whatever the current mode is.
2588;
2589; @param AL The desired ring.
2590; @uses cs, ss, ds, es, fs, gs
2591;
2592BEGINPROC TMPL_NM_CMN(Bs2ToRingN)
2593 pushf
2594 cmp al, 3
2595 je .ring3
2596 cmp al, 2
2597 je .ring2
2598 cmp al, 1
2599 je .ring1
2600.ring0:
2601 call TMPL_NM_CMN(Bs2ToRing0)
2602.done:
2603 popf
2604 ret
2605
2606.ring1:
2607 call TMPL_NM_CMN(Bs2ToRing1)
2608 jmp .done
2609.ring2:
2610 call TMPL_NM_CMN(Bs2ToRing2)
2611 jmp .done
2612.ring3:
2613 call TMPL_NM_CMN(Bs2ToRing3)
2614 jmp .done
2615ENDPROC TMPL_NM_CMN(Bs2ToRingN)
2616
2617%endif ; BS2_WITH_TRAPS
2618
2619
2620
2621;
2622; Wrapper for dynamically calling the right specific method.
2623; This avoid putting large portions of the code in the 2nd template.
2624;
2625
2626TMPL_NM_CMN(g_pfnPrintStrInternal): TMPL_PTR_DEF 0
2627TMPL_NM_CMN(g_pfnPrintChrInternal): TMPL_PTR_DEF 0
2628
2629BEGINPROC TMPL_NM_CMN(PrintStr)
2630 jmp [TMPL_NM_CMN(g_pfnPrintStrInternal)]
2631ENDPROC TMPL_NM_CMN(PrintStr)
2632
2633BEGINPROC TMPL_NM_CMN(PrintChr)
2634 jmp [TMPL_NM_CMN(g_pfnPrintChrInternal)]
2635ENDPROC TMPL_NM_CMN(PrintChr)
2636
2637
2638%include "bootsector2-template-footer.mac"
2639
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