source: trunk/src/os2ahci/init.asm@ 144

Last change on this file since 144 was 144, checked in by rousseau, 13 years ago

Fixed the Open Watcom build

Building with Open Watcom produced a non working driver.

Causes & Fixes

o Enum types were 8 bits when using WCC

This caused the functions with variable arguments to fail.
Adding the -ei compiler-flag to WCC solved this issue.

o Incorrect inline assembler syntax to call DeviceHelp in os2ahci.c

DeviceHelp is a 16:16 far pointer residing in memory.
MASM interprets 'call DeviceHelp' differently than WASM.
The correct syntax is: 'call dword ptr [DeviceHelp]'.

o Missing segments from TGROUP in init.asm

WLINK then generates the AUTO class, most probably causing incorrect
relocation fixups.

Enhancements

o WASM (or JWASM) can now be used instead of ALP
o WCC can now be used instead of CL
o The Open Watcom linker (WLINK) can now be used instead of LINK
o Streamlined both makefiles a notch so it's easy to use both tool-chains

To investigate

o CL barks about a missing prototype for DevHelp_Yield() in lib.c

The prototype is actually defined in dhcalls.h but CL still barks.

o Using WCC with ALP and WLINK produces an oversized image

Probaly due to misplaced BSS segments. WCC with ALP and LINK produces
a normal sized image however.

