VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 5 months ago

Copyright year updates by scm.

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