📄 loader_hybrid_com.asm
字号:
; loader_hybrid_com.asm;; This is a DOS command-line loader for RTEMS executables running on; the Technologic Systems TS-1325 Embedded PC.;; It loads a DOS file given on the command line to the address `KernelBase',; and then transfers control there. It uses DOS file I/O commands to read from; the A: flash disk, and direct memory access to read from the C: ramdisk.;; Copying uses protected flat mode, so kernelbase could be above 1MB.; It does not initialize protected mode before transferring control; to the RTEMS executable image.;; Compile with: nasm -o loader.com loader_hybrid_com.asm;; Tony Ambardar (c) 1999; E.C.E. Department; University of British Columbia%include "ts1325.inc" ; Some useful LED and button macros; IMPORTANT: [org xxx] MUST be the same as RelocAddr below.[org E000h][bits 16]; Only these three definitions may need to changeKernelBase equ 08000h ; Where (32-bit) to locate and run RTEMS executableRelocSeg equ 9000h ; Segment to relocate code.RelocAddr equ 0E000h ; Address to relocate code, same as "org" above; Next three used in GDTRelocBase equ RelocSeg*16Reloc15 equ RelocBase & 0FFFFhReloc23 equ RelocBase / 10000hBuffer equ RelocAddr+400h ; In same segment as RelocSegBuffSiz equ 200h ; Size of disk read + copyStackSeg equ RelocSegStackSiz equ 40hStackAddr equ Buffer+BuffSiz+StackSiz; Used to jump to kernel in real modeKernelAddr equ KernelBase & 0FFFFhKernelSeg equ (KernelBase - KernelAddr) / 16; Used to load from the ramdiskExtended equ 100000h ; Start of extended memory / C: ramdiskOffsetBPB equ 0Bh ; Start of BIOS param block in bootsector; Command-line parametersParamLen equ 80h ; Byte length of command line paramsParamStr equ 82h ; Start of param string; The ORG address above means pre-relocation addresses are wrong. The; following macro fixes these up.%define PRE_RELOC_ADDR(addr) (addr-CodeStart+100h)CodeStart:mov dx, PRE_RELOC_ADDR(Greet)mov ah, 9hint 21hmov ax, 0b021h ; Exit to DOS if push-button switch pressedint 15hand al, 01h ; Bit 0 == 0 if button pressedjz ButtonExitxor cx, cxmov cl, [ParamLen] ; See if there is a command line argjcxz NameErrordec cx ; Nix leading space. Is this standard?cmp cx, 12 ; Limit to 12 chars: e.g. ABCDEFGH.IJKjg NameError ; Damn. Should make sure of no ':' or '\' chars too.; Required by "relocated" [org] statement abovemov di, PRE_RELOC_ADDR(FName) mov si, ParamStrrepnemovsb ; Copy command line arg; Make sure no ':' in filename. This forces using the default dir.mov di, PRE_RELOC_ADDR(FName)mov al, ':'mov cx, 12repnescasbje NameErrorjmp RelocateButtonExit:mov dx, PRE_RELOC_ADDR(Button)jmp short DosPrintNameError:mov dx, PRE_RELOC_ADDR(FError)jmp short DosPrintDosError: ; Only call this AFTER relocationmov dx, RErrorDosPrint:mov ah, 9hint 21hDosExit:mov ax, 04C00h ; DOS Function: Exit programint 21h ; Call DOS. Terminate ProgramRelocate: ; Move this code down to RelocAddrcldmov ax, RelocSegmov es, ax ; Set destination = RelocSeg:RelocAddrmov di, RelocAddrmov si, 100h ; Source is ds:0100h i.e. a COM filemov cx, CodeEnd - CodeStart ; Size of all coderepnemovsb; continue in copied codejmp RelocSeg:RelocAddr + (RelocStart - CodeStart) RelocStart:climov ax, StackSegmov ss, axmov sp, StackAddrmov ax, csmov ds, axmov es, ax ; Setup segments and stackstimov ah, 19hint 21hmov [DDrive], al ; Save current default drivemov ax, 3d00h ; DOS Function: Open the file for readingmov dx, FName ; Presume DS points at filename segmentint 21hjc DosErrorGoodOpen:mov [FHndl], ax ; Save file handlemov al, [DDrive] ; Check if loading from C: drive (ramdisk)cmp al, 2je LoadRamdiskLoadDosdisk:; Here we are loading from A: drive. Use DOS calls to load the file into; extended memory. Then copy from extended memory to `KernelBase'. This way; we avoid overwriting DOS file I/O structures if reading directly into; conventional (<640K) memory.mov edi, Extended ; Destination for code read @ 1 MegReadLoop:mov ah,3fh ; DOS Function: Read data from the filemov bx, [FHndl]mov dx, Buffer ; Address of data buffermov cx, BuffSiz ; Request BuffSiz bytesint 21hjc DosErrorGoodRead:cmp ax, cx ; EOF reached? AX = # bytes readpushfadd ax, 3shr ax, 2 ; Copy buffer by dwords, # = (ax + 3)/4movzx ecx, axmov esi, RelocBase + Buffer ; Source for copy, destination is in edicall CopyData32 ; Do protected-mode copypopfje ReadLoop ; Still data left, so read next chunkmov esi, Extended ; Source for copy @ 1 Megmov ecx, edi ; Make count in dwordssub ecx, esiadd ecx, 3shr ecx, 2mov edi, KernelBase ; Destination copycall CopyData32 ; Move code into conventional memoryjmp RunKernelLoadRamdisk:; Here we are loading from C: drive. Use protected mode to directly access; the virtual disk sectors in extended memory and copy to `KernelBase'. ; This way we avoid using DOS file I/O calls, except for an `open' earlier; which tells us the file exists.; Copy C: "bootsector" to buffer and save the BIOS parameter blockmov esi, Extendedmov edi, RelocBase + Buffer ; Must be a 32-but address...mov ecx, 80hcall CopyData32mov si, Buffer + OffsetBPBmov di, SavBPBmov cx, EndBPB - SavBPBrepnemovsb; Calculate FAT, root dir, and data start addresses for the ramdiskxor eax, eaxmov ebx, eaxmov ecx, ebxmov ax, [ResSec]mov bl, [NumFAT]imul bx, [SecFAT]mov cx, [NRoot]shr cx, 4 ; 10h directory entries per sectoradd bx, axadd cx, bxmov dx, [BpSect]imul ax, dximul bx, dximul cx, dxadd eax, Extendedadd ebx, Extendedadd ecx, Extendedmov [BegFAT], eaxmov [BegRoot], ebxmov [BegData], ecx; Convert the saved filename to format used in directory entry. Assume; there's a `.' in it. Hopefully this won't haunt us later...mov di, FName ; Find the `.'mov al, '.'mov cx, 12repnescasbmov bx, di ; di points to filename extensionmov di, DirNamemov si, FNamemov cx, bx ; Make countsub cx, sidec cxrepne ; Copy initial part of filenamemovsbmov di, bx ; Find the terminating zeroxor al,almov cx, 4repnescasbmov cx, di ; Make countsub cx, bxdec cxmov si, bxmov di, DirName + 8repne ; Copy filename extensionmovsbmov si, DirName ; Convert the stupid thing to upper casemov di, simov cx, 11Cvt2Upper:lodsbcmp al, 'a'jb NotLowcmp al, 'z'ja NotLowxor al, 20hNotLow:stosbloop Cvt2Upper; Now load in the root directory (temporarily) to find the first cluster; of our file. Use KernelSeg:KernelAddr as temporary storage.mov esi, [BegRoot]mov edi, KernelBasexor ecx, ecxmov cx, [NRoot]shl cx, 3 ; Each root entry is 8 dwordscall CopyData32mov dx, [NRoot] ; Max # of dir entriesmov cx, KernelSeg ; Setup segment selector for comparisonmov es, cxmov di, KernelAddrFindEntry:mov cx, 11mov si, DirNamepush direp cmpsbpop dije GotEntryadd di, 20h ; Point to next dir entrydec dxjnz FindEntryint 3h ; Should never get here...GotEntry:mov eax, KernelBase ; Setup initial address for copymov [CurrDst], eaxadd di, 32 - 6 ; Load first cluster numbermov ax, [es:di]mov cx, ds ; Fix `es' selector just in casemov es, cxLoadKernel:call LoadCluster ; Load cluster `ax' to [CurrDst], update [CurrDst]call NextCluster ; Get next cluster number in axcmp ax, 0FF8h ; Repeat until EOFjb LoadKernelRunKernel:mov ax, KernelSeg ; Setup data segment and transfer controlmov ds, axjmp KernelSeg:KernelAddr ; Huzzah!!; Load cluster `ax' to [CurrDst], update [CurrDst]LoadCluster:push axsub ax, 2 ; Cluster numbers start at 2movzx eax, axxor ecx, ecx ; Calculate bytes in a clustermov cl, [SpClst]imul cx, [BpSect]imul eax, ecxadd eax, [BegData] ; Start of clustershr ecx, 2 ; Cluster size in dwordsmov esi, eax ; Copy sourcemov edi, [CurrDst] ; Copy destinationcall CopyData32mov [CurrDst], edi ; Update destpop ax ; Restore cluster numberret; Search FAT (FAT12 format) for next cluster in file after `ax'.NextCluster:movzx ecx, ax ; Calculate offset into FATshr ax, 1pushfadd cx, axmov esi, [BegFAT] ; Copy word containing next cluster to bufferadd esi, ecxmov edi, RelocBase + Bufferxor ecx, ecxinc ecxcall CopyData32mov ax, [Buffer] ; Handle odd/even cluster numberspopfjnc EvenClustershr ax, 4EvenCluster:and ax, 0FFFhret; Enable the A20 line for accesses to extended memory.EnableA20: in al,92h or al,2 jmp short $+2 jmp short $+2 jmp short $+2 out 92h,al ret; The CopyData32 routine copies ecx dwords from esi to edi. Both esi; and edi hold 32-bit values. CopyData32 runs in 32-bit protected mode.CopyData32: cli call EnableA20 ; Put here in case file I/O screws with this ; or with the GDTR lgdt [GDTStart] ; Initialize GDTR for 32-bit protected mode mov eax, cr0 or al, 1 mov cr0, eax ;go to real flat mode; LED_GRN; PSW_WAIT jmp dword 8h : RelocBase+ProtJmp[bits 32]ProtJmp:; LED_YEL; PSW_WAIT mov ax, 10h mov ds, ax mov es, ax mov ss, ax rep movsd ;copy the sector to where it should be mov ax, 20h mov ds, ax mov es, ax mov ss, ax; LED_RED; PSW_WAIT jmp 18h : RealJmp1 ;use code segment with 64K limit[bits 16]RealJmp1:; LED_OFF; PSW_WAIT mov eax, cr0 ;back to real segmented mode and eax, 0fffffffeh mov cr0, eax jmp RelocSeg : RealJmp2RealJmp2:; LED_GRN; PSW_WAIT mov ax, cs mov es, ax mov ds, ax mov ss, ax stiret; Storage for a Dos 3+ BIOS Parameter Block (for the C: ramdisk)SavBPB:BpSect dw 0h ; Bytes per sector, always 512SpClst db 0h ; Sectors per clusterResSec dw 0h ; Num of reserved sectorsNumFAT db 0h ; Num of FATsNRoot dw 0h ; Num of root directory entriesTotSec dw 0h ; Total sectorsMedia db 0h ; Media descriptor byteSecFAT dw 0h ; Sectors per FATEndBPB:CurrDst dd 0h ; Current destination address for copying RTEMS exec; Important (32-bit) address for the C: ramdiskBegFAT dd 0h ; Start of the FATBegRoot dd 0h ; Start of root directoryBegData dd 0h ; Start of data clustersDDrive db 0h ; Default drive: 0h = A:, 2h = C:DirName times 11 db 32 ; Room for 8.3 directory entry nameFName times 13 db 0 ; Room for a 12 character null-terminated stringFHndl dw 0000hGreet db "RTEMS DOS Loader (c) 1999 Tony R. Ambardar",13,10,"$"Button db "Button pressed -- Aborting.",13,10,"$"FError db "Missing or incorrect file name.",13,10,"$"RError db "Error opening or reading file.",13,10,"$"; Global Descriptor Table used for protectd mode.; Store the GDTR in the first null GDT entryGDTStart:dw GDTEnd - GDTStart - 1dd RelocBase + GDTStartdw 0; base=0h, limit=4Gb, present, code, exec/read, conform, 32-bit dw 0ffffh ;seg. lim. [15:0]dw 0 ;base[15:0]db 0 ;base[23:16]db 9eh ;p=1,dpl=0,s=1 ; code: execute/read, conformingdb 0cfh ;c: gran=4K, D/B=1(32-bit) ; f: seg. lim. [19:16] db 0 ;base[31:24]; base=0h, limit=4Gb, present, data, read/write exp. up, 32-bit SPdw 0ffffh ;seg. lim. [15:0]dw 0 ;base[15:0]db 0 ;base[23:16]db 92h ;p=1,dpl=0,s=1 ; data: read/write expand-updb 0cfh ;c: gran=4K, D/B=1(32-bit) ; f: seg. lim. [19:16]db 0 ;base[31:24]; base=0h, limit=ffffh, present, code, exec/read, conform, 16-bit ; NOTE: this descriptor is used to change back to real mode.dw 0ffffh ;seg. lim. [15:0]dw Reloc15 ;base[15:0]db Reloc23 ;base[23:16]db 9eh ;p=1,dpl=0,s=1 ; code: execute/read, conformingdb 000h ;4: gran=1 byte, D/B=0(16-bit) ; 0: seg. lim. [19:16] db 0 ;base[31:24]; base=0h, limit=ffffh, present, data, read/write exp. up, 16-bit SP; NOTE: this descriptor is used to change back to real mode.dw 0ffffh ;seg. lim. [15:0]dw Reloc15 ;base[15:0]db Reloc23 ;base[23:16]db 92h ;p=1,dpl=0,s=1 ; data: read/write expand-updb 000h ;0: gran=1 byte, D/B=0(16-bit) ; 0: seg. lim. [19:16]db 0 ;base[31:24]GDTEnd:CodeEnd: ; end-of-code marker for copy
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -