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

Last change on this file since 133 was 133, checked in by Markus Thielen, 13 years ago
  • (#13) added IDC entry point to allow switching back to BIOS mode
  • added IDCTEST driver and program for testing the IDC entry point
  • fixed bug in IOCTL handling (missing 'break')
File size: 14.4 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 _readl ; MMIO read (32 bits)
17 PUBLIC _writel ; MMIO write (32 bits)
18 PUBLIC _memset ; C memset() implementation
19 PUBLIC _memcpy ; C memcpy() implementation
20 PUBLIC _restart_hook ; port restart context hook
21 PUBLIC _reset_hook ; port reset context hook
22 PUBLIC _engine_hook ; engine trigger context hook
23 PUBLIC _dev_hdr ; device driver header
24 PUBLIC __I4M ; 32bit signed multiply routine
25 PUBLIC __U4M ; 32bit unsigned multiply routine
26 PUBLIC __U4D ; 32bit unsigned divide routine
27 PUBLIC __I4D ; 32bit signed divide routine
28 PUBLIC _end_of_data ; end of all data (label)
29 PUBLIC _end_of_code ; end of all code (label)
30
31; ----------------------------------------------------------------------------
32; Device Driver Header
33
34DEVHDR SEGMENT WORD PUBLIC 'DATA'
35_dev_hdr dd _legacy_hdr ; next device header
36 dw DEVLEV_3 + DEV_CHAR_DEV + DEV_IDC ; flags for ADD drivers
37 dw OFFSET _asm_strat ; strategy routine
38 dw OFFSET _asm_idc_entry ; IDC entry point
39 db "OS2AHCI$" ; name of character device
40 dq 0 ; 8 reserved bytes
41 dd DEV_IOCTL2 + DEV_ADAPTER_DD + DEV_INITCOMPLETE + 20h ; ADD flags
42 dw 0
43
44_legacy_hdr dd -1 ; no headers after this one
45 dw DEVLEV_3 + DEV_CHAR_DEV ; flags for ADD drivers
46 dw OFFSET _asm_strat ; strategy routine
47 dw 0 ; IDC entry point
48 db "IBMS506$" ; name of character device
49 dq 0 ; 8 reserved bytes
50 dd 0
51 dw 0
52DEVHDR ENDS
53
54; ----------------------------------------------------------------------------
55; Segment Definitions. We need to reference all segments here, even if they
56; are not used, to allow proper grouping of all segments into one group for
57; data and one group for code as well as proper ordering of the segments
58; within each group to make sure the end of segment markers are at the end
59; of each group.
60
61; On top of that, we need to make sure that the end of segment marker is in
62; a data segment of class 'BSS' because BSS segments are always put towards
63; the end of the executable when linking with high-level language objects
64; such as C.
65
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
73CONST SEGMENT WORD PUBLIC 'CONST'
74CONST ENDS
75
76_BSS SEGMENT WORD PUBLIC 'BSS'
77_BSS ENDS
78
79c_common SEGMENT WORD PUBLIC 'BSS'
80 EXTRN _debug : WORD ; global debug flag
81c_common ENDS
82
83_z_data SEGMENT WORD PUBLIC 'BSS'
84_end_of_data db 0
85_z_data ENDS
86
87_TEXT SEGMENT WORD PUBLIC 'CODE'
88 EXTRN _c_strat : NEAR ; C strategy routine
89 EXTRN _printf : NEAR ; C printf routine
90 EXTRN _restart_ctxhook : NEAR ; C restart context hook
91 EXTRN _reset_ctxhook : NEAR ; C reset context hook
92 EXTRN _engine_ctxhook : NEAR ; C engine context hook
93_TEXT ENDS
94
95CODE SEGMENT WORD PUBLIC 'CODE'
96CODE ENDS
97
98RMCode SEGMENT WORD PUBLIC 'CODE'
99RMCode ENDS
100
101LIBCODE SEGMENT WORD PUBLIC 'CODE'
102LIBCODE ENDS
103
104_z_text SEGMENT WORD PUBLIC 'CODE'
105_end_of_code LABEL NEAR
106_z_text ENDS
107
108DGROUP GROUP DEVHDR, _DATA, CONST, _BSS, c_common, _z_data
109TGROUP GROUP _TEXT, CODE, _z_text
110
111; ----------------------------------------------------------------------------
112; Start of code
113
114_TEXT SEGMENT WORD PUBLIC 'CODE'
115 ASSUME DS:DGROUP
116 ASSUME ES:NOTHING
117 ASSUME SS:NOTHING
118
119
120; Device driver main entry point (strategy routine)
121_asm_strat PROC FAR
122
123 ; push request packet address
124 PUSH ES
125 PUSH BX
126 CLD
127
128 ; call C strategy routine
129 CALL _c_strat
130
131 POP BX
132 POP ES
133 MOV WORD PTR ES:[BX+3], AX
134 RET
135_asm_strat ENDP
136
137
138; IDC entry point (Assembler stub)
139_asm_idc_entry PROC FAR
140
141 ; push request packet address
142 PUSH ES
143 PUSH BX
144 CLD
145
146 ; call C IDC entry point - which is the strategy routine
147 CALL _c_strat
148
149 POP BX
150 POP ES
151 MOV WORD PTR ES:[BX+3], AX
152 RET
153_asm_idc_entry ENDP
154
155 .386
156
157
158; Read long value from MMIO address; need to do this here to get real
159; 32-bit operations because at least the AHCI device in VirtualBox doesn't
160; seem to support reading 32-bit MMIO registers in two 16-bit steps.
161;
162; C prototype: u32 readl(void _far *addr);
163_readl PROC NEAR
164 ENTER 0, 0
165
166 ; load 'addr' into ES:EAX
167 LES AX, [BP+4]
168 AND EAX, 0000FFFFh
169
170 ; read MMIO register into EDX and return it in DX:AX
171 MOV EDX, ES:[EAX]
172
173 ; print debug message if debug level is 3+
174 CMP _debug, 3
175 JB no_debug
176 PUSH EDX ; save value read from MMIO port
177 PUSH EDX ; value read from MMIO address
178 PUSH AX ; offset of MMIO address
179 PUSH ES ; segment of MMIO address
180 PUSH OFFSET readl_dbg_fmt
181 CALL _printf
182 ADD SP, 10
183 POP EDX ; restore value read from MMIO port
184
185no_debug: MOV EAX, EDX
186 SHR EDX, 16
187
188 LEAVE
189 RET
190_readl ENDP
191
192
193; Write long value to MMIO address; need to do this here to get real
194; 32-bit operations because at least the AHCI device in VirtualBox doesn't
195; seem to support reading 32-bit MMIO registers in two 16-bit steps and the
196; assumption is that this is the same with writing 32-bit MMIO registers.
197;
198; C prototype: void writel(void _far *addr, u32 val);
199_writel PROC NEAR
200 ENTER 0, 0
201
202 ; load 'addr' into ES:EAX
203 LES AX, [BP+4]
204 AND EAX, 0000FFFFh
205
206 ; load 'val' into EDX, preserving the upper 16 bits of EBP
207 MOV EBX, EBP
208 AND EBP, 0000FFFFh
209 MOV EDX, [EBP+8]
210 MOV EBP, EBX
211
212 ; store 'val' at MMIO address in ES:EAX
213 MOV DWORD PTR ES:[EAX], EDX
214
215 ; print debug message if debug level is 3+
216 CMP _debug, 3
217 JB no_debug2
218 PUSH EDX ; value written to MMIO address
219 PUSH AX ; offset of MMIO address
220 PUSH ES ; segment of MMIO address
221 PUSH OFFSET writel_dbg_fmt
222 CALL _printf
223 ADD SP, 10
224
225no_debug2: LEAVE
226 RET
227_writel ENDP
228
229
230; Halfway-decent 32-bit implementation of memset().
231;
232; C prototype: void *memset(void _far *s, int c, size_t n);
233_memset PROC NEAR
234 ENTER 0, 0
235
236 PUSH DI
237
238 ; load 's' into ES:EDI
239 LES DI, [BP+4]
240 AND EDI, 0000FFFFh
241
242 ; load 'c' into EAX, replicating the low 8 bits all over
243 MOV BL, [BP+8]
244 MOV BH, BL
245 MOV AX, BX
246 SHL EAX, 16
247 MOV AX, BX
248
249 ; load 'n / 4' into ECX
250 MOV CX, [BP+10]
251 SHR CX, 2
252 AND ECX, 0000FFFFh
253
254 ; fill 's' with 32-bit chunks of EAX
255 REP STOSD
256
257 ; set remaining bytes (n % 4)'
258 MOV CX, [BP+10]
259 AND CX, 0003h
260 REP STOSB
261
262 ; return address of 's'
263 LES AX, [BP+4]
264 PUSH ES
265 POP DX
266
267 POP DI
268
269 LEAVE
270 RET
271_memset ENDP
272
273
274; Halfway-decent 32-bit implementation of memcpy().
275;
276; C prototype: void *memcpy(void _far *d, void _far *s, size_t n);
277_memcpy PROC NEAR
278 ENTER 0, 0
279
280 PUSH SI
281 PUSH DI
282 PUSH DS
283
284 ; load 'd' into ES:EDI
285 LES DI, [BP+4]
286 AND EDI, 0000FFFFh
287
288 ; load 's' into DS:ESI
289 LDS SI, [BP+8]
290 AND ESI, 0000FFFFh
291
292 ; load 'n / 4' into ECX
293 MOV CX, [BP+12]
294 SHR CX, 2
295 AND ECX, 0000FFFFh
296
297 ; copy 's' to 'd' in 32-bit chunks
298 REP MOVSD
299
300 ; copy remaining bytes (n % 4)'
301 MOV CX, [BP+12]
302 AND CX, 0003h
303 REP MOVSB
304
305 ; return address of 'd'
306 LES AX, [BP+4]
307 PUSH ES
308 POP DX
309
310 POP DS
311 POP DI
312 POP SI
313
314 LEAVE
315 RET
316_memcpy ENDP
317
318
319; Port restart context hook; context hooks need to save all registers
320; and get the parameter passed to DevHelp_ArmCtxHook() in EAX, thus
321; we need a stub which calls the real context hook.
322_restart_hook PROC FAR
323 PUSHAD
324 PUSH EAX
325 CALL _restart_ctxhook
326 POP EAX
327 POPAD
328 RET
329_restart_hook ENDP
330
331
332; Port reset context hook; context hooks need to save all registers
333; and get the parameter passed to DevHelp_ArmCtxHook() in EAX, thus
334; we need a stub which calls the real context hook.
335_reset_hook PROC FAR
336 PUSHAD
337 PUSH EAX
338 CALL _reset_ctxhook
339 POP EAX
340 POPAD
341 RET
342_reset_hook ENDP
343
344
345; Engine trigger context hook; context hooks need to save all registers
346; and get the parameter passed to DevHelp_ArmCtxHook() in EAX, thus
347; we need a stub which calls the real context hook.
348_engine_hook PROC FAR
349 PUSHAD
350 PUSH EAX
351 CALL _engine_ctxhook
352 POP EAX
353 POPAD
354 RET
355_engine_hook ENDP
356
357
358; Unsigned long divide routine;
359; taken from OS/2 Uniaud project, original author: Timur Tabi
360__U4D proc near
361 shl edx,10h ;; Load dx:ax into eax
362 mov dx,ax
363 mov eax,edx
364 xor edx,edx ;; Zero extend eax into edx
365 shl ecx,10h ;; Load cx:bx into ecx
366 mov cx,bx
367 div ecx ;; Divide eax/ecx into eax
368 mov ecx,edx ;; Load edx into cx:bx
369 shr ecx,10h
370 mov bx,dx
371 mov edx,eax ;; Load eax into dx:ax
372 shr edx,10h
373 ret
374__U4D endp
375
376; Long multiply routine;
377; taken from OS/2 Uniaud project, original author: Timur Tabi
378__U4M proc near
379__I4M label near
380 shl edx,10h ;; Load dx:ax into eax
381 mov dx,ax
382 mov eax,edx
383 mov dx,cx ;; Load cx:bx into edx
384 shl edx,10h
385 mov dx,bx
386 mul edx ;; Multiply eax*edx into edx:eax
387 mov edx,eax ;; Load eax into dx:ax
388 shr edx,10h
389 ret
390__U4M endp
391
392
393; Signed long divide routine;
394; taken from OS/2 Uniaud project, original author: Timur Tabi
395__I4D proc near
396 shl edx,10h ;; Load dx:ax into eax
397 mov dx,ax
398 mov eax,edx
399 cdq ;; Sign extend eax into edx
400 shl ecx,10h ;; Load cx:bx into ecx
401 mov cx,bx
402 idiv ecx ;; Divide eax/ecx into eax
403 mov ecx,edx ;; Load edx into cx:bx
404 shr ecx,10h
405 mov bx,dx
406 mov edx,eax ;; Load eax into dx:ax
407 shr edx,10h
408 ret
409__I4D endp
410
411 .286
412
413_TEXT ENDS
414
415 END
416
Note: See TracBrowser for help on using the repository browser.