阅读:6700回复:6
我把NTLDR的源代码贴上来,大家一起来讨论分析吧!
;++
; ; Module name ; ; su.asm ; ; Author ; ; Thomas Parslow (tomp) Jan-15-91 ; ; Description ; ; Startup module for the 386 NT OS loader. ; ; Exported Procedures ; ; EnableProtectPaging ; ; Notes ; NT386 Boot Loader program. This assembly file is required in ; order to link C modules into a \"/TINY\" (single segment) memory ; model. ; ; ; ** WHAT\'S MISSING ** ; Still need to add: ; o a20 enable code ; o compaq speed code (??) ; o low/high memory size determination ; ; ; ; This file does the following: ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; 1) Defines the entry point for the boot loader\'s startup program ; 2) Computes what values should actually be in the DS and SS registers. ; 3) Provides the int bios functionality ; 4) Provides 386/486 mode (protect/paging) switching code. ; ; The OS/2 bootstrap routine (boot sector) loads the boot loader program at ; real-mode address 2000:0000 with the following register values: ; ; CS = 2000 ; IP = 0000 ; DS = 07C0 ; ES = 1000 ; SS = 0000 ; SP = 7C00 ; ; Build Notes: ; ~~~~~~~~~~~~ ; The microsoft C compiler will not produce \"tiny\" model programs. In the ; tiny model, the entire program consists of only one segment. The small ; model produced by our compilers consists of two segments: DGROUP and _TEXT. ; If you convert a small model program into a tiny model program, DS (which ; should point to DGROUP (bss,const,data) will always be wrong. For this reason ; we need an assembly module to do a simple run-time fixup on SS and DS. To ; guarantee that DS will point to DGROUP no matter where os2ldr is loaded, ; the paragraph (shifted right four bits) offset of DGROUP from _TEXT must ; be added to the value in CS to compute DS and SS. ; ; We get the linker to fixup the offset of the beginning of the dgroup segment ; relative to the beginning of the code segment and it\'s this value added ; to the value in CS that allows us to build a \"tiny\" model program in C ; without a lot of munging around in order to get the data reference offsets ; in the code correct. ; ; If the _TEXT:DGROUP fixup appears in other files (which it does), the linker ; will not compute the correct value unless the accumulated data pointer is ; zero when it gets there. Therefore, no data should be placed in the data segment ; until after all instances of _TEXT:DGROUP have been encountered by the linker. ; The linker processes files from right to left on the command line. ; ; A Note About Stacks ; Initially we run on our internal stack (SuStack) which is only 160 bytes deep ; but seems to do the trick. Then we have to have a separate double fault stack. ; This stack can be in the middle of the stack/data segment. It will step on ; the loader image, but that\'s ok since the fault was either caused by 16bit ; code (which won\'t be in the loader image) or, it was caused by the 32bit ; loader (which has already been relocated) so we won\'t be stepping on code ; that may have caused the fault. And finally, we have the \"call back\" stack ; which starts at the top of the stack/data segment. We use this during ; all call backs since the original loader source is no longer needed and ; this\'ll give us plenty of stack for bios calls etc. ; ;-- DoubleWord struc lsw dw ? msw dw ? DoubleWord ends ; ; This is the structure used to pass all shared data between the boot sector ; and NTLDR. ; SHARED struc ReadClusters dd ? ; function pointer ReadSectors dd ? ; function pointer SectorBase dd ? ; starting sector ; for ReadSectors ; callback SHARED ends BPB struc BytesPerSector dw ? SectorsPerCluster db ? ReservedSectors dw ? Fats db ? DirectoryEntries dw ? Sectors dw ? Media db ? FatSectors dw ? SectorsPerTrack dw ? Heads dw ? HiddenSectors dd ? SectorsLong dd ? ; ; The following byte is NOT part of the BPB but is set by SYS and format ; BootDriveNumber db ? BPB ends SU_CODEMODULE equ 1 ; Identifies this module to \"su.inc\" include su.inc include macro.inc extrn _BootRecord:word extrn _puts:near extrn _MemoryDescriptorList:near extrn _InsertDescriptor:near MAXREAD EQU 10000h MAXSECTORS EQU MAXREAD/0200h _TEXT segment para use16 public \'CODE\' ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP .386p ; ; Run-time fixups for stack and data segment ; public Start Start: ; ; The FAT boot sector only reads in the first 512 bytes of NTLDR. This is ; the module that contains those 512 bytes, so we are now responsible for ; loading the rest of the file. Other filesystems (i.e. HPFS, NTFS, RIPL) ; will load the whole file, so the default entrypoint branches around the ; FAT-specific code. ; jmp RealStart FatBegin: .386 ; ; If we\'re here, we\'ve booted off a FAT system and we must load the rest ; of NTLDR at 2000:0200 (right behind this sector) NTLDR passes us the ; following: ; BX = Starting Cluster Number of NTLDR ; DL = INT 13h drive number we\'ve booted from ; DS:SI -> boot media\'s BPB ; DS:DI -> argument structure (see above struc definition) ; ; ; Save away the boot drive and the starting cluster number ; push dx push bx ; ; Blast the FAT into memory at 6000:0000 - 8000:0000 ; .386 push 06000h .8086 pop es xor bx,bx ; (es:bx) = 6000:0000 mov cx,ds:[si].ReservedSectors mov ds:[di].SectorBase.msw,0 mov ds:[di].SectorBase.lsw,cx ; set up Sector Base mov ax,ds:[si].FatSectors ; (al) = # Sectors to read cmp ax,080h jbe FatLt64k ; The FAT is > 64k, so we read the first 64k chunk, then the rest. ; (A 16-bit FAT can\'t be bigger than 128k) push cx mov ax,080h ; (al) = # of sectors to read call ds:[di].ReadSectors pop cx ; (cx) = previous SectorBase .386 push 07000h .8086 pop es xor bx,bx ; (es:bx) = 7000:0000 mov ax,ds:[si].FatSectors sub ax,080h ; (ax) = # Sectors left to read add cx,080h ; (cx) = SectorBase for next read mov ds:[di].SectorBase.lsw,cx adc ds:[di].SectorBase.msw,0 ; set up SectorBase ; ; (al) = # of sectors to read ; FatLt64k: call ds:[di].ReadSectors ; ; FAT is in memory, now we restore our starting cluster number ; pop dx ; (dx) = starting cluster number xor bx,bx ; ; set up FS and GS for reading the FAT ; .386 mov ax,6000h mov fs,ax mov ax,7000h mov gs,ax .8086 ; ; set up ES for reading in the rest of us ; push cs pop es mov ah,MAXSECTORS ; (ah) = number of sectors we can read ; until boundary FatLoop: ; ; (dx) = next cluster to load ; push dx mov al,ds:[si].SectorsPerCluster ; (al) = number of contiguous sectors ; found sub ah,ds:[si].SectorsPerCluster ; can read before 64k ; ; Check to see if we\'ve reached the end of the file ; cmp dx,0ffffh jne Fat10 ; ; The entire file has been loaded. Throw away the saved next cluster, ; restore the boot drive, and let NTLDR do its thing. ; pop dx pop dx jmp RealStart Fat10: mov cx,dx ; ; (dx) = (cx) = last contiguous cluster ; (al) = # of contiguous clusters found ; call NextFatEntry ; ; (dx) = cluster following last contiguous cluster ; ; Check to see if the next cluster is contiguous. If not, go load the ; contiguous block we\'ve found. ; inc cx cmp dx,cx jne LncLoad ; ; Check to see if we\'ve reached the 64k boundary. If so, go load the ; contiguous block so far. If not, increment the number of contiguous ; sectors and loop again. ; cmp ah,0 jne Lnc20 mov ah,MAXSECTORS ; (ah) = number of sectors until ; boundary reached again jmp short LncLoad Lnc20: add al,ds:[si].SectorsPerCluster sub ah,ds:[si].SectorsPerCluster jmp short Fat10 LncLoad: ; ; (TOS) = first cluster to load ; (dx) = first cluster of next group to load ; (al) = number of contiguous sectors ; pop cx push dx mov dx,cx mov cx,10 ; (cx) = retry count ; ; N.B. ; This assumes that we will never have more than 255 contiguous clusters. ; Since that would get broken up into chunks that don\'t cross the 64k ; boundary, this is ok. ; ; (dx) = first cluster to load ; (al) = number of contiguous sectors ; (TOS) = first cluster of next group to load ; (es:bx) = address where clusters should be loaded ; FatRetry: push bx push ax push dx push cx if 0 push dx call PrintDbg mov dx,ax call PrintDbg pop dx endif call [di].ReadClusters jnc ReadOk ; ; error in the read, reset the drive and try again ; if 0 mov dx, ax call PrintDbg endif mov ax,01h mov al,ds:[si].BootDriveNumber int 13h if 0 mov dx,ax call PrintDbg endif xor ax,ax mov al,ds:[si].BootDriveNumber int 13h ; ; pause for a while ; xor ax,ax FatPause: dec ax jnz FatPause pop cx pop dx pop ax pop bx dec cx jnz FatRetry ; ; we have re-tried ten times, it still doesn\'t work, so punt. ; push cs pop ds mov si,offset FAT_ERROR FatErrPrint: lodsb or al,al jz FatErrDone mov ah,14 ; write teletype mov bx,7 ; attribute int 10h ; print it jmp FatErrPrint FatErrDone: jmp $ FAT_ERROR db \"NTLDR: I/O error reading disk\",0dh,0ah db \" Please insert another disk\",0dh,0ah,0 ReadOk: pop cx pop dx pop ax pop bx pop dx ; (dx) = first cluster of next group ; to load. .386 ; ; Convert # of sectors into # of bytes. ; mov cl,al xor ch,ch shl cx,9 .8086 add bx,cx jz FatLoopDone jmp FatLoop FatLoopDone: ; ; (bx) = 0 ; This means we\'ve just ended on a 64k boundary, so we have to ; increment ES to continue reading the file. We are guaranteed to ; always end on a 64k boundary and never cross it, because we ; will reduce the number of contiguous clusters to read ; to ensure that the last cluster read will end on the 64k boundary. ; Since we start reading at 0, and ClusterSize will always be a power ; of two, a cluster will never cross a 64k boundary. ; mov ax,es add ax,01000h mov es,ax mov ah,MAXSECTORS jmp FatLoop ;++ ; ; NextFatEntry - This procedure returns the next cluster in the FAT chain. ; It will deal with both 12-bit and 16-bit FATs. It assumes ; that the entire FAT has been loaded into memory. ; ; Arguments: ; (dx) = current cluster number ; (fs:0) = start of FAT in memory ; (gs:0) = start of second 64k of FAT in memory ; ; Returns: ; (dx) = next cluster number in FAT chain ; (dx) = 0ffffh if there are no more clusters in the chain ; ;-- NextFatEntry proc near push bx ; ; Check to see if this is a 12-bit or 16-bit FAT. The biggest FAT we can ; have for a 12-bit FAT is 4080 clusters. This is 6120 bytes, or just under ; 12 sectors. ; ; A 16-bit FAT that\'s 12 sectors long would only hold 3072 clusters. Thus, ; we compare the number of FAT sectors to 12. If it\'s greater than 12, we ; have a 16-bit FAT. If it\'s less than or equal to 12, we have a 12-bit FAT. ; call IsFat12 jnc Next16Fat Next12Fat: mov bx,dx ; (fs:bx) => temporary index shr dx,1 ; (dx) = offset/2 ; (CY) = 1 need to shift pushf ; = 0 don\'t need to shift add bx,dx ; (fs:bx) => next cluster number .386 mov dx,fs:[bx] ; (dx) = next cluster number .8086 popf jc shift ; carry flag tells us whether to and dx,0fffh ; mask jmp short N12Tail shift: .386 shr dx,4 ; or shift .8086 N12Tail: ; ; Check for end of file ; cmp dx,0ff8h ; If we\'re at the end of the file, jb NfeDone ; convert to canonical EOF. mov dx,0ffffh jmp short NfeDone Next16Fat: add dx,dx ; (dx) = offset jc N16high mov bx,dx ; (fs:bx) => next cluster number .386 mov dx,fs:[bx] ; (dx) = next cluster number .8086 jmp short N16Tail N16high: mov bx,dx .386 mov dx,gs:[bx] .8086 N16Tail: cmp dx,0fff8h jb NfeDone mov dx,0ffffh ; If we\'re at the end of the file ; convert to canonical EOF. NfeDone: pop bx ret NextFatEntry endp ;++ ; ; IsFat12 - This function determines whether the BPB describes a 12-bit ; or 16-bit FAT. ; ; Arguments - ds:si supplies pointer to BPB ; ; Returns ; CY set - 12-bit FAT ; CY clear - 16-bit FAT ; ;-- IsFat12 proc near .386 push eax push ebx push ecx push edx movzx ecx, ds:[si].Sectors or cx,cx jnz if10 mov ecx, ds:[si].SectorsLong if10: ; ; (ecx) = number of sectors ; movzx ebx, byte ptr ds:[si].Fats movzx eax, word ptr ds:[si].FatSectors mul ebx sub ecx,eax ; ; (ecx) = (#sectors)-(sectors in FATs) ; movzx eax, word ptr ds:[si].DirectoryEntries shl eax, 5 ; ; (eax) = #bytes in root dir ; mov edx,eax and edx,0ffff0000h div word ptr ds:[si].BytesPerSector sub ecx,eax ; ; (ecx) = (#sectors) - (sectors in fat) - (sectors in root dir) ; movzx eax, word ptr ds:[si].ReservedSectors sub ecx, eax mov eax, ecx movzx ecx, byte ptr ds:[si].SectorsPerCluster xor edx,edx div ecx cmp eax, 4087 jae if20 stc jmp short if30 if20: clc if30: pop edx pop ecx pop ebx pop eax ret .8086 IsFat12 endp PrintDbg proc near push ax push bx push cx mov cx,4 pd10: .386 rol dx,4 .8086 mov ah,0eh mov bx,7 mov al,dl and al,0fh add al,\'0\' cmp al,\'9\' jbe pd15 add al,\'A\'-(\'9\'+1) pd15: int 010h loop pd10 mov ah,0eh mov al,\' \' mov bx,7 int 010h pop cx pop bx pop ax ret PrintDbg endp Free EQU 512-($-Start) if Free lt 0 %out FATAL PROBLEM: FAT-specific startup code is greater than %out 512 bytes. Fix it! .err endif RealStart: .386p ; ; Compute the paragraph needed for DS ; if 0 mov ax,0 int 16h endif mov bx,offset _TEXT:DGROUP ; first calculate offset to data shr bx,4 ; must be para aligned mov ax,cs ; get base of code add ax,bx ; add paragraph offset to data mov ss,ax ; ints disabled for next instruct mov sp,offset DGROUP:SuStack ; (sp) = top of internal stack ; ; Build C stack frame for _SuMain ; xor dh,dh push dx ; pass bootdisk (dl) to main. push ds ; segment of bios parameter block push si ; offset to bios parameter block push es ; segment of root directory push di ; offset to root directory ; ; Make DS point to the paragraph address of DGROUP ; mov ds,ax ; ds now points to beginning of DGROUP ; ; Compute the physical address of the end of the data segment (which ; will be the beginning of the prepended loader file). ; movzx edx,ax shl edx,4 add edx,offset DGROUP:_edata mov dword ptr _FileStart,edx ; ; Force the upper parts of ; of EBP and ESP to be zero in real mode. ; xor bp,bp movzx ebp,bp movzx esp,sp mov [saveDS],ds call _SuMain ; go to C code to do everything else. ;++ ; _EnableProtectPaging ; ; Loads 386 protect mode registers. ; Enables 386 protection h/w ; Loads pagings registers ; Enables 386 paging h/w ; ;-- public _EnableProtectPaging _EnableProtectPaging proc near ; ; Sanitize ES and GS and clean out any junk in the upper 16bits ; of the flags that may have been left by the bios, before we go protected ; push dword ptr 0 popfd mov bx,sp mov dx,[bx+2] ; are we enabling prot/paging for the first time? xor ax,ax mov gs,ax mov es,ax ; ; FS must contain the selector of the PCR when we call the kernel ; push PCR_Selector pop fs ; ; Load the gdtr and idtr. ; We disable interrupts here since we can\'t handle interrups with the ; idt loaded while were in real mode and before we switch to protmode. cli lgdt fword ptr [_GDTregister] lidt fword ptr [_IDTregister] ; ; We have to stamp the segment portion of any real-mode far pointer with ; the corresponding selector values before we go protected. ; mov si,offset _ScreenStart mov word ptr [si+2],VideoSelector mov si,offset _vp mov word ptr [si+2],VideoSelector ; ; Enable protect and paging mode ; mov eax,cr0 ; If we\'re enabling protect mode for the first time, don\'t turn on paging ; because the osloader does all that. However, if we\'re returning to ; protected mode, the page tables are already setup, therefore we do want ; to turn paging on. or dx,dx jz only_prot or eax,PROT_MODE + ENABLE_PAGING mov cr0,eax ; ; The following JMP must be DWORD-aligned in order to avoid an obscure i386 ; hardware bug. If not, it is possible (albeit unlikely) that the prefetch ; queue can get trashed. ; ALIGN 4 jmp flush only_prot: or eax,PROT_MODE mov cr0,eax ; ; Flush the prefetch queue ; ALIGN 4 jmp flush flush: ; ; Load CS with the SU module\'s code selector ; push SuCodeSelector push offset cs:restart retf ; ; Now load DS and SS with the SU module\'s protect mode data selector. ; restart: mov ax,SuDataSelector mov ds,ax mov ss,ax ; ; Load LDT with zero since it will never be used. ; xor bx,bx lldt bx ; ; Load the Task Register and return to the boot SU module. ; or dx,dx jnz epp10 mov bx,TSS_Selector ltr bx epp10: ret _EnableProtectPaging endp .286p ;** _biosint ; ; Rom bios interrupt dispatcher ; public _biosint _biosint proc near enter 0,0 push di push si push ds push es ; Get pointer to register parameter frame les di,[bp+4] ; Get requested interrupt number mov ax,es:[di].intnum ; Check that requested bios interrupt is supported sub ax,10h ; sub lowest int number supported jnc short bios1 mov es:[di].intnum,FUNCTION_ERROR jmp short biosx bios1: shl ax,1 ; shift if to make it a word offset cmp ax,bios_cnt ; offset beyond end of table? jb short bios2 ; Error: requested interrupt not supported mov es:[di].sax,FUNCTION_ERROR jmp short biosx bios2: mov bx,ax mov ax,word ptr cs:bios_table[bx] push es ; save seg of address frame push di ; save stack register frame pointer push ax ; address of bios int mov ax,es:[di].sax mov bx,es:[di].sbx mov cx,es:[di].scx mov dx,es:[di].sdx mov si,es:[di].ssi mov es,es:[di].ses ret ; this sends us to the \"int #\" instruction ; We return here from the jmp instruction following the int bios_ret: pop di ; get address of register parameter frame pop es ; restore segment of parameter frame bios5: pushf pop es:[di].sfg mov es:[di].sax,ax mov es:[di].sbx,bx mov es:[di].scx,cx mov es:[di].sdx,dx mov es:[di].ssi,si mov es:[di].ses,es ; Restore original registers and return to caller biosx: pop es pop ds pop si pop di leave ret _biosint endp ;** Bios Interrupt Table ; bios10: int 10h jmp short bios_ret bios11: int 11h jmp short bios_ret bios12: int 12h jmp short bios_ret bios13: int 13h jmp short bios_ret bios14: int 14h jmp short bios_ret bios15: int 15h jmp short bios_ret bios16: int 16h jmp short bios_ret bios17: int 17h jmp short bios_ret bios18: int 18h jmp short bios_ret bios19: int 19h jmp short bios_ret bios_table dw bios10,bios11,bios12,bios13,bios14,bios15,bios16,bios17,bios18,bios19 bios_cnt equ $ - bios_table .386p ;++ ; ; _MoveMemory ; ; Routine Description ; ; Moves dwords in memory from source to destination. ; ; Arguments ; ; (TOS+4) = number of bytes to move ; (TOS+8) = linear address of destination ; (TOS+12) = linear address of source ; ; Notes ; ; 1) Valid page table entries must already exist for the ; source and destination memory. ; ; 2) ALL memory in the lower one megabyte is assumed to ; be identity mapped if used. ; ; USES ESI, EDI, ECX, FLAGS ; ; ;-- public _MoveMemory _MoveMemory proc near enter 0,0 push ds push es ; ; Get source, destination, and count arguments from the stack ; Make \"count\" the number of dwords to move. ; mov esi,dword ptr [bp+4] mov edi,dword ptr [bp+8] mov ecx,dword ptr [bp+12] shr ecx,2 ; ; Load FLAT selectors into DS and ES ; mov ax,KeDataSelector mov ds,ax mov es,ax ; ; Move the block of data. ; assume es:FLAT, ds:FLAT ; ; move the dwords ; cld rep movs dword ptr [edi],dword ptr [esi] ; ; move the remaining tail ; mov ecx, dword ptr [bp+12] and ecx, 3 rep movs byte ptr [edi],byte ptr [esi] assume es:nothing, ds:DGROUP pop es pop ds leave ret _MoveMemory endp ;++ ; ; _ZeroMemory ; ; Routine Description ; ; Writes zeros into memory at the target address. ; ; Arguments ; ; (TOS+4) = linear address of target ; (TOS+8) = number of bytes to zero ; ; Notes ; ; 1) Valid page table entries must already exist for the ; source and destination memory. ; ; 2) ALL memory in the lower one megabyte is assumed to ; be identity mapped if used. ; ; USES ESI, EDI, ECX, FLAGS ; ; ;-- public _ZeroMemory _ZeroMemory proc near enter 0,0 push es ; ; Get source, destination, and count arguments from the stack ; Make \"count\" the number of dwords to move. ; mov edi,dword ptr [bp+4] mov ecx,dword ptr [bp+8] shr ecx,2 ; ; Load FLAT selectors into DS and ES ; mov ax,KeDataSelector mov es,ax xor eax,eax ; ; Zero the the block of data. ; assume es:FLAT ; ; Zero the dwords ; cld rep stos dword ptr [edi] ; ; Zero the remaining bytes ; mov ecx, dword ptr [bp+8] and ecx, 3 rep stos byte ptr [edi] assume es:nothing, ds:DGROUP pop es leave ret _ZeroMemory endp ;++ ; ; Turn Floppy Drive Motor Off ; ;-- public _TurnMotorOff DriveControlRegister equ 3f2h ; Floppy control register _TurnMotorOff proc near mov dx,DriveControlRegister mov ax,0CH out dx,al ret _TurnMotorOff endp ; ; Note: we do not save and restore the gdt and idt values because they ; cannot change while external services are being used by the OS loader. ; This is because they MUST remain identity mapped until all mode ; switching has ceased. ; public _RealMode _RealMode proc near ; ; Switch to real-mode ; sgdt fword ptr [_GDTregister] sidt fword ptr [_IDTregister] push [saveDS] ; push this so we can get to it later mov ax,SuDataSelector mov es,ax mov fs,ax mov gs,ax mov eax,cr0 and eax, not (ENABLE_PAGING + PROT_MODE) mov cr0,eax ; ; flush the pipeline ; jmp far ptr here here: ; ; Flush TLB ; ; HACKHACK - We don\'t know where the page directory is, since it was ; allocated in the osloader. So we don\'t want to clear out cr3, ; but we DO want to flush the TLB.... ; mov eax,cr3 nop ; Fill - Ensure 13 non-page split nop ; accesses before CR3 load nop ; (P6 errata #11 stepping B0) nop mov cr3,eax ; ; switch to real mode addressing ; ; N. B. We need to do a far jump rather than a retf, because a retf will not ; reset the access rights to CS properly. ; db 0EAh ; JMP FAR PTR dw offset _TEXT:rmode ; 2000:rmode dw 02000h rmode: pop ax mov ds,ax mov ss,ax ; ; Stamp video pointers for real-mode use ; mov si,offset _ScreenStart mov word ptr [si+2],0b800h mov si,offset _vp mov word ptr [si+2],0b800h ; ; re-enable interrups ; lidt fword ptr [_IDTregisterZero] ; ; Re-enable interrupts ; sti ret _RealMode endp ;** _TransferToLoader - transfer control the the OS loader ; ; ; Arguments: ; ; None ; ; Returns: ; ; Does not return ; ;** public _TransferToLoader _TransferToLoader proc near ; generates a double fault for debug purposes ; mov sp,0 ; push 0 mov ebx,dword ptr [esp+2] ; get entrypoint arg xor eax,eax mov ax,[saveDS] ; ; Setup OS loader\'s stack. Compute FLAT model esp to id map to ; original stack. ; mov cx,KeDataSelector mov ss,cx mov esp,LOADER_STACK ;** TMP HACK *** BUGBUG BUGBUG ; ; Load ds and es with kernel\'s data selectors ; mov ds,cx mov es,cx ; ; Setup pointer to file system and boot context records ; ; Make a linear pointer to the Boot Context Record shl eax,4 xor ecx,ecx mov cx,offset _BootRecord add eax,ecx push eax push 1010h ; dummy return address. push 1010h ; dummy return address. ; ; Push 48bit address of loader entry-point ; db OVERRIDE push KeCodeSelector push ebx ; ; Pass control to the OS loader ; db OVERRIDE retf _TransferToLoader endp ;++ ; Description: ; ; Gets memory block sizes for memory from zero to one meg and ; from one meg to 64 meg. We do this by calling int 12h ; (get conventional memory size) and int 15h function 88h (get ; extended memory size). ; ; Arguments: ; ; None ; ; Returns: ; ; USHORT - Size of usable memory (in pages) ; ;-- public _IsaConstructMemoryDescriptors BmlTotal equ [bp-4] Func88Result equ [bp-6] _IsaConstructMemoryDescriptors proc near push bp ; save ebp mov bp, sp sub sp, 6 ; ; Initialize the MemoryList to start with a zero entry. (end-of-list) ; les si, dword ptr _MemoryDescriptorList xor eax,eax mov es:[si].BlockSize,eax mov es:[si].BlockBase,eax ; ; Get conventional (below one meg) memory size ; push es push si int 12h movzx eax,ax ; ; EAX is the number of 1k blocks, which we need to convert to the ; number of bytes. ; shl eax,10 push eax shr eax, 12 mov BmlTotal, eax xor eax,eax push eax call _InsertDescriptor add sp,8 ; ; Get extended memory size and fill-in the second descriptor ; mov ah,88h int 15h mov Func88Result,ax and eax,0ffffh ; ; EAX is the number of 1k blocks, which we need to convert to the ; number of bytes. ; shl eax,10 push eax shr eax,12 add BmlTotal, ax mov eax,0100000h push eax call _InsertDescriptor add sp,8 ; ; Try function E801, see if that is supported on this machine ; mov ax,0E801h int 15h jc short Isa50 cmp ax,Func88Result ; Is extended memory same as 88? je short Isa40 ; Yes, go add the rest cmp ax, (16-1) * 1024 ; Is extended memory exactly 16MB? jne short Isa50 ; No, conflict between 88 & E801 Isa40: ; ; Function looks like it worked ; ; AX = extended memory < 16M in 1k blocks ; BX = extended memory > 16M in 64k blocks ; and ebx,0ffffh jz short Isa50 shl ebx,16 ; ebx = memory > 16M in bytes (via E801) add ebx, 16*1024*1024 ; ebx = end of memory in bytes (via E801) mov ax, Func88Result and eax,0ffffh shl eax, 10 ; eax = memory > 1M in bytes (via 88) add eax, 1*1024*1024 ; eax = end of memory in bytes (via 88) sub ebx, eax ; ebx = memory above eax jbe short Isa50 ; if ebx <= eax, done push ebx shr ebx,12 add BmlTotal, bx push eax call _InsertDescriptor add sp,8 and eax,0ffffh Isa50: pop si pop es mov eax, BmlTotal mov sp, bp pop bp ret _IsaConstructMemoryDescriptors endp ;++ ; ; BOOLEAN ; Int15E820 ( ; E820Frame *Frame ; ); ; ; ; Description: ; ; Gets address range descriptor by calling int 15 function E820h. ; ; Arguments: ; ; Returns: ; ; BOOLEAN - failed or succeed. ; ;-- cmdpFrame equ [bp + 6] public _Int15E820 _Int15E820 proc near push ebp mov bp, sp mov bp, cmdpFrame ; (bp) = Frame push es push edi push esi push ebx push ss pop es mov ebx, [bp].Key mov ecx, [bp].DescSize lea di, [bp].BaseAddrLow mov eax, 0E820h mov edx, \'SMAP\' ; (edx) = signature INT 15h mov [bp].Key, ebx ; update callers ebx mov [bp].DescSize, ecx ; update callers size sbb ecx, ecx ; ecx = -1 if carry, else 0 sub eax, \'SMAP\' ; eax = 0 if signature matched or ecx, eax mov [bp].ErrorFlag, ecx ; return 0 or non-zero pop ebx pop esi pop edi pop es pop ebp ret _Int15E820 endp _TEXT ends end Start ;*********************************************************** ;++ ; ; Module name ; ; su.inc ; ; Author ; ; Thomas Parslow (tomp) Mar-1-90 ; ; Description ; ; Include file for SU.ASM. ; ; ;-- .386 PAGE_SIZE equ 1000h MACHINE_TYPE_ISA equ 0 MACHINE_TYPE_EISA equ 1 MACHINE_TYPE_MCA equ 2 ; ; Define the segment:offset address pair of the location to ; load detection module. ; N.B. This definition *MUST* be the same as the ones defined ; in ..\\constant.h ; DETECTION_ADDRESS_SEG equ 1000h DETECTION_ADDRESS_OFFSET equ 0 ; ; Structure definitions and equates for INT 15 function E820 ; E820Frame struc ErrorFlag dd ? Key dd ? DescSize dd ? BaseAddrLow dd ? BaseAddrHigh dd ? SizeLow dd ? SizeHigh dd ? MemoryType dd ? E820Frame ends MemoryDescriptorFramePointer struc E820FramePointer dd ? MemoryDescriptorFramePointer ends ; BIOS_DISK_INTERRUPT equ 13h BIOS_READ_SECTOR equ 2 IDT_ENTRIES equ 100h BIOS_KEYBOARD_INTERRUPT equ 16h EXPORT_STACK equ 07ffeh RE_ENABLING equ 1 LOADER_STACK equ 061ffch CR0_ET equ 10h ; ; Trap Number macro save eax on the stack and then pushes the ; number of the trap that\'s in progress. ; TRAP_NUMBER macro num,addr IF num EQ 9 push eax ; push place holder for error code ENDIF IF num LE 7 push eax ; push place holder for error code ENDIF push eax ; save eax on stack first mov eax,num push eax jmp addr endm ;; ; ; GetSector Stack Frame Structure ; ; Stack frame definition for GetSector call from OS loader ; to 16bit routines. ; ;; GetSectorFrame struc FunctionNumber dd ? DriveNumber dd ? HeadNumber dd ? TrackNumber dd ? SectorNumber dd ? NumberOfSectors dd ? BufferPointer dd ? GetSectorFrame ends ;; ; ; GetEddsSector Stack Frame Structure ; ; Stack frame definition for GetEddsSector call from OS loader ; to 16bit routines. ; ;; GetEddsSectorFrame struc DriveNum dd ? LBNLow dd ? LBNHigh dd ? NumberOfBlocks dd ? BufPointer dd ? GetEddsSectorFrame ends RebootFrame struc BootType dd ? RebootFrame ends ; ; ABIOS services Stack Frame Structure ; ; Stack frame definition for ABIOS services call from OS loader ; to 16 bit routine. ; AbiosServicesFrame struc AbiosFunction dd ? CommonDataArea dd ? InitTable dd ? RamExtension dd ? AbiosRoutine dd ? LogicalId dd ? NumberLids dd ? AbiosServicesFrame ends ; ; Hardware detection frame structure ; ; Stack frame definition for DetectHardware call from OS loader ; to 16 bit routine. ; DetectionFrame struc HeapStart dd ? HeapSize dd ? ConfigTree dd ? HeapUsed dd ? LoadOptions dd ? OptionsLength dd ? DetectionFrame ends ; ; HardwareCursor Stack Frame Structure ; ; Stack frame definition for HardwareCursor call from OS loader ; to 16 bit routine. ; HardwareCursorFrame struc XCoord dd ? YCoord dd ? HardwareCursorFrame ends ; ; GetDateTime Stack Frame Structure ; ; Stack frame definition for GetDateTime call from OS loader ; to 16 bit routine. ; GetDateTimeFrame struc DateDword dd ? TimeDword dd ? GetDateTimeFrame ends ; ; ComPort Stack Frame Structure ; ; Stack frame definition for ComPort call from OS loader ; to 16 bit routine. ; ComPortFrame struc ComPortPort dd ? ComPortFunction dd ? ComPortArg dd ? ComPortFrame ends ; ; IsMcaMachine Stack Frame Structure ; ; Stack frame definition for IsMcaMachine call from OS loader ; to 16 bit routine. ; IsMcaMachineFrame struc Dummy dd ? IsMcaMachineFrame ends ;; ; ; GetElToritoStatus Stack Frame Structure ; ; Stack frame definition for GetElToritoStatus call from OS loader ; to 16bit routines. ; ;; GetElToritoStatusFrame struc SpecPacketPointer dd ? ETDriveNum dd ? GetElToritoStatusFrame ends ;; ; ; Memory Descriptor Structure. ; ; Passed to OS loader as part of the boot context record ; ;; MemoryDescriptor struc BlockBase dd ? BlockSize dd ? MemoryDescriptor ends ;; ; ; File System Context Record Structure ; ;; FsContextRecord struc BootDrive dd ? PointerToBpb dd ? Reserved dd ? FsContextRecord ends ;; ; ; IDT Descriptor Structure ; ;; TrapDesc struc IDT_offset dw ? IDT_selector dw ? IDT_attribute dw ? IDT_reserved dw ? TrapDesc ends ;; ; ; GDT Descriptor Structure ;; ; ;; GDTDesc struc GDT_limit dw 0 GDT_base1 dw 0 GDT_base2 db 0 GDT_access db 0 GDT_limacc db 0 GDT_base3 db 0 GDTDesc ends ;; ; ; GDT Selector Definitions ; ;; NULL_Selector equ 0h KeCodeSelector equ 8h KeDataSelector equ 10h UsCodeSelector equ 18h UsDataSelector equ 20h TSS_Selector equ 28h PCR_Selector equ 30h TEP_Selector equ 38h BDA_Selector equ 40h KeLdtSelector equ 48h DblFltTskSelector equ 50h SuCodeSelector equ 58h SuDataSelector equ 60h VideoSelector equ 68h GDT_AliasSelector equ 70h DbCodeSelector equ 78h DbDataSelector equ 80h DebugUseSelector equ 88h ReservedSelector equ 90h ;; ; ; Exception Frame Structure ; Note, this absolutely must match the corresponding structure ; defined in \"types.h\" ; ;; ExceptionFrame struc Ftr dw 0 Fdr6 dd 0 Fcr0 dd 0 Fcr2 dd 0 Fcr3 dd 0 Fss dw 0 Fgs dw 0 Ffs dw 0 Fes dw 0 Fds dw 0 Fedi dd 0 Fesi dd 0 Febp dd 0 Fesp dd 0 Febx dd 0 Fedx dd 0 Fecx dd 0 TrapNum dd 0 Feax dd 0 Error dd 0 Feip dd 0 Fcs dd 0 Feflags dd 0 ExceptionFrame ends tFsContext struc dw 0 tFsContext ends tBootContext struc dd 0 dd 0 tBootContext ends FUNCTION_ERROR equ -1 ;; ; ; Register Frame Structure ; ; For bios int calls ; ;; reg_frame struc intnum dw ? sfg dw ? sax dw ? sbx dw ? scx dw ? sdx dw ? ssi dw ? ses dw ? reg_frame ends ;; ;; Processor Flags ;; PROT_MODE equ 000000001 ; Enable protect mode operation ENABLE_PAGING equ 80000000h ; Enable paging hardware PD_PHYSICAL_ADDRESS equ 99000h TSS_SIZE equ 80h OVERRIDE equ 66h ; ; Operand and Address size overrides ; OPSIZE macro db 66h endm ADSIZE macro db 67h endm ; ; External Procedures for SUDATA.ASM ; IFDEF SU_CODEMODULE extrn _SuMain:near extrn _ScreenStart:near extrn _vp:near extrn _putx:near extrn _TrapHandler:near extrn _GDTregister:fword extrn _IDTregister:fword extrn _IDTregisterZero:fword extrn saveDS:word extrn SuStack:word extrn _edata:word extrn _FileStart:dword ENDIF ; ; External Procedures for SUDATA.ASM ; IFDEF SU_DATAMODULE extrn Trap0:far extrn Trap1:far extrn Trap2:far extrn Trap3:far extrn Trap4:far extrn Trap5:far extrn Trap6:far extrn Trap7:far extrn Trap8:far extrn Trap9:far extrn TrapA:far extrn TrapB:far extrn TrapC:far extrn TrapD:far extrn TrapE:far extrn TrapF:far extrn _edata:near ENDIF ; ; Segment declarations for \"Small Model\" 16 bit Su Module. ; _TEXT segment para use16 public \'CODE\' _TEXT ends _DATA segment para use16 public \'DATA\' _DATA ends CONST segment para use16 public \'CONST\' CONST ends _BSS segment para use16 public \'BSS\' _BSS ends DGROUP group const, _BSS, _DATA ;;; END OF FILE ;;; ;******************************************************** ;++ ; ; File Name: ; ; macro.inc ; ; Author: ; ; Thomas Parslow [tomp] ; ; Created: ; ; 27-Feb-91 ; ; Abstract: ; ; The macros used for creating the exported entry points the ; OS loader will use for basic h/w dependent services. These ; services are: ; ; o Disk I/O ; o Character I/O ; ; ;-- ;++ ; ; EXPORT_ENTRY_MACRO ; We arrive here from the OS loader with a 32bit CS. That is, we\'re ; executing the code with cs:eip where cs contains a selector for a ; 32bit flat segment. We want to get to a 16bit cs. That is, cs:ip. ; The entry points are exported as 32bit near pointers to the OS loader. ; All code in the SU module is identity mapped so the flat 32bit offset ; is equal to the physical address. ; ; Therefore, we export the 32bit physical address as the ; entry point and the code may be executed with either the 32bit ; flat cs or the SU module\'s 16bit based cs. Before we can switch ; modes we must load all of the segment registers with selectors for ; 16bit segments. We start by pushing a far pointer to a label in ; the macro and then doing a retf. This allows us to fall through ; to the next instruction, but we\'re now executing through cs:ip ; with a 16bit CS. ; ; Output: ; ; (ebx) = pointer to stack frame (and top of 32bit stack). ; EXPORT_ENTRY_MACRO macro entryname LOCAL exp1 _TEXT32 segment para use32 public \'CODE\' ASSUME CS:_TEXT32 ALIGN 4 Public EntryName EntryName LABEL near ; ; We\'ve go a 32bit CS:EIP - go to a 16bit CS:IP push dword ptr SuCodeSelector push dword ptr (offset exp1) retf _TEXT32 ends ASSUME CS:_TEXT ALIGN 4 exp1: ; ; Save caller\'s EBP register and stack pointer (ESP) ; push ebp push ebx push esi push edi mov ebx,esp ; ; Load all the segment registers with 16bit segment selectors ; mov ax,SuDataSelector mov ds,ax mov ss,ax ; ; Set the stack to the top of the segment. We can do this now since ; all of the OS loader\'s code has already be relocated. Also, we need ; plenty of stack since we\'ll be calling BIOS routines. ; mov sp,EXPORT_STACK push ebx ; save the caller\'s esp endm ; ; EXPORT_ENTRY_MACRO end ; ;++ ; ; Name: ; ; ExportExit ; ; Arguments: ; ; ; Notes: ; ; EAX = return code and MUST be preserved by this macro. ; ;-- EXPORT_EXIT_MACRO macro ; ; Next get caller\'s esp that we saved upon entry on the 16bit stack ; pop ebx ; get caller\'s esp ; ; Restore flat selectors in segment registers. ; mov dx,KeDataSelector mov ds,dx mov ss,dx mov es,dx mov esp,ebx ; ; Restore callers\' ebp that we saved on the 32bit stack ; pop edi pop esi pop ebx pop ebp ; (ebp) = caller\'s ebp ; ; Pull callers flat return address off stack and push the ; flat code selector followed by the return offset, then ; execute a far return and we\'ll be back in the OS loaders code space. ; pop edx ; (edx) = caller\'s return address push dword ptr KeCodeSelector push edx db OVERRIDE retf endm ;++ ; ; ; ;-- RE_ENABLE_PAGING_MACRO macro extrn _EnableProtectPaging:near push RE_ENABLING call _EnableProtectPaging add sp,2 endm ENTER_REALMODE_MACRO macro extrn _RealMode:near call _RealMode endm WAIT_FOREVER_MACRO macro LOCAL wf1 wf1: jmp wf1 endm ;++ ; ; MAKE_STACK_FRAME_MACRO ; ; Arguments: ; ; _FrameName_ - is the name of the structure defining the ; stack frame layout. ; ; _PointerRegister_ - is the register containing the linear pointer to ; the top of the stack frame. ; ProtectMode ONLY ; ;-- MAKE_STACK_FRAME_MACRO macro _FrameName_ , _PointerRegister_ Local msf1 mov ecx, (size _FrameName_)/2 mov esi,_PointerRegister_ ; (esi) = offset of argument frame add esi,20 ; account for ebp, ebx, esi, edi and ; return address push KeDataSelector ; (ax) = Flat 32bit segment selector pop ds ; (ds:esi) points to argument frame push ss ; pop es ; (es) = 16bit stack selector sub sp, size _FrameName_ ; make room for the arguments xor edi,edi ; clear out upper 16bits of edi mov di,sp ; (es:edi) points to top of stack msf1: mov ax,[esi] mov es:[edi],ax add esi,2 add edi,2 loop msf1 push es ; pop ds ; put 16bit selector back into ds endm REMOVE_STACK_FRAME_MACRO macro _FrameName_ add sp, size _FrameName_ endm ;BuildDescriptor macro Base,Limit,Access,Dpl,Stype ; dw (Limit AND 0ffffh) ; dw (Base AND 0ffffh) ; db ((Base SHR 16) AND 0ffh) ; db (Gran + Dpl + Stype) ; db ((Limit SHR 16) AND 0ffh) ; db ((Base SHR 24) AND 0ffh) ; endm ; ; ; RETURNCODE_IN_EAX_MACRO macro shl edx,16 mov dx,ax mov eax,edx endm ;以上代码为NTLDR的主框架。主要代码稍后发上来。 |
|
|
沙发#
发布于:2005-04-22 17:43
哪位仁兄把英文注释翻译过来好吗?这源代码来自NT4源代码中一个字没改个,就是全英文的看不懂注释。可能我把这代码贴上来已经太晚了,大家也许都有了吧。但我只是想大家在这儿来一起分析讨论,都可以学习吗?这样分析起来也快一些。希望各位高手来此讨论!
代码太多了,我只能慢慢的组织出来。请大家原谅。 |
|
|
板凳#
发布于:2005-04-23 11:41
这好象是装入ntldr的程序,ntldr那么大,这么点code也不对呀,
似乎象是ntldr的头部。 |
|
地板#
发布于:2005-04-26 00:22
这段代码主要完成给引导nt的程序定义一个入口点的作用,这段程序是所谓的nt自加载程序,计算出来的值实际上此时在DS和SS寄存器里;这段程序也为后面的程序提供bios功能的高程架构;另外一个重要的作用是提供将处理器由8086模式到保护的分页模式的代码转换,使用软件的方法屏蔽掉了Intel x86 处理器的分段机制,整个逻辑空间为一个连续的4GB空间(不扩展地址)再分页映射到虚拟的物理地址空间,nt实际上并不关心物理内存是多少。总之这是一段为加载ntlrd作软件和硬件准备的代码。应该是由BIOS加载后取得控制权的,它在加载了loader程序之后,向loader 交权,由loader分几步加载系统后再将控制交给系统。
你如由NT的原代码,应该将它在若干国内的网站上公开,且在公开之前你要提前一个月公告天下,这样才可以引发下载狂潮,而你也将因此而名利双收。记住,自古是先有名而后有利,名扬则利至,希望你能把物机会! |
|
|
地下室#
发布于:2007-05-17 19:30
貌似还有个ntloader.exe吧
|
|
5楼#
发布于:2007-08-13 22:48
ntdetect.com吧?
|
|
|
6楼#
发布于:2007-08-22 10:19
可以考虑参考一下 ReactOS 的 Freeldr 的代码。^_^
|
|