reactos操作系统实现(47)
当光盘变成记录数据以后,就开始使用光盘来分发操作系统了。毕竟光盘有着储存数据量大,成本便宜的优势。下面就来分析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,0 #936 copyright_str db ' Copyright (C) 1994-2002 H. Peter Anvin',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',0 #955 spec_err_msg: db 'Loading spec packet failed,trying to wing it...',0 #956 maybe_msg: db 'Found something at drive = ',0 #957 alright_msg: db 'Looks like it might be right,continuing...',0 #958 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.',0 #959 isolinux_str db 'IsoBoot: ',0 #960 crlf_msg db CR,0 #961 diskerr_msg: db 'Disk error ',0 #962 ondrive_str: db ',drive ',0 #963 err_bootfailed db CR,'Boot failed: press a key to retry...' #964 isolinux_dir db '/LOADER',0 #965 no_dir_msg db 'Could not find the LOADER directory.',0 #966 isolinux_bin db 'SETUPLDR.SYS',0 #967 no_isolinux_msg db 'Could not find SETUPLDR.SYS.',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 ; 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运行。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |