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

reactos操作系统实现(47)

2009-07-22 20:14 369 查看
当光盘变成记录数据以后,就开始使用光盘来分发操作系统了。毕竟光盘有着储存数据量大,成本便宜的优势。下面就来分析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运行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: