您的位置:首页 > Web前端 > React

reactos操作系统实现(47)

2009-07-22 20:14 288 查看
当光盘变成记录数据以后,就开始使用光盘来分发操作系统了。毕竟光盘有着储存数据量大,成本便宜的优势。下面就来分析Reactos是怎么样通过光盘的格式来引导操作系统的。

现今的计算机BIOS,会在开机时根据El Torito规格,查找光盘上的开机代码。若该光盘具有开机代码,则BIOS会指配一个磁盘驱动器代号给该光驱。磁盘驱动器代号通常为80(模拟硬盘)或是00(模拟软盘)等。借由模拟成硬盘或软盘,可让旧式的操作系统由光盘开机。

现今新式的操作系统则不需做模拟,只要有如ISOLINUX之类的开机引导程序(boot loader),即可由光盘开机。

#001 ;
****************************************************************************

#002 ;

#003 ;
isolinux.asm

#004 ;

#005 ; A
program to boot Linux kernels off a CD-ROM using the El Torito

#006 ; boot
standard in "no emulation" mode, making the entire filesystem

#007 ;
available. It is based on the
SYSLINUX boot loader for MS-DOS

#008 ;
floppies.

#009 ;

#010 ;
Copyright (C) 1994-2001 H. Peter
Anvin

#011 ;

#012 ; This
program is free software; you can redistribute it and/or modify

#013 ; it
under the terms of the GNU General Public License as published by

#014 ; the
Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,

#015 ; USA;
either version 2 of the License, or (at your option) any later

#016 ;
version; incorporated herein by reference.

#017 ;

#018 ;
****************************************************************************

#019 ;

#020 ; THIS FILE IS A MODIFIED VERSION OF
ISOLINUX.ASM

#021 ; MODIFICATION DONE BY MICHAEL K TER LOUW

#022 ; LAST UPDATED 3-9-2002

#023 ; SEE "COPYING" FOR INFORMATION
ABOUT THE LICENSE THAT APPLIES TO THIS RELEASE

#024 ;

#025 ;
****************************************************************************

#026 ;

#027 ; This file is a modified version of
ISOLINUX.ASM.

#028 ; Modification done by Eric Kohl

#029 ; Last update 04-25-2002

#030 ;

#031 ;
****************************************************************************

#032

#033 ; Note: The Makefile builds one version with
DEBUG_MESSAGES automatically.

#034 ;%define DEBUG_MESSAGES ; Uncomment to get debugging
messages

#035

#036 %define WAIT_FOR_KEY

#037

#038

下面BIOS的数据区保留内存空间。

#039 ;
---------------------------------------------------------------------------

#040 ;
BEGIN THE BIOS/CODE/DATA SEGMENT

#041 ;
---------------------------------------------------------------------------

#042

#043 absolute
0400h

#044 serial_base resw
4 ; Base addresses for 4
serial ports

#045 absolute
0413h

#046 BIOS_fbm resw
1 ; Free Base Memory
(kilobytes)

#047 absolute
046Ch

#048 BIOS_timer resw
1 ; Timer ticks

#049 absolute
0472h

#050 BIOS_magic resw
1 ; BIOS reset magic

#051 absolute
0484h

#052 BIOS_vidrows resb
1 ; Number of screen rows

#053

#054 ;

#055 ; Memory below this point is reserved for the
BIOS and the MBR

#056 ;

1000h以前都是BIOS的数据区,不能放置代码。

#057 absolute
1000h

#058 trackbuf resb
8192 ; Track buffer goes here

#059 trackbufsize equ
$-trackbuf

#060 ; trackbuf
ends at 3000h

#061

#062 struc
open_file_t

#063 file_sector resd
1 ; Sector pointer (0 =
structure free)

#064 file_left resd
1 ; Number of sectors
left

#065 endstruc

#066

#067 struc
dir_t

#068 dir_lba resd
1 ; Directory start (LBA)

#069 dir_len resd
1 ; Length in bytes

#070 dir_clust resd
1 ; Length in clusters

#071 endstruc

#072

#073

#074 MAX_OPEN_LG2 equ
2 ; log2(Max number of
open files)

#075 MAX_OPEN equ
(1 << MAX_OPEN_LG2)

#076 SECTORSIZE_LG2 equ 11 ; 2048
bytes/sector (El Torito requirement)

#077 SECTORSIZE equ
(1 << SECTORSIZE_LG2)

#078 CR equ
13 ; Carriage Return

#079 LF equ
10 ; Line Feed

#080 retry_count equ
6 ; How patient are we
with the BIOS?

#081

#082

#083

BSS段数据。

#084 absolute
5000h ; Here we
keep our BSS stuff

#085

#086 DriveNo resb
1 ; CD-ROM BIOS drive
number

