VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 3 years ago

scm copyright and license note update

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