windows-nt/Source/XPSP1/NT/base/mvdm/dos/v86/inc/mshalo.asm
2020-09-26 16:20:57 +08:00

248 lines
5 KiB
NASM

; SCCSID = @(#)ibmhalo.asm 1.1 85/04/10
; On 2K (800h) boundaries beginning at address C0000h and ending at EF800h
; there is a header that describes a block of rom program. This header
; contains information needed to initialize a module and to provide PCDOS
; with a set of reserved names for execution.
;
; This header has the following format:
;
; rom_header STRUC
; Signature1 DB 55h
; Signature2 DB AAh
; rom_length DB ? ; number of 512 byte pieces
; init_jmp DB 3 dup (?)
; name_list name_struc <>
; rom_header ENDS
;
; name_struc STRUC
; name_len DB ?
; name_text DB ? DUP (?)
; name_jmp DB 3 DUP (?)
; name_struc ENDS
;
; The name list is a list of names that are reserved by a particular section
; of a module. This list of names is terminated by a null name (length
; is zero).
;
; Consider now, the PCDOS action when a user enters a command:
;
; COMMAND.COM has control.
; o If location FFFFEh has FDh then
; o Start scanning at C0000h, every 800h for a byte 55h followed
; by AAh, stop scan if we get above or = F0000H
; o When we've found one, compare the name entered by the user
; with the one found in the rom. If we have a match, then
; set up the environment for execution and do a long jump
; to the near jump after the found name.
; o If no more names in the list, then continue scanning the module
; for more 55h followed by AAh.
; o We get to this point only if there is no matching name in the
; rom. We now look on disk for the command.
;
; This gives us the flexibility to execute any rom cartridge without having
; to 'hard-code' the name of the cartridge into PCDOS. Rom modules that
; want to be invisible to the DOS should not have any names in their lists
; (i.e. they have a single null name).
;
; Consider a new release of BASIC, say, that patches bugs in the ROM version.
; Clearly this version will be available on disk. How does a user actually
; invoke this new BASIC?? He cannot call it BASIC on the disk because the
; EXEC loader will execute the ROM before it even looks at the disk! Only
; solution:
;
; o Keep things consistent and force the user to have his software named
; differently from the ROM names (BASIC1, BASIC2, etc).
rom_header STRUC
Signature1 DB ?
Signature2 DB ?
rom_length DB ?
init_jmp DB 3 dup (?)
name_list DB ?
rom_header ENDS
name_struc STRUC
name_len DB ?
name_text DB 1 DUP (?)
name_jmp DB 3 DUP (?)
name_struc ENDS
ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
;
; Check for IBM PC Jr rom cartrides. DS:DX is a pointer to name
;
ROM_SCAN:
PUSH ES
PUSH SI
PUSH DI
PUSH CX
PUSH AX
PUSH BX
;
; check for PC Jr signature in rom
;
MOV AX,0F000h
MOV ES,AX
CMP BYTE PTR ES:[0FFFEh],0FDh
JZ SCAN_IT
NO_ROM:
CLC
ROM_RET:
POP BX
POP AX
POP CX
POP DI
POP SI
POP ES
RET
SCAN_IT:
;
; start scanning at C000
;
MOV AX,0C000h
SCAN_ONE:
MOV ES,AX
XOR DI,DI
SCAN_MODULE:
;
; check for a valid header
;
CMP WORD PTR ES:[DI],0AA55h
JZ SCAN_LIST
ADD AX,080h
SCAN_END:
CMP AX,0F000h
JB SCAN_ONE
JMP NO_ROM
;
; trundle down list of names
;
SCAN_LIST:
MOV BL,ES:[DI].rom_length ; number of 512-byte jobbers
XOR BH,BH ; nothing in the high byte
SHL BX,1
SHL BX,1 ; number of paragraphs
ADD BX,7Fh
AND BX,0FF80h ; round to 2k
MOV DI,name_list
SCAN_NAME:
MOV CL,ES:[DI] ; length of name
INC DI ; point to name
XOR CH,CH
OR CX,CX ; zero length name
JNZ SCAN_TEST ; nope... compare
ADD AX,BX ; yep, skip to next block
JMP SCAN_END
;
; compare a single name
;
SCAN_TEST:
MOV SI,DX
INC SI
REPE CMPSB ; compare name
JZ SCAN_FOUND ; success!
SCAN_NEXT:
ADD DI,CX ; failure, next name piece
ADD DI,3
JMP SCAN_NAME
;
; found a name. save entry location
;
SCAN_FOUND:
CMP BYTE PTR DS:[SI],'?'
JZ SCAN_SAVE
CMP BYTE PTR DS:[SI],' '
JNZ SCAN_NEXT
SCAN_SAVE:
MOV [rom_cs],ES
MOV [ROM_ip],DI
STC
JMP ROM_RET
;
; execute a rom-placed body of code. allocate largest block
;
ROM_EXEC:
MOV BX,0FFFFh
MOV AH,ALLOC
INT int_command
MOV AH,ALLOC
INT int_command
PUSH BX
PUSH AX
;
; set terminate addresses
;
MOV AX,(set_interrupt_vector SHL 8) + int_terminate
PUSH DS
MOV DS,[RESSEG]
ASSUME DS:RESGROUP
MOV DX,OFFSET RESGROUP:EXEC_WAIT
INT int_command
MOV DX,DS
MOV ES,DX
ASSUME ES:RESGROUP
POP DS
ASSUME DS:NOTHING
;
; and create program header and dup all jfn's
;
POP DX
MOV AH,DUP_PDB
INT int_command
;
; set up dma address
;
MOV DS,DX
MOV DX,080h
MOV AH,SET_DMA
INT int_command
;
; copy in environment info
;
MOV AX,[ENVIRSEG]
MOV DS:[PDB_environ],AX
;
; set up correct size of block
;
POP BX ; BX has size, DS has segment
MOV DX,DS
ADD DX,BX
MOV DS:[PDB_block_len],DX
;
; change ownership of block
;
MOV DX,DS
DEC DX
MOV DS,DX
INC DX
MOV DS:[arena_owner],DX
MOV DS,DX
;
; set up correct stack
;
CMP BX,1000h
JB GOT_STACK
XOR BX,BX
GOT_STACK:
MOV CL,4
SHL BX,CL
MOV DX,DS
MOV SS,DX
MOV SP,BX
XOR AX,AX
PUSH AX
;
; set up initial registers and go to the guy
;
NOT AX
PUSH [ROM_CS]
PUSH [ROM_IP]
MOV ES,DX
ASSUME ES:NOTHING
FOOBAR PROC FAR
RET
FOOBAR ENDP