#087 DiskError resb
1 ; Error code for disk
I/O

#088 RetryCount resb
1 ; Used for disk access
retries

#089 TimeoutCount resb
1 ; Timeout counter

#090 ISOFlags resb
1 ; Flags for ISO
directory search

#091 RootDir resb
dir_t_size ; Root directory

#092 CurDir resb
dir_t_size ; Current directory

#093 ISOFileName resb
64 ; ISO filename
canonicalization buffer

#094 ISOFileNameEnd equ $

#095

#096

#097 alignb
open_file_t_size

#098 Files resb
MAX_OPEN*open_file_t_size

#099

#100

#101

这里ISOBOOT有代码段开始,由于BIOS会读取光盘的引导区到内存 7000开始位置,跟硬盘和磁盘是一样的。

#102 section
.text

#103 org
7000h

#104

#105 start:

#106 cli ; Disable
interrupts

#107 xor ax, ax ;
ax = segment zero

#108 mov ss, ax ;
Initialize stack segment

#109 mov sp, start ;
Set up stack

#110 mov ds, ax ;
Initialize other segment registers

#111 mov es, ax

#112 mov fs, ax

#113 mov gs, ax

#114 sti ; Enable interrupts

#115 cld ; Increment
pointers

#116

把引导代码从0000:7C00位置拷贝到0000:7000位置,然后再运行。

#117 mov cx, 2048 >> 2 ; Copy the bootsector

#118 mov si, 0x7C00 ; from 0000:7C00

#119 mov di, 0x7000 ;
to 0000:7000

#120 rep movsd ;
copy the program

通过一个跳转,实现重定位代码位置。

#121 jmp 0:relocate ;
jump into relocated code

#122

#123 relocate:

如果显示调度信息。

#124 ;
Display the banner and copyright

#125 %ifdef DEBUG_MESSAGES

#126 mov si, isolinux_banner ; si points to hello message

#127 call writestr ;
display the message

#128 mov si,copyright_str

#129 call writestr

#130 %endif

#131

#132

下面通过检查键盘输入来决定是否从光盘引导系统。

先清空键盘输入。

#133 ;
Make sure the keyboard buffer is empty

#134 %ifdef WAIT_FOR_KEY

#135 .kbd_buffer_test:

#136 call pollchar

#137 jz .kbd_buffer_empty

#138 call getchar

#139 jmp .kbd_buffer_test

#140 .kbd_buffer_empty:

到这里已经把键盘缓冲区清空了。

检查硬盘的MBR是否可以引导。

#141

#142 ;
Check for MBR on harddisk

#143 pusha

#144 mov ax, 0201h

#145 mov dx, 0080h

#146 mov cx, 0001h

#147 mov bx, trackbuf

#148 int 13h

#149 popa

如果硬盘不是可引导的,就立即跳到光盘引导,不需要用户选择。

#150 jc .boot_cdrom ; could not read hdd

#151

判断硬盘是否有引导扇区。

#152 push
ax

#153 mov
ax, word [trackbuf]

#154 cmp
ax, 0

如果没有引导扇区,就立即跳到光盘引导。

#155 je .boot_cdrom ; no boot sector found
(hopefully there are no weird bootsectors which begin with 0)

#156 pop
ax

#157

开始显示用户选择光盘引导,还是磁盘引导,同时进行5秒钟计时,如果用户不按下任何按键,就会自动选择硬盘引导。

#158 ;
Display the 'Press key' message and wait for a maximum of 5 seconds

输出换行回车。

#159 call crlf

输出按下任何键的提示字符串。

#160 mov si, presskey_msg ; si points to 'Press key' message

#161 call writestr ;
display the message

#162

5秒钟倒计时。

#163 mov byte [TimeoutCount], 5

#164 .next_second:

获取当前时钟计数到eax,并且相加19个计数。

#165 mov eax, [BIOS_timer] ; load current tick counter

#166 add eax, 19 ;

#167

测试是否有键盘输入任何按键。

#168 .poll_again:

#169 call pollchar

如果有任何按键输入,就跳到光盘引导。

#170 jnz .boot_cdrom

#171

每次比较BIOS里的计数是否与EAX计数相同。

#172 mov ebx, [BIOS_timer]

#173 cmp eax, ebx

#174 jnz .poll_again

#175

如果经历过19个计数,说明已经过了1秒钟。接着开始在屏幕上打印一个点。

#176 mov si, dot_msg ;
print '.'

#177 call writestr

如果超过5秒钟,就跳到硬盘引导。

#178 dec byte [TimeoutCount] ; decrement timeout counter

#179 jz .boot_harddisk

跳到下一秒计时。

#180 jmp .next_second

#181

硬盘引导的代码。

#182 .boot_harddisk:

#183 call crlf

#184

从第一个硬盘引导。

