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

Last change on this file since 141 was 141, checked in by Markus Thielen, 13 years ago

fixed #13 (kernel exit call for trap dumps)

File size: 15.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 _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_DATA SEGMENT WORD PUBLIC 'DATA'
68readl_dbg_fmt db "readl(%04x:%04x) = 0x%08lx"
69 db 10, 0
70writel_dbg_fmt db "writel(%04x:%04x, 0x%08lx)"
71 db 10, 0
72_DATA ENDS
73
74CONST SEGMENT WORD PUBLIC 'CONST'
75CONST ENDS
76
77_BSS SEGMENT WORD PUBLIC 'BSS'
78_BSS ENDS
79
80c_common SEGMENT WORD PUBLIC 'BSS'
81 EXTRN _debug : WORD ; global debug flag
82c_common ENDS
83
84_z_data SEGMENT WORD PUBLIC 'BSS'
85_end_of_data db 0
86_z_data ENDS
87
88_TEXT SEGMENT WORD PUBLIC 'CODE'
89 EXTRN _c_strat : NEAR ; C strategy routine
90 EXTRN _printf : NEAR ; C printf routine
91 EXTRN _restart_ctxhook : NEAR ; C restart context hook
92 EXTRN _reset_ctxhook : NEAR ; C reset context hook
93 EXTRN _engine_ctxhook : NEAR ; C engine context hook
94 EXTRN _apm_suspend : NEAR ; C routine for INT13 IO enable
95_TEXT ENDS
96
97CODE SEGMENT WORD PUBLIC 'CODE'
98CODE ENDS
99
100RMCode SEGMENT WORD PUBLIC 'CODE'
101RMCode ENDS
102
103LIBCODE SEGMENT WORD PUBLIC 'CODE'
104LIBCODE ENDS
105
106_z_text SEGMENT WORD PUBLIC 'CODE'
107_end_of_code LABEL NEAR
108_z_text ENDS
109
110DGROUP GROUP DEVHDR, _DATA, CONST, _BSS, c_common, _z_data
111TGROUP GROUP _TEXT, CODE, _z_text
112
113; ----------------------------------------------------------------------------
114; Start of code
115
116_TEXT SEGMENT WORD PUBLIC 'CODE'
117 ASSUME DS:DGROUP
118 ASSUME ES:NOTHING
119 ASSUME SS:NOTHING
120
121
122; Device driver main entry point (strategy routine)
123_asm_strat PROC FAR
124
125 ; push request packet address
126 PUSH ES
127 PUSH BX
128 CLD
129
130 ; call C strategy routine
131 CALL _c_strat
132
133 POP BX
134 POP ES
135 MOV WORD PTR ES:[BX+3], AX
136 RET
137_asm_strat ENDP
138
139
140; IDC entry point (Assembler stub)
141_asm_idc_entry PROC FAR
142
143 ; push request packet address
144 PUSH ES
145 PUSH BX
146 CLD
147
148 ; call C IDC entry point - which is the 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_idc_entry ENDP
156
157; Kernel exit routine to enable INT13 I/O (called before a trap dump occurrs)
158_asm_krnl_exit PROC FAR
159
160 PUSH ES
161 PUSH DS
162 MOV AX,DGROUP
163 MOV DS,AX
164 CLD
165
166 ; call C routine
167 CALL _apm_suspend
168
169 POP DS
170 POP ES
171
172 RET
173_asm_krnl_exit ENDP
174
175
176 .386
177
178
179; Read long value from MMIO address; need to do this here to get real
180; 32-bit operations because at least the AHCI device in VirtualBox doesn't
181; seem to support reading 32-bit MMIO registers in two 16-bit steps.
182;
183; C prototype: u32 readl(void _far *addr);
184_readl PROC NEAR
185 ENTER 0, 0
186
187 ; load 'addr' into ES:EAX
188 LES AX, [BP+4]
189 AND EAX, 0000FFFFh
190
191 ; read MMIO register into EDX and return it in DX:AX
192 MOV EDX, ES:[EAX]
193
194 ; print debug message if debug level is 3+
195 CMP _debug, 3
196 JB no_debug
197 PUSH EDX ; save value read from MMIO port
198 PUSH EDX ; value read from MMIO address
199 PUSH AX ; offset of MMIO address
200 PUSH ES ; segment of MMIO address
201 PUSH OFFSET readl_dbg_fmt
202 CALL _printf
203 ADD SP, 10
204 POP EDX ; restore value read from MMIO port
205
206no_debug: MOV EAX, EDX
207 SHR EDX, 16
208
209 LEAVE
210 RET
211_readl ENDP
212
213
214; Write long value to MMIO address; need to do this here to get real
215; 32-bit operations because at least the AHCI device in VirtualBox doesn't
216; seem to support reading 32-bit MMIO registers in two 16-bit steps and the
217; assumption is that this is the same with writing 32-bit MMIO registers.
218;
219; C prototype: void writel(void _far *addr, u32 val);
220_writel PROC NEAR
221 ENTER 0, 0
222
223 ; load 'addr' into ES:EAX
224 LES AX, [BP+4]
225 AND EAX, 0000FFFFh
226
227 ; load 'val' into EDX, preserving the upper 16 bits of EBP
228 MOV EBX, EBP
229 AND EBP, 0000FFFFh
230 MOV EDX, [EBP+8]
231 MOV EBP, EBX
232
233 ; store 'val' at MMIO address in ES:EAX
234 MOV DWORD PTR ES:[EAX], EDX
235
236 ; print debug message if debug level is 3+
237 CMP _debug, 3
238 JB no_debug2
239 PUSH EDX ; value written to MMIO address
240 PUSH AX ; offset of MMIO address
241 PUSH ES ; segment of MMIO address
242 PUSH OFFSET writel_dbg_fmt
243 CALL _printf
244 ADD SP, 10
245
246no_debug2: LEAVE
247 RET
248_writel ENDP
249
250
251; Halfway-decent 32-bit implementation of memset().
252;
253; C prototype: void *memset(void _far *s, int c, size_t n);
254_memset PROC NEAR
255 ENTER 0, 0
256
257 PUSH DI
258
259 ; load 's' into ES:EDI
260 LES DI, [BP+4]
261 AND EDI, 0000FFFFh
262
263 ; load 'c' into EAX, replicating the low 8 bits all over
264 MOV BL, [BP+8]
265 MOV BH, BL
266 MOV AX, BX
267 SHL EAX, 16
268 MOV AX, BX
269
270 ; load 'n / 4' into ECX
271 MOV CX, [BP+10]
272 SHR CX, 2
273 AND ECX, 0000FFFFh
274
275 ; fill 's' with 32-bit chunks of EAX
276 REP STOSD
277
278 ; set remaining bytes (n % 4)'
279 MOV CX, [BP+10]
280 AND CX, 0003h
281 REP STOSB
282
283 ; return address of 's'
284 LES AX, [BP+4]
285 PUSH ES
286 POP DX
287
288 POP DI
289
290 LEAVE
291 RET
292_memset ENDP
293
294
295; Halfway-decent 32-bit implementation of memcpy().
296;
297; C prototype: void *memcpy(void _far *d, void _far *s, size_t n);
298_memcpy PROC NEAR
299 ENTER 0, 0
300
301 PUSH SI
302 PUSH DI
303 PUSH DS
304
305 ; load 'd' into ES:EDI
306 LES DI, [BP+4]
307 AND EDI, 0000FFFFh
308
309 ; load 's' into DS:ESI
310 LDS SI, [BP+8]
311 AND ESI, 0000FFFFh
312
313 ; load 'n / 4' into ECX
314 MOV CX, [BP+12]
315 SHR CX, 2
316 AND ECX, 0000FFFFh
317
318 ; copy 's' to 'd' in 32-bit chunks
319 REP MOVSD
320
321 ; copy remaining bytes (n % 4)'
322 MOV CX, [BP+12]
323 AND CX, 0003h
324 REP MOVSB
325
326 ; return address of 'd'
327 LES AX, [BP+4]
328 PUSH ES
329 POP DX
330
331 POP DS
332 POP DI
333 POP SI
334
335 LEAVE
336 RET
337_memcpy ENDP
338
339
340; Port restart context hook; context hooks need to save all registers
341; and get the parameter passed to DevHelp_ArmCtxHook() in EAX, thus
342; we need a stub which calls the real context hook.
343_restart_hook PROC FAR
344 PUSHAD
345 PUSH EAX
346 CALL _restart_ctxhook
347 POP EAX
348 POPAD
349 RET
350_restart_hook ENDP
351
352
353; Port reset context hook; context hooks need to save all registers
354; and get the parameter passed to DevHelp_ArmCtxHook() in EAX, thus
355; we need a stub which calls the real context hook.
356_reset_hook PROC FAR
357 PUSHAD
358 PUSH EAX
359 CALL _reset_ctxhook
360 POP EAX
361 POPAD
362 RET
363_reset_hook ENDP
364
365
366; Engine trigger context hook; context hooks need to save all registers
367; and get the parameter passed to DevHelp_ArmCtxHook() in EAX, thus
368; we need a stub which calls the real context hook.
369_engine_hook PROC FAR
370 PUSHAD
371 PUSH EAX
372 CALL _engine_ctxhook
373 POP EAX
374 POPAD
375 RET
376_engine_hook ENDP
377
378
379; Unsigned long divide routine;
380; taken from OS/2 Uniaud project, original author: Timur Tabi
381__U4D proc near
382 shl edx,10h ;; Load dx:ax into eax
383 mov dx,ax
384 mov eax,edx
385 xor edx,edx ;; Zero extend eax into edx
386 shl ecx,10h ;; Load cx:bx into ecx
387 mov cx,bx
388 div ecx ;; Divide eax/ecx into eax
389 mov ecx,edx ;; Load edx into cx:bx
390 shr ecx,10h
391 mov bx,dx
392 mov edx,eax ;; Load eax into dx:ax
393 shr edx,10h
394 ret
395__U4D endp
396
397; Long multiply routine;
398; taken from OS/2 Uniaud project, original author: Timur Tabi
399__U4M proc near
400__I4M label near
401 shl edx,10h ;; Load dx:ax into eax
402 mov dx,ax
403 mov eax,edx
404 mov dx,cx ;; Load cx:bx into edx
405 shl edx,10h
406 mov dx,bx
407 mul edx ;; Multiply eax*edx into edx:eax
408 mov edx,eax ;; Load eax into dx:ax
409 shr edx,10h
410 ret
411__U4M endp
412
413
414; Signed long divide routine;
415; taken from OS/2 Uniaud project, original author: Timur Tabi
416__I4D proc near
417 shl edx,10h ;; Load dx:ax into eax
418 mov dx,ax
419 mov eax,edx
420 cdq ;; Sign extend eax into edx
421 shl ecx,10h ;; Load cx:bx into ecx
422 mov cx,bx
423 idiv ecx ;; Divide eax/ecx into eax
424 mov ecx,edx ;; Load edx into cx:bx
425 shr ecx,10h
426 mov bx,dx
427 mov edx,eax ;; Load eax into dx:ax
428 shr edx,10h
429 ret
430__I4D endp
431
432 .286
433
434_TEXT ENDS
435
436 END
437
Note: See TracBrowser for help on using the repository browser.