VirtualBox

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

Last change on this file since 102270 was 102270, checked in by vboxsync, 13 months ago

bs3kit: Fixed some issues with loading of a fake 63.5 MB floppy. Added optional checksumming of the images we load (disabled by default, as it's slow in IEM). bugref:10371

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