#185 ;
Boot first harddisk (drive 0x80)

#186 mov ax, 0201h

#187 mov dx, 0080h

#188 mov cx, 0001h

#189 mov bx, 7C00h

#190 int 13h

#191 jnc .go_hd

#192 jmp kaboom

#193 .go_hd:

#194 mov ax, cs

#195 mov ds, ax

#196 mov es, ax

#197 mov fs, ax

#198 mov gs, ax

#199 mov dx, 0080h

#200

#201 jmp 0:0x7C00

#202 %endif

#203

从光盘引导。

#204 .boot_cdrom:

#205 %ifdef WAIT_FOR_KEY

#206 call crlf

#207 call crlf

#208 %endif

#209

#210 ;
Save and display the boot drive number

#211 mov [DriveNo], dl

#212 %ifdef DEBUG_MESSAGES

#213 mov si, startup_msg

#214 call writemsg

#215 mov al, dl

#216 call writehex2

#217 call crlf

#218 %endif

#219

获取光驱的模拟状态。

#220 ;
Now figure out what we're actually doing

#221 ;
Note: use passed-in DL value rather than 7Fh because

#222 ;
at least some BIOSes will get the wrong value otherwise

#223 mov ax, 4B01h ;
Get disk emulation status

#224 mov dl, [DriveNo]

#225 mov si, spec_packet

#226 int 13h

#227 jc near spec_query_failed ; Shouldn't happen (BIOS bug)

#228 mov dl, [DriveNo]

#229 cmp [sp_drive], dl ;
Should contain the drive number

#230 jne near spec_query_failed

#231

#232 %ifdef DEBUG_MESSAGES

#233 mov si, spec_ok_msg

#234 call writemsg

#235 mov al, byte [sp_drive]

#236 call writehex2

#237 call crlf

#238 %endif

#239

发现有驱动器可以使用。

#240 found_drive:

通过中断13 的48H号功能读取驱动器信息。

#241 ;
Get drive information

#242 mov ah, 48h

#243 mov dl, [DriveNo]

#244 mov si, drive_params

#245 int 13h

#246 jnc params_ok

#247

#248 ;
mov si, nosecsize_msg No use in reporting this

#249 ;
call writemsg

#250

#251 params_ok:

