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

Last change on this file since 164 was 164, checked in by David Azarewicz, 12 years ago

Debug output updates

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