VirtualBox

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

Last change on this file since 101362 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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