#252 ;
Check for the sector size (should be 2048, but

#253 ;
some BIOSes apparently think we're 512-byte media)

#254 ;

#255 ;
FIX: We need to check what the proper behaviour

#256 ;
is for getlinsec when the BIOS thinks the sector

#257 ;
size is 512!!! For that, we need such a
BIOS, though...

#258 %ifdef DEBUG_MESSAGES

#259 mov si, secsize_msg

#260 call writemsg

#261 mov ax, [dp_secsize]

#262 call writehex4

#263 call crlf

#264 %endif

#265

#266

清空文件结构。

#267 ;

#268 ;
Clear Files structures

#269 ;

#270 mov di, Files

#271 mov cx, (MAX_OPEN*open_file_t_size)/4

#272 xor eax, eax

#273 rep stosd

#274

#275 ;

#276 ;
Now, we need to sniff out the actual filesystem data structures.

#277 ;
mkisofs gave us a pointer to the primary volume descriptor

#278 ;
(which will be at 16 only for a single-session disk!); from the PVD

#279 ;
we should be able to find the rest of what we need to know.

#280 ;

获取一个扇区数据。

#281 get_fs_structures:

#282 mov eax, 16 ;
Primary Volume Descriptor (sector 16)

#283 mov bx, trackbuf

#284 call getonesec

#285

#286 mov eax, [trackbuf+156+2]

#287 mov [RootDir+dir_lba],eax

#288 mov [CurDir+dir_lba],eax

#289 %ifdef DEBUG_MESSAGES

#290 mov si, rootloc_msg

#291 call writemsg

#292 call writehex8

#293 call crlf

#294 %endif

#295

#296 mov eax,[trackbuf+156+10]

#297 mov [RootDir+dir_len],eax

#298 mov [CurDir+dir_len],eax

#299 %ifdef DEBUG_MESSAGES

#300 mov si, rootlen_msg

#301 call writemsg

#302 call writehex8

#303 call crlf

#304 %endif

#305 add eax,SECTORSIZE-1

#306 shr eax,SECTORSIZE_LG2

#307 mov [RootDir+dir_clust],eax

#308 mov [CurDir+dir_clust],eax

#309 %ifdef DEBUG_MESSAGES

#310 mov si, rootsect_msg

#311 call writemsg

#312 call writehex8

#313 call crlf

#314 %endif

#315

这里查找根目录里的目录名称“/LOADER”。

#316 ;
Look for the "REACTOS" directory, and if found,

#317 ;
make it the current directory instead of the root

#318 ;
directory.

#319 mov di,isolinux_dir

#320 mov al,02h ;
Search for a directory

#321 call searchdir_iso

#322 jnz .dir_found

#323 mov si,no_dir_msg

#324 call writemsg

#325 jmp kaboom

#326

#327 .dir_found:

#328 mov [CurDir+dir_len],eax

#329 mov eax,[si+file_left]

#330 mov [CurDir+dir_clust],eax

#331 xor eax,eax ;
Free this file pointer entry

#332 xchg eax,[si+file_sector]

#333 mov [CurDir+dir_lba],eax

#334

#335

这里查找二级引导程序“SETUPLDR.SYS”文件。

#336 mov di, isolinux_bin ; di points to Isolinux filename

#337 call searchdir ;
look for the file

#338 jnz .isolinux_opened ; got the file

#339 mov si, no_isolinux_msg ; si points to error message

#340 call writemsg ;
display the message

#341 jmp kaboom ;
fail boot

#342

#343 .isolinux_opened:

#344 mov di, si ;
save file pointer

#345

#346 %ifdef DEBUG_MESSAGES

#347 mov si, filelen_msg

#348 call writemsg

#349 call writehex8

#350 call crlf

#351 %endif

#352

计算扇区的大小。

#353
mov
ecx, eax ; calculate sector
count

#354 shr
ecx, 11

#355 test
eax, 0x7FF

#356 jz
.full_sector

#357 inc
ecx

#358 .full_sector:

#359

#360 %ifdef DEBUG_MESSAGES

#361 mov
eax, ecx

#362 mov si, filesect_msg

#363 call writemsg

#364 call writehex8

#365 call crlf

#366 %endif

#367

这里把二级引导程序加载到0x8000位置。

#368 mov bx, 0x8000 ;
bx = load address

#369 mov si, di ;
restore file pointer

#370 mov cx, 0xFFFF ;
load the whole file

#371 call getfssec ;
get the whole file

#372

#373 %ifdef DEBUG_MESSAGES

#374 mov si, startldr_msg

#375 call writemsg

#376 call crlf

#377 %endif

#378

#379 mov dl, [DriveNo] ;
dl = boot drive

#380 mov
dh, 0 ;
dh = boot partition

最后跳转到0x8000的位置运行二级引导程序,也就是运行SETUPLDR.SYS文件。

#381 jmp 0:0x8000 ;
jump into OSLoader

#382

#383

#384

#385 ;

#386 ; searchdir:

#387 ;

#388 ; Open a file

#389 ;

#390 ; On
entry:

#391 ; DS:DI = filename

#392 ; If
successful:

#393 ; ZF
clear

#394 ; SI = file pointer

#395 ; DX:AX
or EAX = file length in bytes

#396 ; If
unsuccessful

#397 ; ZF
set

#398 ;

#399

#400 ;

#401 ; searchdir_iso is a special entry point for
ISOLINUX only. In addition

#402 ; to the above, searchdir_iso passes a file
flag mask in AL. This is useful

#403 ; for searching for directories.

#404 ;

#405 alloc_failure:

#406 xor ax,ax ;
ZF <- 1

#407 ret

#408

#409 searchdir:

#410 xor al,al

#411 searchdir_iso:

#412 mov [ISOFlags],al

#413 call allocate_file ;
Temporary file structure for directory

#414 jnz alloc_failure

#415 push es

#416 push ds

#417 pop es ; ES = DS

#418 mov si,CurDir

#419 cmp byte [di],'/' ;
If filename begins with slash

#420 jne .not_rooted

#421 inc di ;
Skip leading slash

#422 mov si,RootDir ;
Reference root directory instead

#423 .not_rooted:

#424 mov eax,[si+dir_clust]

#425 mov [bx+file_left],eax

#426 mov eax,[si+dir_lba]

#427 mov [bx+file_sector],eax

#428 mov edx,[si+dir_len]

#429

#430 .look_for_slash:

#431 mov ax,di

#432 .scan:

#433 mov cl,[di]

#434 inc di

#435 and cl,cl

#436 jz .isfile

#437 cmp cl,'/'

#438 jne .scan

#439 mov [di-1],byte 0 ;
Terminate at directory name

#440 mov cl,02h ;
Search for directory

#441 xchg cl,[ISOFlags]

#442 push di

#443 push cx

#444 push word .resume ; Where to "return" to

#445 push es

#446 .isfile:

#447 xchg ax,di

#448

#449 .getsome:

#450 ;
Get a chunk of the directory

#451 mov si,trackbuf

#452 pushad

#453 xchg bx,si

#454 mov cx,1 ;
load one sector

#455 call getfssec

#456 popad

#457

#458 .compare:

#459 movzx eax, byte [si] ; Length of directory entry

#460 cmp al, 33

#461 jb .next_sector

#462 mov cl, [si+25]

#463 xor cl, [ISOFlags]

#464 test cl, byte 8Eh ;
Unwanted file attributes!

#465 jnz .not_file

#466 pusha

#467 movzx cx, byte [si+32] ; File identifier length

#468 add si, byte 33 ;
File identifier offset

#469 call iso_compare_names

#470 popa

#471 je .success

#472 .not_file:

#473 sub edx, eax ;
Decrease bytes left

#474 jbe .failure

#475 add si, ax ;
Advance pointer

#476

#477 .check_overrun:

#478 ;
Did we finish the buffer?

#479 cmp si, trackbuf+trackbufsize

#480 jb .compare ;
No, keep going

#481

#482 jmp short .getsome ;
Get some more directory

#483

#484 .next_sector:

#485 ;
Advance to the beginning of next sector

#486 lea ax, [si+SECTORSIZE-1]

#487 and ax, ~(SECTORSIZE-1)

#488 sub ax, si

#489 jmp short .not_file ; We still need to do length checks

#490

#491 .failure:

#492 %ifdef DEBUG_MESSAGES

#493 mov si, findfail_msg

#494 call writemsg

#495 call crlf

#496 %endif

#497 xor eax, eax ;
ZF = 1

#498 mov [bx+file_sector], eax

#499 pop es

#500 ret

#501

#502 .success:

#503 mov eax, [si+2] ;
Location of extent

#504 mov [bx+file_sector], eax

#505 mov eax, [si+10] ;
Data length

#506 push eax

#507 add eax, SECTORSIZE-1

#508 shr eax, SECTORSIZE_LG2

#509 mov [bx+file_left], eax

#510 pop eax

#511 mov edx, eax

#512 shr edx, 16

#513 and bx, bx ;
ZF = 0

#514 mov si, bx

#515 pop es

#516 ret

#517

#518
.resume:

#519 ;
We get here if we were only doing part of a lookup

#520 ;
This relies on the fact that .success returns bx == si

#521 xchg edx, eax ;
Directory length in edx

#522 pop cx ;
Old ISOFlags

#523 pop di ;
Next filename pointer

#524

#525 mov byte [di-1], '/' ; restore the backslash in the filename

#526

#527 mov [ISOFlags], cl ;
Restore the flags

#528 jz .failure ;
Did we fail? If so fail for real!

#529 jmp .look_for_slash ; Otherwise, next level

#530

#531 ;

#532 ; allocate_file: Allocate a file structure

#533 ;

#534 ; If
successful:

#535 ; ZF set

#536 ; BX = file pointer

#537 ; In
unsuccessful:

#538 ; ZF clear

#539 ;

#540 allocate_file:

#541 push cx

#542 mov bx, Files

#543 mov cx, MAX_OPEN

#544 .check:

#545 cmp dword [bx], byte 0

#546 je .found

#547 add bx, open_file_t_size ; ZF = 0

#548 loop .check

#549 ;
ZF = 0 if we fell out of the loop

#550 .found:

#551 pop cx

#552 ret

#553

#554 ;

#555 ; iso_compare_names:

#556 ; Compare
the names DS:SI and DS:DI and report if they are

#557 ; equal
from an ISO 9660 perspective. SI is the
name from

#558 ; the
filesystem; CX indicates its length, and ';' terminates.

#559 ; DI
is expected to end with a null.

#560 ;

#561 ; Note:
clobbers AX, CX, SI, DI; assumes DS == ES == base segment

#562 ;

#563 iso_compare_names:

#564 ;
First, terminate and canonicalize input filename

#565 push di

#566 mov di, ISOFileName

#567 .canon_loop:

#568 jcxz .canon_end

#569 lodsb

#570 dec cx

#571 cmp al, ';'

#572 je .canon_end

#573 and al, al

#574 je .canon_end

#575 stosb

#576 cmp di, ISOFileNameEnd-1 ; Guard against buffer overrun

#577 jb .canon_loop

#578 .canon_end:

#579 cmp di, ISOFileName

#580 jbe .canon_done

#581 cmp byte [di-1], '.' ; Remove terminal dots

#582 jne .canon_done

#583 dec di

#584 jmp short .canon_end

#585 .canon_done:

#586 mov [di], byte 0 ;
Null-terminate string

#587 pop di

#588 mov si, ISOFileName

#589 .compare:

#590 lodsb

#591 mov ah, [di]

#592 inc di

#593 and ax, ax

#594 jz .success ;
End of string for both

#595 and al, al ;
Is either one end of string?

#596 jz .failure ;
If so, failure

#597 and ah, ah

#598 jz .failure

#599 or ax, 2020h ;
Convert to lower case

#600 cmp al, ah

#601 je .compare

#602 .failure:

#603 and ax, ax ;
ZF = 0 (at least one will be nonzero)

#604 .success:

#605 ret

#606

#607

#608

#609

#610

#611

#612

#613 ;

#614 ; getfssec: Get multiple clusters from a
file, given the file pointer.

#615 ;

#616 ; On
entry:

#617 ; ES:BX -> Buffer

#618 ; SI -> File pointer

#619 ; CX -> Cluster count; 0FFFFh = until end of
file

#620 ; On
exit:

#621 ; SI -> File pointer (or 0 on EOF)

#622 ; CF
= 1 -> Hit EOF

#623 ;

#624 getfssec:

#625 cmp cx, [si+file_left]

#626 jna .ok_size

#627 mov cx, [si+file_left]

#628

#629 .ok_size:

#630 mov bp, cx

#631 push cx

#632 push si

#633 mov eax, [si+file_sector]

#634 call getlinsec

#635 xor ecx, ecx

#636 pop si

#637 pop cx

#638

#639 add [si+file_sector], ecx

#640 sub [si+file_left], ecx

#641 ja .not_eof ;
CF = 0

#642

#643 xor ecx, ecx

#644 mov [si+file_sector], ecx ; Mark as unused

#645 xor si,si

#646 stc

#647

#648 .not_eof:

#649 ret

#650

#651

#652

#653 ; INT 13h, AX=4B01h, DL=<passed in
value> failed.

#654 ; Try to scan the entire 80h-FFh from the
end.

#655 spec_query_failed:

#656 mov si,spec_err_msg

#657 call writemsg

#658

#659 mov dl, 0FFh

#660 .test_loop:

#661 pusha

#662 mov ax, 4B01h

#663 mov si, spec_packet

#664 mov byte [si], 13 ;
Size of buffer

#665 int 13h

#666 popa

#667 jc .still_broken

#668

#669 mov si, maybe_msg

#670 call writemsg

#671 mov al, dl

#672 call writehex2

#673 call crlf

#674

#675 cmp byte [sp_drive], dl

#676 jne .maybe_broken

#677

#678 ;
Okay, good enough...

#679 mov si, alright_msg

#680 call writemsg

#681 mov [DriveNo], dl

#682 .found_drive:

#683 jmp found_drive

#684

#685 ;
Award BIOS 4.51 apparently passes garbage in sp_drive,

#686 ;
but if this was the drive number originally passed in

#687 ;
DL then consider it "good enough"

#688 .maybe_broken:

#689 cmp byte [DriveNo], dl

#690 je .found_drive

#691

#692 .still_broken:

#693 dec
dx

#694 cmp dl, 80h

#695 jnb .test_loop

#696

#697 fatal_error:

#698 mov si, nothing_msg

#699 call writemsg

#700

#701 .norge:

#702 jmp short .norge

#703

#704

#705

#706 ;
Information message (DS:SI) output

#707 ;
Prefix with "isolinux: "

#708 ;

#709 writemsg:

#710 push ax

#711 push si

#712 mov si, isolinux_str

#713 call writestr

#714 pop si

#715 call writestr

#716 pop ax

#717 ret

#718

#719 ;

#720 ; crlf: Print a newline

#721 ;

#722 crlf:

#723 mov si, crlf_msg

#724 ;
Fall through

#725

#726 ;

#727 ; writestr: write a null-terminated string to
the console, saving

#728 ;
registers on entry.

#729 ;

#730 writestr:

#731 pushfd

#732 pushad

#733 .top:

#734 lodsb

#735 and al, al

#736 jz .end

#737 call writechr

#738 jmp short .top

#739 .end:

#740 popad

#741 popfd

#742 ret

#743

#744

#745 ;

#746 ; writehex[248]: Write a hex number in (AL,
AX, EAX) to the console

