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

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

Makefile updates
Debug output improvements
Support for ACPI suspend/resume added

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