VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-bootsector.asm@ 104792

Last change on this file since 104792 was 103866, checked in by vboxsync, 9 months ago

ValidationKit/bootsectors: clean up bs3-bootsector a little, bugref:9898

  • fix non-display of error code
  • add code to dodge around 64kB DMA boundaries
  • remove never-working code to handle wrong fd geometry
  • simplify 'HLT_ON_FAILURE' ifdefs
  • squeeze out a few bytes
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.5 KB
Line 
1; $Id: bs3-bootsector.asm 103866 2024-03-15 12:07:48Z vboxsync $
2;; @file
3; Generic bootsector for BS3.
4;
5; This sets up stack at %fff0 and loads the next sectors from the floppy at
6; %10000 (1000:0000 in real mode), then starts executing at cs:ip=1000:0000.
7;
8
9;
10; Copyright (C) 2007-2023 Oracle and/or its affiliates.
11;
12; This file is part of VirtualBox base platform packages, as
13; available from https://www.virtualbox.org.
14;
15; This program is free software; you can redistribute it and/or
16; modify it under the terms of the GNU General Public License
17; as published by the Free Software Foundation, in version 3 of the
18; License.
19;
20; This program is distributed in the hope that it will be useful, but
21; WITHOUT ANY WARRANTY; without even the implied warranty of
22; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23; General Public License for more details.
24;
25; You should have received a copy of the GNU General Public License
26; along with this program; if not, see <https://www.gnu.org/licenses>.
27;
28; The contents of this file may alternatively be used under the terms
29; of the Common Development and Distribution License Version 1.0
30; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
31; in the VirtualBox distribution, in which case the provisions of the
32; CDDL are applicable instead of those of the GPL.
33;
34; You may elect to license modified versions of this file under the
35; terms and conditions of either the GPL or the CDDL or both.
36;
37; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
38;
39
40
41
42;*********************************************************************************************************************************
43;* Header Files *
44;*********************************************************************************************************************************
45%include "bs3kit.mac"
46%include "iprt/asmdefs.mac"
47%include "iprt/x86.mac"
48
49
50;*********************************************************************************************************************************
51;* Defined Constants And Macros *
52;*********************************************************************************************************************************
53;; Enables faster loading.
54%define BS3KIT_BOOTSECTOR_FASTER_LOAD
55;; Enables load progress dots.
56%define BS3KIT_BOOTSECTOR_LOAD_DOTS
57;; Enables support for fake 63.5 MB floppies with 255 sectors, 2 heads and 255 tracks.
58%define BS3KIT_BOOTSECTOR_SUPPORT_63_5MB_FLOPPIES
59;; Enables code to avoid trying to read across 64kB DMA boundaries.
60%define BS3KIT_BOOTSECTOR_DODGE_BOUNDARIES
61
62;; Halts on failure location. For debugging.
63;%define HLT_ON_FAILURE 1
64
65;; Enables saving of initial register state.
66;; Dropping this is useful for making more room for debugging.
67%define BS3KIT_BOOTSECTOR_SAVE_INITIAL_STATE
68
69
70%ifdef __YASM__
71[map all]
72%endif
73
74;
75; Start with a jump just to follow the convention.
76; Also declare all segments/sections to establish them and their order.
77;
78 ORG 07c00h
79
80BITS 16
81CPU 8086
82start:
83 jmp short bs3InitCode
84 db 0ah ; Should be nop, but this looks better.
85g_OemId: ; 003h
86 db 'BS3Kit', 0ah, 0ah
87
88;
89; DOS 4.0 Extended Bios Parameter Block:
90;
91g_cBytesPerSector: ; 00bh
92 dw 512
93g_cSectorsPerCluster: ; 00dh
94 db 1
95g_cReservedSectors: ; 00eh
96 dw 1
97g_cFATs: ; 010h
98 db 0
99g_cRootDirEntries: ; 011h
100 dw 0
101g_cTotalSectors: ; 013h - We (ab)use this for the number of checksumed sectors.
102 dw 0
103g_bMediaDescriptor: ; 015h
104 db 0
105g_cSectorsPerFAT: ; 016h
106 dw 0
107g_cPhysSectorsPerTrack: ; 018h
108 dw 18
109g_cHeads: ; 01ah
110 dw 2
111g_cHiddentSectors: ; 01ch
112 dd 1
113g_cLargeTotalSectors: ; 020h - We (ab)use this to indicate the number of sectors to load.
114 dd 0
115g_bBootDrv: ; 024h
116 db 80h
117g_bFlagsEtc: ; 025h
118 db 0
119g_bExtendedSignature: ; 026h
120 db 0x29
121g_dwSerialNumber: ; 027h - We (ab)use this for the base image checksum.
122 dd 0x0a458634
123g_abLabel: ; 02bh
124 db 'VirtualBox', 0ah
125g_abFSType: ; 036h
126 db 'RawCode', 0ah
127g_BpbEnd: ; 03ch
128
129
130;
131; Where the real init code starts.
132;
133bs3InitCode:
134 cli
135
136%if 0 ; This does not work, we clear it wholesale below
137%ifdef BS3KIT_BOOTSECTOR_SAVE_INITIAL_STATE
138 ; save the registers.
139 mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.rax], ax
140 mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.ds], ds
141%endif
142%endif
143
144 ; set up the DS segment register so we can skip the CS prefix when saving more prefixes..
145 mov ax, 0 ; no xor ax,ax as that messes with the eflags
146 mov ds, ax
147
148%if 0 ; This does not work, we clear it wholesale below
149%ifdef BS3KIT_BOOTSECTOR_SAVE_INITIAL_STATE
150 mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rdi], di
151 mov di, BS3_ADDR_REG_SAVE
152 mov [di + BS3REGCTX.rsp], sp
153 mov [di + BS3REGCTX.ss], ss
154 mov [di + BS3REGCTX.rcx], cx
155 mov [di + BS3REGCTX.es], es
156 mov [di + BS3REGCTX.rbp], bp
157%endif
158%endif
159
160 ; set up the stack.
161 mov ss, ax
162 mov sp, BS3_ADDR_STACK
163
164 ; Load es and setup bp frame.
165 mov es, ax
166 mov bp, sp
167%if 0
168 mov [bp], ax ; clear the first 8 bytes (terminates the ebp chain)
169 mov [bp + 02h], ax
170 mov [bp + 04h], ax
171 mov [bp + 06h], ax
172%else
173 mov di, sp ; Combine clearing the rbp chain and register save area.
174%endif
175
176 ; Save flags now that we know that there's a valid stack.
177 pushf
178
179 ;
180 ; Clear the register area.
181 ;
182%if 0
183 mov di, BS3_ADDR_REG_SAVE
184 mov cx, BS3REGCTX_size/2
185%else
186 mov cx, (BS3_ADDR_LOAD - BS3_ADDR_STACK) / 2
187%endif
188 cld
189 rep stosw
190
191 ;
192 ; Do basic CPU detection.
193 ;
194
195 ; 0. Load the register save area address into DI to avoid absolute addressing
196 ; when saving additional state. To avoid disp16, offset the address.
197 mov di, BS3_ADDR_REG_SAVE + 0x70
198
199 ; 1. bit 15-bit was fixed to 1 in pre-286 CPUs, and fixed to 0 in 286+.
200%if 0 ; 3 vs 2 bytes
201 mov ax, [bp - 2]
202%else
203 pop ax
204 push ax
205%endif
206 test ah, 080h ; always set on pre 286, clear on 286 and later
207 jnz .pre_80286
208
209 ; 2. On a 286 you cannot popf IOPL and NT from real mode.
210.detect_286_or_386plus:
211CPU 286
212 mov ah, (X86_EFL_IOPL | X86_EFL_NT) >> 8 ; OR'ing would be safer, but costs a byte and nothing should be set anyway.
213 push ax
214 popf
215 pushf
216 cmp ah, [bp - 3]
217 pop ax
218 je .is_386plus
219.is_80286:
220CPU 286
221%ifdef BS3KIT_BOOTSECTOR_SAVE_INITIAL_STATE
222 smsw [di + BS3REGCTX.cr0 - 0x70]
223%endif
224.pre_80286:
225CPU 8086
226%ifdef BS3KIT_BOOTSECTOR_SAVE_INITIAL_STATE
227 mov [di - 0x70 + BS3REGCTX.rflags], ax
228 mov [di - 0x70 + BS3REGCTX.rbx], bx
229 mov [di - 0x70 + BS3REGCTX.rdx], dx
230 mov [di - 0x70 + BS3REGCTX.rsi], si
231%endif
232 jmp .do_load
233
234 ; Save 386 registers. We can now skip the CS prefix as DS is flat.
235CPU 386
236.is_386plus:
237%ifdef BS3KIT_BOOTSECTOR_SAVE_INITIAL_STATE
238 shr eax, 16
239 mov [di - 0x70 + BS3REGCTX.rax+2], ax
240 mov eax, esp
241 shr eax, 16
242 mov [di - 0x70 + BS3REGCTX.rsp+2], ax
243 mov eax, ebp
244 shr eax, 16
245 mov [di - 0x70 + BS3REGCTX.rbp+2], ax
246 mov eax, edi
247 shr eax, 16
248 mov [di - 0x70 + BS3REGCTX.rdi+2], ax
249 shr ecx, 16
250 mov [di - 0x70 + BS3REGCTX.rcx+2], cx
251 mov [di - 0x70 + BS3REGCTX.fs], fs
252 mov [di - 0x70 + BS3REGCTX.gs], gs
253 mov [di - 0x70 + BS3REGCTX.rbx], ebx
254 mov [di - 0x70 + BS3REGCTX.rdx], edx
255 mov [di - 0x70 + BS3REGCTX.rsi], esi
256 mov eax, cr2
257 mov [di - 0x70 + BS3REGCTX.cr2], eax
258 mov eax, cr3
259 mov [di - 0x70 + BS3REGCTX.cr3], eax
260 mov byte [di - 0x70 + BS3REGCTX.bMode], BS3_MODE_RM
261 mov [di - 0x70 + BS3REGCTX.cs], cs
262 xor eax, eax
263 mov ax, start
264 mov [di - 0x70 + BS3REGCTX.rip], eax
265
266 ; Pentium/486+: CR4 requires VME/CPUID, so we need to detect that before accessing it.
267 mov [di - 0x70 + BS3REGCTX.cr4], eax
268 popf ; (restores IOPL+NT)
269 pushfd
270 pop eax
271 mov [di - 0x70 + BS3REGCTX.rflags], eax
272 xor eax, X86_EFL_ID
273 push eax
274 popfd
275 pushfd
276 pop ebx
277 cmp ebx, eax
278 jne .no_cr4
279 mov eax, cr4
280 mov [di - 0x70 + BS3REGCTX.cr4], eax
281.no_cr4:
282%else
283 popf ; (restores IOPL+NT)
284%endif
285 ; Make sure caching is enabled and alignment is off.
286 mov eax, cr0
287%ifdef BS3KIT_BOOTSECTOR_SAVE_INITIAL_STATE
288 mov [di - 0x70 + BS3REGCTX.cr0], eax
289%endif
290 and eax, ~(X86_CR0_NW | X86_CR0_CD | X86_CR0_AM)
291 mov cr0, eax
292
293 ; Load all the code.
294.do_load
295 mov [g_bBootDrv], dl
296 call NAME(bs3InitLoadImage)
297%if 0
298 mov al, '='
299 call bs3PrintChrInAl
300%endif
301
302 ;
303 ; Call the user 'main' procedure (shouldn't return).
304 ;
305 cld
306 call BS3_SEL_TEXT16:0000h
307
308 ; Panic/hang.
309Bs3Panic:
310 cli
311 jmp Bs3Panic
312
313
314;; For debug and error handling.
315; @uses ax
316bs3PrintHexInAl:
317CPU 286
318 push ax
319 shr al, 4
320 call bs3PrintHexDigitInAl
321 pop ax
322bs3PrintHexDigitInAl:
323 and al, 0fh
324 cmp al, 10
325 jb .decimal
326 add al, 'a' - '0' - 10
327.decimal:
328 add al, '0'
329bs3PrintChrInAl:
330 push bx
331 mov ah, 0eh
332 mov bx, 0ff00h
333 int 10h
334 pop bx
335 ret
336
337
338;;
339; Loads the image off the floppy.
340;
341; This uses g_cLargeTotalSectors to figure out how much to load.
342;
343; Clobbers everything except ebp and esp. Panics on failure.
344;
345; @param dl The boot drive number (from BIOS).
346; @uses ax, cx, bx, esi, di
347;
348BEGINPROC bs3InitLoadImage
349 push bp
350 mov bp, sp
351 push es
352%define bSavedDiskNo byte [bp - 04h]
353 push dx
354%define bMaxSector byte [bp - 06h]
355%define wMaxSector word [bp - 06h]
356 xor ax, ax
357 push ax
358%define bMaxHead byte [bp - 08h]
359 push ax
360
361 ;
362 ; Try figure the geometry.
363 ;
364 mov ah, 08h
365 int 13h
366%ifndef HLT_ON_FAILURE
367 jc .failure
368%else
369 jnc .ok_geometry_call
370 cli
371 hlt
372.ok_geometry_call:
373%endif
374%ifndef BS3KIT_BOOTSECTOR_SUPPORT_63_5MB_FLOPPIES
375 and cl, 63 ; only the sector count. (63.5MB has 255 sectors, so don't do this!)
376%endif
377 mov bMaxSector, cl
378 mov bMaxHead, dh
379 mov dl, bSavedDiskNo
380 ;63*2*0xff*512 = 0xFB0400 (16 450 560)
381%if 0 ; DEBUG ; bMaxSector=0x12 (18); bMaxHead=0x01; bMaxCylinder=0x4f (79)
382 mov al, 'S'
383 call bs3PrintChrInAl
384 mov al, bMaxSector
385 call bs3PrintHexInAl
386 mov al, 'H'
387 call bs3PrintChrInAl
388 mov al, bMaxHead
389 call bs3PrintHexInAl
390 mov al, 'C'
391 call bs3PrintChrInAl
392 mov al, ch ; first 8-bit of cylinder count.
393 call bs3PrintHexInAl
394 mov al, ';'
395 call bs3PrintChrInAl
396%endif
397
398%ifndef BS3KIT_BOOTSECTOR_FASTER_LOAD
399 ;
400 ; Load the sectors following the boot sector one at a time (avoids problems).
401 ;
402 mov si, [g_cLargeTotalSectors] ; 16-bit sector count ==> max 512 * 65 535 = 33 553 920 bytes.
403 dec si ; Practically max: ca 575 KB, or 1150 sectors. Linker set BS3_MAX_SIZE to 480KB.
404
405 mov di, BS3_ADDR_LOAD / 16 ; The current load segment.
406 mov cx, 0002h ; ch/cylinder=0 (0-based); cl/sector=2 (1-based)
407 xor dh, dh ; dh/head=0
408.the_load_loop:
409 %if 0 ; DEBUG
410 mov al, 'c'
411 call bs3PrintChrInAl
412 mov al, ch
413 call bs3PrintHexInAl
414 mov al, 's'
415 call bs3PrintChrInAl
416 mov al, cl
417 call bs3PrintHexInAl
418 mov al, 'h'
419 call bs3PrintChrInAl
420 mov al, dh
421 call bs3PrintHexInAl
422 mov al, ';'
423 call bs3PrintChrInAl
424 %elifdef BS3KIT_BOOTSECTOR_LOAD_DOTS
425 mov al, '.'
426 call bs3PrintChrInAl
427 %endif
428 xor bx, bx
429 mov es, di ; es:bx -> buffer
430 mov ax, 0201h ; al=1 sector; ah=read function
431 int 13h
432 %ifndef HLT_ON_FAILURE
433 jc .failure
434 %else
435 jnc .read_ok
436 cli
437 hlt
438.read_ok:
439 %endif
440
441 ; advance to the next sector/head/cylinder.
442 inc cl
443 cmp cl, bMaxSector
444 jbe .adv_addr
445
446 mov cl, 1
447 inc dh
448 cmp dh, bMaxHead
449 jbe .adv_addr
450
451 mov dh, 0
452 inc ch
453
454.adv_addr:
455 add di, 512 / 16
456 dec si
457 jnz .the_load_loop
458
459%else ; BS3KIT_BOOTSECTOR_FASTER_LOAD
460 ;
461 ; Load the sectors following the boot sector, trying to load a whole
462 ; side in each bios call, falling back on single sector reads if we
463 ; run into DMA 64KB boundrary issues (BIOS must tell us).
464 ;
465 mov si, [g_cLargeTotalSectors] ; 16-bit sector count ==> max 512 * 65 535 = 33 553 920 bytes.
466 dec si ; Skip the boot sector, it's not part of the test image we execute.
467 mov di, BS3_ADDR_LOAD / 16 ; The current load segment.
468 mov cx, 0002h ; ch/cylinder=0 (0-based); cl/sector=0 (1-based)
469 xor dh, dh ; dh/head=0
470.the_load_loop:
471 %if 0 ; DEBUG
472 mov al, 'c'
473 call bs3PrintChrInAl
474 mov al, ch
475 call bs3PrintHexInAl
476 mov al, 's'
477 call bs3PrintChrInAl
478 mov al, cl
479 call bs3PrintHexInAl
480 mov al, 'h'
481 call bs3PrintChrInAl
482 mov al, dh
483 call bs3PrintHexInAl
484 mov al, '#'
485 call bs3PrintChrInAl
486 %elifdef BS3KIT_BOOTSECTOR_LOAD_DOTS
487 mov al, '.'
488 call bs3PrintChrInAl
489 %endif
490 mov ax, wMaxSector ; read to the end of the side by default.
491 sub al, cl
492 inc al
493 %ifdef BS3KIT_BOOTSECTOR_SUPPORT_63_5MB_FLOPPIES
494 cmp al, 72 ; The BIOS dislikes reading too many sectors at a time.
495 jbe .read_again ; Look for 'num_sectors > 72' in PC/BIOS/floppy.c.
496 mov al, 72
497 %endif
498.read_again:
499 cmp si, ax
500 jae .do_read
501 mov ax, si
502.do_read:
503
504 %ifdef BS3KIT_BOOTSECTOR_DODGE_BOUNDARIES
505 ; Dodge around 64kB DMA boundaries
506 push di ; di is 'paragraph' address of buffer
507 push ax ; Example: di = 1f60h, al = 12h = 18-sector request;
508 shr di, 5 ; 0fbh addr = 1f600h (can fit 5x 200h below 128kB)
509 and di, 7fh ; 7bh
510 add di, ax ; 8dh
511 sub di, 80h ; 0dh
512 pop ax ; 12h
513 js .non_boundary
514 sub ax, di ; 05h
515.non_boundary:
516 pop di
517 %endif
518
519 %if 0 ; DEBUG
520 push ax
521 call bs3PrintHexInAl
522 mov al, ';'
523 call bs3PrintChrInAl
524 pop ax
525 %endif
526
527 mov ah, 02h ; ah=read function
528 xor bx, bx
529 mov es, di ; es:bx -> buffer
530 int 13h
531 %ifdef BS3KIT_BOOTSECTOR_DODGE_BOUNDARIES
532 jc .failure
533 %else
534 jnc .advance_sector
535
536 cmp ah, 9 ; DMA 64KB crossing error
537 jne .failure
538 mov ax, 1 ; Retry reading a single sector.
539 jmp .read_again
540 %endif ; !BS3KIT_BOOTSECTOR_DODGE_BOUNDARIES
541
542 ; advance to the next sector/head/cylinder and address.
543.advance_sector:
544 inc cl
545 %ifdef BS3KIT_BOOTSECTOR_SUPPORT_63_5MB_FLOPPIES
546 jz .adv_sector ; Wraparound is a 63.5 MB problem.
547 %endif
548 cmp cl, bMaxSector
549 jbe .adv_addr
550
551.adv_sector:
552 mov cl, 1
553 inc dh
554 cmp dh, bMaxHead
555 jbe .adv_addr
556
557 mov dh, 0
558 inc ch
559
560.adv_addr:
561 dec si
562 jz .done_reading
563 add di, 512 / 16
564 dec al
565 jnz .advance_sector
566 jmp .the_load_loop
567
568.done_reading:
569%endif ; BS3KIT_BOOTSECTOR_FASTER_LOAD
570%if 0 ; DEBUG
571 mov al, 'D'
572 call bs3PrintChrInAl
573%elifdef BS3KIT_BOOTSECTOR_LOAD_DOTS
574 mov al, 13
575 call bs3PrintChrInAl
576 mov al, 10
577 call bs3PrintChrInAl
578%endif
579
580%if 0 ; 3 vs 2 bytes
581 add sp, 2*2
582%else
583 pop dx
584 pop dx
585%endif
586 pop dx
587 pop es
588 pop bp
589 ret
590
591%ifndef HLT_ON_FAILURE
592 ;
593 ; Something went wrong, display a message.
594 ;
595.str_sErrMsgBang:
596 db ' rd err!'
597
598.failure:
599 %if 1 ; Disable to save space for debugging.
600 mov al, ah
601 call bs3PrintHexInAl
602 ; print message
603 mov si, .str_sErrMsgBang
604.failure_next_char:
605 lodsb
606 call bs3PrintChrInAl
607 cmp byte [si], '!' ; Don't trust that int 10h/0eh preserves al
608 jne .failure_next_char
609 %endif
610%else
611.failure:
612%endif
613 jmp Bs3Panic
614;ENDPROC bs3InitLoadImage - don't want the padding.
615
616
617;
618; Pad the remainder of the sector with int3's and end it with the DOS signature.
619;
620bs3Padding:
621 times ( 510 - ( (bs3Padding - start) % 512 ) ) db 0cch
622 db 055h, 0aah
623
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