File size: 15.8 KB
Line 
1; ----------------------------------------------------------------------------
2; Initialization routines and segment mappings for os2ahci driver, plus
3; some low-level functions that were implemented in assembler
4
5include devhdr.inc
6
7; -----------------------------------------------------------------------------
8; Constants
9 DEV_IDC EQU 0400h ; IDC bit for ADD flags
10
11; -----------------------------------------------------------------------------
12; Public symbols
13
14 PUBLIC _asm_strat ; low-level strategy routine
15 PUBLIC _asm_idc_entry ; low-level IDC entry point
16 PUBLIC _asm_krnl_exit ; low-level kernel exit routine
17 PUBLIC _readl ; MMIO read (32 bits)
18 PUBLIC _writel ; MMIO write (32 bits)
19 PUBLIC _memset ; C memset() implementation
20 PUBLIC _memcpy ; C memcpy() implementation
21 PUBLIC _restart_hook ; port restart context hook
22 PUBLIC _reset_hook ; port reset context hook
23 PUBLIC _engine_hook ; engine trigger context hook
24 PUBLIC _dev_hdr ; device driver header
25 PUBLIC __I4M ; 32bit signed multiply routine
26 PUBLIC __U4M ; 32bit unsigned multiply routine
27 PUBLIC __U4D ; 32bit unsigned divide routine
28 PUBLIC __I4D ; 32bit signed divide routine
29 PUBLIC _end_of_data ; end of all data (label)
30 PUBLIC _end_of_code ; end of all code (label)
31
32; ----------------------------------------------------------------------------
33; Device Driver Header
34
35DEVHDR SEGMENT WORD PUBLIC 'DATA'
36_dev_hdr dd _legacy_hdr ; next device header
37 dw DEVLEV_3 + DEV_CHAR_DEV + DEV_IDC ; flags for ADD drivers
38 dw OFFSET _asm_strat ; strategy routine
39 dw OFFSET _asm_idc_entry ; IDC entry point
40 db "OS2AHCI$" ; name of character device
41 dq 0 ; 8 reserved bytes
42 dd DEV_IOCTL2 + DEV_ADAPTER_DD + DEV_INITCOMPLETE + 20h ; ADD flags
43 dw 0
44
45_legacy_hdr dd -1 ; no headers after this one
46 dw DEVLEV_3 + DEV_CHAR_DEV ; flags for ADD drivers
47 dw OFFSET _asm_strat ; strategy routine
48 dw 0 ; IDC entry point
49 db "IBMS506$" ; name of character device
50 dq 0 ; 8 reserved bytes
51 dd 0
52 dw 0
53DEVHDR ENDS
54
55; ----------------------------------------------------------------------------
56; Segment Definitions. We need to reference all segments here, even if they
57; are not used, to allow proper grouping of all segments into one group for
58; data and one group for code as well as proper ordering of the segments
59; within each group to make sure the end of segment markers are at the end
60; of each group.
61
62; On top of that, we need to make sure that the end of segment marker is in
63; a data segment of class 'BSS' because BSS segments are always put towards
64; the end of the executable when linking with high-level language objects
65; such as C.
66
67; When using the Watcom Linker, the segment ordering can be overridden in
68; the Watcom Makefile (wmakefile) where the Linker response-file is generated
69; containing statements for segment ordering. First you can order by class and
70; for each class you can specify the order of the segments within that class.
71; See the ORDER directive in the wlink documentation.
72_DATA SEGMENT WORD PUBLIC 'DATA'
73readl_dbg_fmt db "readl(%04x:%04x) = 0x%08lx"
74 db 10, 0
75writel_dbg_fmt db "writel(%04x:%04x, 0x%08lx)"
76 db 10, 0
77_DATA ENDS
78
79LIBDATA SEGMENT WORD PUBLIC 'DATA'
80LIBDATA ENDS
81
82CONST SEGMENT WORD PUBLIC 'CONST'
83CONST ENDS
84
85_BSS SEGMENT WORD PUBLIC 'BSS'
86_BSS ENDS
87
88c_common SEGMENT WORD PUBLIC 'BSS'
89 EXTRN _debug : WORD ; global debug flag
90c_common ENDS
91
92_z_data SEGMENT WORD PUBLIC 'BSS'
93_end_of_data db ?
94_z_data ENDS
95
96_TEXT SEGMENT WORD PUBLIC 'CODE'
97 EXTRN _c_strat : NEAR ; C strategy routine
98 EXTRN _printf : NEAR ; C printf routine
99 EXTRN _restart_ctxhook : NEAR ; C restart context hook
100 EXTRN _reset_ctxhook : NEAR ; C reset context hook
101 EXTRN _engine_ctxhook : NEAR ; C engine context hook
102 EXTRN _apm_suspend : NEAR ; C routine for INT13 IO enable
103_TEXT ENDS
104
105CODE SEGMENT WORD PUBLIC 'CODE'
106CODE ENDS
107
108LIBCODE SEGMENT WORD PUBLIC 'CODE'
109LIBCODE ENDS
110
111RMCode SEGMENT WORD PUBLIC 'CODE'
112RMCode ENDS
113
114_z_text SEGMENT WORD PUBLIC 'CODE'
115_end_of_code LABEL NEAR
116_z_text ENDS
117
118
119; The Watcom Linker behaves differently than the IBM/MS Linkers when segments
120; are defined but not added to the corresponding group. So when you define a
121; a new (logical) segment and want it to be part of a physical segment (group)
122; then don't forget to add it below or unresolvable or miscalculated
123; relocations can be the result.
124DGROUP GROUP DEVHDR, _DATA, LIBDATA, _BSS, c_common, _z_data
125TGROUP GROUP _TEXT, CODE, LIBCODE, RMCode, _z_text
126
127
128; ----------------------------------------------------------------------------
129; Start of code
130
131_TEXT SEGMENT WORD PUBLIC 'CODE'
132 ASSUME DS:DGROUP
133 ASSUME ES:NOTHING
134 ASSUME SS:NOTHING
135
136
137; Device driver main entry point (strategy routine)
138_asm_strat PROC FAR
139
140 ; push request packet address
141 PUSH ES
142 PUSH BX
143 CLD
144
145 ; call C strategy routine
146 CALL _c_strat
147
148 POP BX
149 POP ES
150 MOV WORD PTR ES:[BX+3], AX
151 RET
152_asm_strat ENDP
153
154
155; IDC entry point (Assembler stub)
156_asm_idc_entry PROC FAR
157
158 ; push request packet address
159 PUSH ES
160 PUSH BX
161 CLD
162
163 ; call C IDC entry point - which is the strategy routine
164 CALL _c_strat
165
166 POP BX
167 POP ES
168 MOV WORD PTR ES:[BX+3], AX
169 RET
170_asm_idc_entry ENDP
171
172; Kernel exit routine to enable INT13 I/O (called before a trap dump occurrs)
173_asm_krnl_exit PROC FAR
174
175 PUSH ES
176 PUSH DS
177 MOV AX,DGROUP
178 MOV DS,AX
179 CLD
180
181 ; call C routine
182 CALL _apm_suspend
183
184 POP DS
185 POP ES
186
187 RET
188_asm_krnl_exit ENDP
189
190
191 .386
192
193
194; Read long value from MMIO address; need to do this here to get real
195; 32-bit operations because at least the AHCI device in VirtualBox doesn't
196; seem to support reading 32-bit MMIO registers in two 16-bit steps.
197;
198; C prototype: u32 readl(void _far *addr);
199_readl PROC NEAR
200 ENTER 0, 0
201
202 ; load 'addr' into ES:EAX
203 LES AX, [BP+4]
204 AND EAX, 0000FFFFh
205
206 ; read MMIO register into EDX and return it in DX:AX
207 MOV EDX, ES:[EAX]
208
209 ; print debug message if debug level is 3+
210 CMP _debug, 3
211 JB no_debug
212 PUSH EDX ; save value read from MMIO port
213 PUSH EDX ; value read from MMIO address
214 PUSH AX ; offset of MMIO address
215 PUSH ES ; segment of MMIO address
216 PUSH OFFSET readl_dbg_fmt
217 CALL _printf
218 ADD SP, 10
219 POP EDX ; restore value read from MMIO port
220
221no_debug: MOV EAX, EDX
222 SHR EDX, 16
223
224 LEAVE
225 RET
226_readl ENDP
227
228
229; Write long value to MMIO address; need to do this here to get real
230; 32-bit operations because at least the AHCI device in VirtualBox doesn't
231; seem to support reading 32-bit MMIO registers in two 16-bit steps and the
232; assumption is that this is the same with writing 32-bit MMIO registers.
233;
234; C prototype: void writel(void _far *addr, u32 val);
235_writel PROC NEAR
236 ENTER 0, 0
237
238 ; load 'addr' into ES:EAX
239 LES AX, [BP+4]
240 AND EAX, 0000FFFFh
241
242 ; load 'val' into EDX, preserving the upper 16 bits of EBP
243 MOV EBX, EBP
244 AND EBP, 0000FFFFh
245 MOV EDX, [EBP+8]
246 MOV EBP, EBX
247
248 ; store 'val' at MMIO address in ES:EAX
249 MOV DWORD PTR ES:[EAX], EDX
250
251 ; print debug message if debug level is 3+
252 CMP _debug, 3
253 JB no_debug2
254 PUSH EDX ; value written to MMIO address
255 PUSH AX ; offset of MMIO address
256 PUSH ES ; segment of MMIO address
257 PUSH OFFSET writel_dbg_fmt
258 CALL _printf
259 ADD SP, 10
260
261no_debug2: LEAVE
262 RET
263_writel ENDP
264
265
266; Halfway-decent 32-bit implementation of memset().
267;
268; C prototype: void *memset(void _far *s, int c, size_t n);
269_memset PROC NEAR
270 ENTER 0, 0
271
272 PUSH DI
273
274 ; load 's' into ES:EDI
275 LES DI, [BP+4]
276 AND EDI, 0000FFFFh
277
278 ; load 'c' into EAX, replicating the low 8 bits all over
279 MOV BL, [BP+8]
280 MOV BH, BL
281 MOV AX, BX
282 SHL EAX, 16
283 MOV AX, BX
284
285 ; load 'n / 4' into ECX
286 MOV CX, [BP+10]
287 SHR CX, 2
288 AND ECX, 0000FFFFh
289
290 ; fill 's' with 32-bit chunks of EAX
291 REP STOSD
292
293 ; set remaining bytes (n % 4)'
294 MOV CX, [BP+10]
295 AND CX, 0003h
296 REP STOSB
297
298 ; return address of 's'
299 LES AX, [BP+4]
300 PUSH ES
301 POP DX
302
303 POP DI
304
305 LEAVE
306 RET
307_memset ENDP
308
309
310; Halfway-decent 32-bit implementation of memcpy().
311;
312; C prototype: void *memcpy(void _far *d, void _far *s, size_t n);
313_memcpy PROC NEAR
314 ENTER 0, 0
315
316 PUSH SI
317 PUSH DI
318 PUSH DS
319
320 ; load 'd' into ES:EDI
321 LES DI, [BP+4]
322 AND EDI, 0000FFFFh
323
324 ; load 's' into DS:ESI
325 LDS SI, [BP+8]
326 AND ESI, 0000FFFFh
327
328 ; load 'n / 4' into ECX
329 MOV CX, [BP+12]
330 SHR CX, 2
331 AND ECX, 0000FFFFh
332
333 ; copy 's' to 'd' in 32-bit chunks
334 REP MOVSD
335
336 ; copy remaining bytes (n % 4)'
337 MOV CX, [BP+12]
338 AND CX, 0003h
339 REP MOVSB
340
341 ; return address of 'd'
342 LES AX, [BP+4]
343 PUSH ES
344 POP DX
345
346 POP DS
347 POP DI
348 POP SI
349
350 LEAVE
351 RET
352_memcpy ENDP
353
354
355; Port restart context hook; context hooks need to save all registers
356; and get the parameter passed to DevHelp_ArmCtxHook() in EAX, thus
357; we need a stub which calls the real context hook.
358_restart_hook PROC FAR
359 PUSHAD
360 PUSH EAX
361 CALL _restart_ctxhook
362 POP EAX
363 POPAD
364 RET
365_restart_hook ENDP
366
367
368; Port reset context hook; context hooks need to save all registers
369; and get the parameter passed to DevHelp_ArmCtxHook() in EAX, thus
370; we need a stub which calls the real context hook.
371_reset_hook PROC FAR
372 PUSHAD
373 PUSH EAX
374 CALL _reset_ctxhook
375 POP EAX
376 POPAD
377 RET
378_reset_hook ENDP
379
380
381; Engine trigger context hook; context hooks need to save all registers
382; and get the parameter passed to DevHelp_ArmCtxHook() in EAX, thus
383; we need a stub which calls the real context hook.
384_engine_hook PROC FAR
385 PUSHAD
386 PUSH EAX
387 CALL _engine_ctxhook
388 POP EAX
389 POPAD
390 RET
391_engine_hook ENDP
392
393
394; Unsigned long divide routine;
395; taken from OS/2 Uniaud project, original author: Timur Tabi
396__U4D proc near
397 shl edx,10h ;; Load dx:ax into eax
398 mov dx,ax
399 mov eax,edx
400 xor edx,edx ;; Zero extend eax into edx
401 shl ecx,10h ;; Load cx:bx into ecx
402 mov cx,bx
403 div ecx ;; Divide eax/ecx into eax
404 mov ecx,edx ;; Load edx into cx:bx
405 shr ecx,10h
406 mov bx,dx
407 mov edx,eax ;; Load eax into dx:ax
408 shr edx,10h
409 ret
410__U4D endp
411
412; Long multiply routine;
413; taken from OS/2 Uniaud project, original author: Timur Tabi
414__U4M proc near
415__I4M label near
416 shl edx,10h ;; Load dx:ax into eax
417 mov dx,ax
418 mov eax,edx
419 mov dx,cx ;; Load cx:bx into edx
420 shl edx,10h
421 mov dx,bx
422 mul edx ;; Multiply eax*edx into edx:eax
423 mov edx,eax ;; Load eax into dx:ax
424 shr edx,10h
425 ret
426__U4M endp
427
428
429; Signed long divide routine;
430; taken from OS/2 Uniaud project, original author: Timur Tabi
431__I4D proc near
432 shl edx,10h ;; Load dx:ax into eax
433 mov dx,ax
434 mov eax,edx
435 cdq ;; Sign extend eax into edx
436 shl ecx,10h ;; Load cx:bx into ecx
437 mov cx,bx
438 idiv ecx ;; Divide eax/ecx into eax
439 mov ecx,edx ;; Load edx into cx:bx
440 shr ecx,10h
441 mov bx,dx
442 mov edx,eax ;; Load eax into dx:ax
443 shr edx,10h
444 ret
445__I4D endp
446
447 .286
448
449_TEXT ENDS
450
451 END
452
Note: See TracBrowser for help on using the repository browser.