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

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

Enhanced debug output
Fixed a long time PCI ID bug.

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