#747 ;

#748 writehex2:

#749 pushfd

#750 pushad

#751 shl eax, 24

#752 mov cx, 2

#753 jmp short writehex_common

#754 writehex4:

#755 pushfd

#756 pushad

#757 shl eax, 16

#758 mov cx, 4

#759 jmp short writehex_common

#760 writehex8:

#761 pushfd

#762 pushad

#763 mov cx, 8

#764 writehex_common:

#765 .loop:

#766 rol eax, 4

#767 push eax

#768 and al, 0Fh

#769 cmp al, 10

#770 jae .high

#771 .low:

#772 add al, '0'

#773 jmp short .ischar

#774 .high:

#775 add al, 'A'-10

#776 .ischar:

#777 call writechr

#778 pop eax

#779 loop .loop

#780 popad

#781 popfd

#782 ret

#783

#784 ;

#785 ; Write a character to the screen. There is a more "sophisticated"

#786 ; version of this in the subsequent code, so
we patch the pointer

#787 ; when appropriate.

#788 ;

#789

#790 writechr:

#791 pushfd

#792 pushad

#793 mov ah, 0Eh

#794 xor bx, bx

#795 int 10h

#796 popad

#797 popfd

#798 ret

#799

#800 ;

#801 ; Get one sector. Convenience entry point.

