OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [c/] [src/] [lib/] [libbsp/] [i386/] [ts_386ex/] [tools/] [dos_sup/] [loader_hybrid_com.asm] - Rev 1765

Compare with Previous | Blame | View Log

; 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 change

KernelBase equ  08000h   ; Where (32-bit) to locate and run RTEMS executable

RelocSeg   equ  9000h    ; Segment to relocate code.
RelocAddr  equ  0E000h   ; Address to relocate code, same as "org" above

; Next three used in GDT

RelocBase  equ  RelocSeg*16
Reloc15    equ  RelocBase & 0FFFFh
Reloc23    equ  RelocBase / 10000h

Buffer     equ  RelocAddr+400h   ; In same segment as RelocSeg
BuffSiz    equ  200h             ; Size of disk read + copy

StackSeg   equ  RelocSeg
StackSiz   equ  40h
StackAddr  equ  Buffer+BuffSiz+StackSiz

; Used to jump to kernel in real mode

KernelAddr equ  KernelBase & 0FFFFh
KernelSeg  equ  (KernelBase - KernelAddr) / 16

; Used to load from the ramdisk

Extended   equ  100000h  ; Start of extended memory / C: ramdisk
OffsetBPB  equ  0Bh      ; Start of BIOS param block in bootsector

; Command-line parameters

ParamLen   equ  80h      ; Byte length of command line params
ParamStr   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, 9h
int  21h

mov  ax, 0b021h       ; Exit to DOS if push-button switch pressed
int  15h
and  al, 01h          ; Bit 0 == 0 if button pressed
jz   ButtonExit

xor cx, cx
mov cl, [ParamLen]   ; See if there is a command line arg
jcxz NameError

dec  cx              ; Nix leading space. Is this standard?
cmp  cx, 12          ; Limit to 12 chars: e.g. ABCDEFGH.IJK
jg   NameError
                     ; Damn. Should make sure of no ':' or '\' chars too.

; Required by "relocated" [org] statement above

mov  di, PRE_RELOC_ADDR(FName)  
mov  si, ParamStr
repne
movsb                ; 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, 12
repne
scasb
je   NameError

jmp  Relocate

ButtonExit:
mov  dx, PRE_RELOC_ADDR(Button)
jmp short  DosPrint

NameError:
mov  dx, PRE_RELOC_ADDR(FError)
jmp short  DosPrint

DosError:            ; Only call this AFTER relocation
mov  dx, RError

DosPrint:
mov  ah, 9h
int  21h

DosExit:
mov  ax, 04C00h      ; DOS Function: Exit program
int  21h             ; Call DOS. Terminate Program

Relocate:            ; Move this code down to RelocAddr

cld
mov  ax, RelocSeg
mov  es, ax           ; Set destination = RelocSeg:RelocAddr
mov  di, RelocAddr
mov  si, 100h         ; Source is ds:0100h i.e. a COM file
mov  cx, CodeEnd - CodeStart ; Size of all code

repne
movsb

; continue in copied code

jmp  RelocSeg:RelocAddr + (RelocStart - CodeStart) 

RelocStart:
cli
mov  ax, StackSeg
mov  ss, ax
mov  sp, StackAddr
mov  ax, cs
mov  ds, ax
mov  es, ax          ; Setup segments and stack
sti

mov  ah, 19h
int  21h
mov  [DDrive], al    ; Save current default drive

mov  ax, 3d00h       ; DOS Function: Open the file for reading
mov  dx, FName       ; Presume DS points at filename segment
int  21h
jc   DosError

GoodOpen:
mov  [FHndl], ax     ; Save file handle

mov  al, [DDrive]    ; Check if loading from C: drive (ramdisk)
cmp  al, 2
je   LoadRamdisk

LoadDosdisk:

; 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 Meg

ReadLoop:

mov  ah,3fh          ; DOS Function: Read data from the file
mov  bx, [FHndl]
mov  dx, Buffer      ; Address of data buffer
mov  cx, BuffSiz     ; Request BuffSiz bytes
int  21h
jc   DosError

GoodRead:

cmp  ax, cx          ; EOF reached? AX = # bytes read
pushf

add  ax, 3
shr  ax, 2           ; Copy buffer by dwords, # = (ax + 3)/4
movzx  ecx, ax
mov  esi, RelocBase + Buffer     ; Source for copy, destination is in edi

call CopyData32      ; Do protected-mode copy

popf
je   ReadLoop        ; Still data left, so read next chunk

mov  esi, Extended   ; Source for copy @ 1 Meg
mov  ecx, edi        ; Make count in dwords
sub  ecx, esi
add  ecx, 3
shr  ecx, 2
mov  edi, KernelBase ; Destination copy

call CopyData32      ; Move code into conventional memory
jmp  RunKernel

LoadRamdisk:

; 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 block

mov  esi, Extended
mov  edi, RelocBase + Buffer     ; Must be a 32-but address...
mov  ecx, 80h
call CopyData32

mov  si, Buffer + OffsetBPB
mov  di, SavBPB
mov  cx, EndBPB - SavBPB
repne
movsb

; Calculate  FAT, root dir, and data start addresses for the ramdisk

xor  eax, eax
mov  ebx, eax
mov  ecx, ebx

mov  ax, [ResSec]

