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

Last change on this file since 61 was 61, checked in by markus, 15 years ago

removed INT 3 from memcpy (haha, got ya!); removed obsolete atapi_execute_cdb_pp func

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