#802 ;

#803 getonesec:

#804 mov bp, 1

#805 ;
Fall through to getlinsec

#806

#807 ;

#808 ; Get linear sectors - EBIOS LBA addressing,
2048-byte sectors.

#809 ;

#810 ; Note that we can't always do this as a
single request, because at least

#811 ; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick

#812 ; to 32 sectors (64K) per request.

#813 ;

#814 ; Input:

#815 ; EAX - Linear sector number

#816 ; ES:BX - Target buffer

#817 ; BP - Sector count

#818 ;

#819 getlinsec:

#820 mov
si,dapa ; Load up the DAPA

#821 mov
[si+4],bx

#822 mov
bx,es

#823 mov
[si+6],bx

#824 mov
[si+8],eax

#825 .loop2:

#826 push
bp ; Sectors left

#827 cmp
bp,[MaxTransfer]

#828 jbe
.bp_ok

#829 mov
bp,[MaxTransfer]

#830 .bp_ok:

#831 mov
[si+2],bp

#832 push
si

#833 mov
dl,[DriveNo]

#834 mov
ah,42h ; Extended Read

#835 call
xint13

#836 pop
si

#837 pop
bp

#838 movzx
eax,word [si+2] ; Sectors we read

#839 add
[si+8],eax ; Advance
sector pointer