mov  bl, [NumFAT]
imul bx, [SecFAT]

mov  cx, [NRoot]
shr  cx, 4           ; 10h directory entries per sector

add  bx, ax
add  cx, bx

mov  dx, [BpSect]
imul ax, dx
imul bx, dx
imul cx, dx

add  eax, Extended
add  ebx, Extended
add  ecx, Extended

mov  [BegFAT], eax
mov  [BegRoot], ebx
mov  [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, 12
repne
scasb

mov  bx, di          ; di points to filename extension

mov  di, DirName
mov  si, FName
mov  cx, bx          ; Make count
sub  cx, si
dec cx
repne                ; Copy initial part of filename
movsb

mov  di, bx          ; Find the terminating zero
xor  al,al
mov  cx, 4
repne
scasb

mov  cx, di          ; Make count
sub  cx, bx
dec  cx
mov  si, bx
mov  di, DirName + 8
repne                ; Copy filename extension
movsb

mov  si, DirName     ; Convert the stupid thing to upper case
mov  di, si
mov  cx, 11

Cvt2Upper:

lodsb
cmp  al, 'a'
jb   NotLow
cmp  al, 'z'
ja   NotLow
xor  al, 20h

NotLow:

stosb
loop 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, KernelBase
xor  ecx, ecx
mov  cx, [NRoot]
shl  cx, 3           ; Each root entry is 8 dwords
call CopyData32

mov  dx, [NRoot]     ; Max # of dir entries

mov  cx, KernelSeg   ; Setup segment selector for comparison
mov  es, cx
mov  di, KernelAddr

FindEntry:

mov  cx, 11
mov  si, DirName
push di
rep  cmpsb
pop  di
je   GotEntry
add  di, 20h         ; Point to next dir entry
dec  dx
jnz  FindEntry

int  3h              ; Should never get here...

GotEntry:

mov  eax, KernelBase ; Setup initial address for copy
mov  [CurrDst], eax

add  di, 32 - 6      ; Load first cluster number
mov  ax, [es:di]
mov  cx, ds          ; Fix `es' selector just in case
mov  es, cx

LoadKernel:

call LoadCluster     ; Load cluster `ax' to [CurrDst], update [CurrDst]

call NextCluster     ; Get next cluster number in ax

cmp  ax, 0FF8h       ; Repeat until EOF
jb   LoadKernel

RunKernel:

mov  ax, KernelSeg   ; Setup data segment and transfer control
mov  ds, ax

jmp  KernelSeg:KernelAddr  ; Huzzah!!


; Load cluster `ax' to [CurrDst], update [CurrDst]

LoadCluster:

push ax
sub  ax, 2           ; Cluster numbers start at 2
movzx eax, ax

xor  ecx, ecx        ; Calculate bytes in a cluster
mov  cl, [SpClst]
imul cx, [BpSect]

imul eax, ecx
add  eax, [BegData]  ; Start of cluster

shr  ecx, 2          ; Cluster size in dwords
mov  esi, eax        ; Copy source
mov  edi, [CurrDst]  ; Copy destination
call CopyData32

mov  [CurrDst], edi  ; Update dest
pop  ax              ; Restore cluster number

ret

; Search FAT (FAT12 format) for next cluster in file after `ax'.

NextCluster:

movzx ecx, ax        ; Calculate offset into FAT
shr  ax, 1
pushf
add  cx, ax

mov  esi, [BegFAT]   ; Copy word containing next cluster to buffer
add  esi, ecx
mov  edi, RelocBase + Buffer
xor  ecx, ecx
inc  ecx
call CopyData32

mov  ax, [Buffer]    ; Handle odd/even cluster numbers
popf
jnc  EvenCluster
shr  ax, 4

EvenCluster:

and  ax, 0FFFh
ret

; 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 : RealJmp2
RealJmp2:
;       LED_GRN
;       PSW_WAIT

        mov ax, cs       
        mov es, ax
        mov ds, ax
        mov ss, ax

        sti
ret

; Storage for a Dos 3+ BIOS Parameter Block (for the C: ramdisk)

SavBPB:

BpSect  dw  0h       ; Bytes per sector, always 512
SpClst  db  0h       ; Sectors per cluster
ResSec  dw  0h       ; Num of reserved sectors
NumFAT  db  0h       ; Num of FATs
NRoot   dw  0h       ; Num of root directory entries
TotSec  dw  0h       ; Total sectors
Media   db  0h       ; Media descriptor byte
SecFAT  dw  0h       ; Sectors per FAT

EndBPB:

CurrDst dd  0h       ; Current destination address for copying RTEMS exec

; Important (32-bit) address for the C: ramdisk

BegFAT  dd  0h       ; Start of the FAT
BegRoot dd  0h       ; Start of root directory
BegData dd  0h       ; Start of data clusters

DDrive  db  0h       ; Default drive: 0h = A:, 2h = C:

DirName times 11 db 32 ; Room for 8.3 directory entry name

FName   times 13 db 0  ; Room for a 12 character null-terminated string
FHndl   dw  0000h

Greet   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 entry

GDTStart:

dw GDTEnd - GDTStart - 1
dd RelocBase + GDTStart
dw 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, conforming
db 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 SP

dw 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-up
db 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, conforming
db 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-up
db 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

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.