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

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

debugging updates

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