#840 sub
bp,ax ; Sectors left

#841 shl
ax,SECTORSIZE_LG2-4 ; 2048-byte
sectors -> segment

#842 add
[si+6],ax ; Advance buffer
pointer

#843 and
bp,bp

#844 jnz
.loop2

#845 mov
eax,[si+8] ; Next
sector

#846 ret

#847

#848 ;
INT 13h with retry

#849 xint13:

#850 mov byte [RetryCount], retry_count

#851 .try:

#852 pushad

#853 int 13h

#854 jc .error

#855 add sp, byte 8*4 ;
Clean up stack

#856 ret

#857 .error:

#858 mov [DiskError], ah ;
Save error code

#859 popad

#860 dec
byte [RetryCount]

#861 jz
.real_error

#862 push
ax

#863 mov
al,[RetryCount]

#864 mov
ah,[dapa+2] ; Sector
transfer count

#865 cmp
al,2 ; Only 2 attempts left

#866 ja
.nodanger

#867 mov
ah,1 ; Drop transfer
size to 1

#868 jmp
short .setsize

#869 .nodanger:

#870 cmp
al,retry_count-2

#871 ja
.again ; First time, just
try again

#872 shr
ah,1 ; Otherwise, try to
reduce

#873 adc
ah,0 ; the max
transfer size, but not to 0

#874 .setsize:

#875 mov
[MaxTransfer],ah

#876 mov
[dapa+2],ah

#877 .again:

#878 pop
ax

#879 jmp
.try

#880

#881 .real_error:

#882 mov si, diskerr_msg

#883 call writemsg

#884 mov al, [DiskError]

#885 call writehex2

#886 mov si, ondrive_str

#887 call writestr

#888 mov al, dl

#889 call writehex2

#890 call crlf

#891 ;
Fall through to kaboom

#892

#893 ;

#894 ; kaboom: write a message and bail out. Wait for a user keypress,

#895 ; then do a hard reboot.

#896 ;

#897 kaboom:

#898 mov ax, cs

#899 mov ds, ax

#900 mov es, ax

#901 mov fs, ax

#902 mov gs, ax

#903 sti

#904 mov si, err_bootfailed

#905 call writestr

#906 call getchar

#907 cli

#908 mov word [BIOS_magic], 0 ; Cold reboot

#909 jmp 0F000h:0FFF0h ; Reset vector address

#910

#911 getchar:

#912 .again:

#913 mov ah, 1 ;
Poll keyboard

#914 int 16h

#915 jz .again

#916 .kbd:

#917 xor ax, ax ;
Get keyboard input

#918 int 16h

#919 .func_key:

#920 ret

#921

#922

#923 ;

#924 ; pollchar: check if we have an input
character pending (ZF = 0)

#925 ;

#926 pollchar:

#927 pushad

#928 mov
ah,1 ; Poll keyboard

#929 int
16h

#930 popad

#931 ret

#932

#933

#934

#935 isolinux_banner db CR, LF, 'Loading IsoBoot...', CR, LF, 0

#936 copyright_str db
' Copyright (C) 1994-2002 H. Peter Anvin', CR, LF, 0

#937 presskey_msg db
'Press any key to boot from CD', 0

#938 dot_msg db
'.',0

