1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
|
; 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 HALO 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 halo 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
|