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= 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运行。

转载于:https://www.cnblogs.com/ajuanabc/archive/2009/07/22/2463788.html

你可能感兴趣的:(reactos操作系统实现(47))