#939

#940 %ifdef DEBUG_MESSAGES

#941 startup_msg: db
'Starting up, DL = ', 0

#942 spec_ok_msg: db
'Loaded spec packet OK, drive = ', 0

#943 secsize_msg: db
'Sector size appears to be ', 0

#944 rootloc_msg: db
'Root directory location: ', 0

#945 rootlen_msg: db
'Root directory length: ', 0

#946 rootsect_msg: db
'Root directory length(sectors): ', 0

#947 fileloc_msg: db
'SETUPLDR.SYS location: ', 0

#948 filelen_msg: db
'SETUPLDR.SYS length: ', 0

#949 filesect_msg: db
'SETUPLDR.SYS length(sectors): ', 0

#950 findfail_msg: db
'Failed to find file!', 0

#951 startldr_msg: db
'Starting SETUPLDR.SYS', 0

#952 %endif

#953

#954 nosecsize_msg: db 'Failed to get sector size, assuming 0800', CR, LF, 0

#955 spec_err_msg: db
'Loading spec packet failed, trying to wing it...', CR, LF, 0

#956 maybe_msg: db
'Found something at drive = ', 0

#957 alright_msg: db
'Looks like it might be right, continuing...', CR, LF, 0

#958 nothing_msg: db
'Failed to locate CD-ROM device; boot failed.', CR, LF, 0

#959 isolinux_str db
'IsoBoot: ', 0

#960 crlf_msg db
CR, LF, 0

#961 diskerr_msg: db 'Disk error ', 0

#962 ondrive_str: db
', drive ', 0

#963 err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'

#964 isolinux_dir db
'/LOADER', 0

#965 no_dir_msg db
'Could not find the LOADER directory.', CR, LF, 0

#966 isolinux_bin db
'SETUPLDR.SYS', 0

#967 no_isolinux_msg db 'Could not find SETUPLDR.SYS.', CR, LF, 0

#968

#969 ;

#970 ; El Torito spec packet

#971 ;

#972 align
8, db 0

#973 spec_packet: db
13h ; Size of
packet

#974 sp_media: db
0 ; Media type

#975 sp_drive: db
0 ; Drive
number

#976 sp_controller: db 0 ;
Controller index

#977 sp_lba: dd
0 ; LBA for
emulated disk image

#978 sp_devspec: dw
0 ; IDE/SCSI
information

#979 sp_buffer: dw
0 ;
User-provided buffer

#980 sp_loadseg: dw
0 ; Load
segment

#981 sp_sectors: dw
0 ; Sector
count

#982 sp_chs: db
0,0,0 ; Simulated CHS
geometry

#983 sp_dummy: db
0 ; Scratch,
safe to overwrite

#984

#985 ;

#986 ; EBIOS drive parameter packet

#987 ;

#988 align
8, db 0

#989 drive_params: dw
30 ; Buffer size

#990 dp_flags: dw
0 ; Information
flags

#991 dp_cyl: dd
0 ; Physical
cylinders

#992 dp_head: dd
0 ; Physical
heads

#993 dp_sec: dd
0 ; Physical sectors/track

#994 dp_totalsec: dd
0,0 ; Total
sectors

#995 dp_secsize: dw
0 ; Bytes per
sector

#996 dp_dpte: dd
0 ; Device
Parameter Table

#997 dp_dpi_key: dw
0 ; 0BEDDh if
rest valid

#998 dp_dpi_len: db 0 ;
DPI len

#999 db
0

#1000 dw
0

#1001 dp_bus: times
4 db 0 ; Host bus type

#1002 dp_interface: times
8 db 0 ; Interface type

#1003 db_i_path: dd
0,0 ; Interface
path

#1004 db_d_path: dd
0,0 ; Device path

#1005 db
0

#1006 db_dpi_csum: db
0 ; Checksum
for DPI info

#1007

#1008 ;

#1009 ; EBIOS disk address packet

#1010 ;

#1011 align
8, db 0

#1012 dapa: dw
16 ; Packet size

#1013 .count: dw
0 ; Block count

#1014 .off: dw
0 ; Offset of
buffer

#1015 .seg: dw
0 ; Segment of
buffer

#1016 .lba: dd
0 ; LBA (LSW)

#1017 dd
0 ; LBA (MSW)

#1018

#1019 alignb
4, db 0

#1020 MaxTransfer dw
2 ;32 ; Max sectors
per transfer

#1021

#1022 times
2046-($-$$) db 0 ; Pad to file
offset 2046

#1023 dw
0aa55h ; BootSector
signature

#1024

上面分析了光盘引导程序,知道怎么跳转到二级引导程序工作。也就是加载SETUPLDR.SYS文件到内存,然后跳到相应位置运行。最后加载内核ntoskrnl.exe运行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: