]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/hw/llmem/llmemasm.asm
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / hw / llmem / llmemasm.asm
1
2 ; NTS: We use NASM to achieve our goals here because WASM sucks donkey balls
3 ;      Maybe when they bother to implement a proper conditional macro system, I'll consider it...
4
5 %if TARGET_MSDOS == 16
6  %ifndef MMODE
7   %error You must specify MMODE variable (memory model) for 16-bit real mode code
8  %endif
9 %endif
10
11 %if TARGET_MSDOS == 16
12  %ifidni MMODE,l
13   %define retnative retf
14   %define cdecl_param_offset 6  ; RETF addr + PUSH BP
15  %else
16   %ifidni MMODE,m
17    %define retnative retf
18    %define cdecl_param_offset 6 ; RETF addr + PUSH BP
19   %else
20    %define retnative ret
21    %define cdecl_param_offset 4 ; RET addr + PUSH BP
22   %endif
23  %endif
24 %else
25  %define retnative ret
26  %define cdecl_param_offset 8   ; RET addr + PUSH EBP
27 %endif
28
29 ; NTS: Associate our data with Watcom's data segment
30 segment .data public align=4 class=data
31
32 %if TARGET_MSDOS == 16
33 ; ext vars
34 ; uint32_t far* near    llmemcpy_gdt = NULL;
35 extern _llmemcpy_gdt
36 ; uint16_t near         llmemcpy_gdtr[4];
37 extern _llmemcpy_gdtr
38 ; uint16_t near         llmemcpy_idtr[4];
39 extern _llmemcpy_idtr
40 ; uint32_t near         llmemcpy_vcpi[0x20];
41 extern _llmemcpy_vcpi
42 ; uint32_t near         llmemcpy_vcpi_return[2];
43 extern _llmemcpy_vcpi_return
44 ; volatile void FAR*    llmemcpy_pagetables = NULL;
45 extern _llmemcpy_pagetables
46 %endif
47
48 ; NTS: Help NASM put the code segment in the right place for Watcom to link it in properly
49 segment text public align=1 class=code
50
51 %if TARGET_MSDOS == 16
52
53 global llmem_memcpy_16_inner_pae_
54 llmem_memcpy_16_inner_pae_:
55                 ; save sregs
56                 push    es
57                 push    ds
58                 push    ss
59
60                 ; patch exit jmp
61                 mov     ax,cs
62                 mov     word [cs:exit_pae_patch+1+2],ax
63
64                 ; jump into protected mode, with paging
65                 mov     eax,cr0
66                 or      eax,0x80000001
67                 mov     cr0,eax
68                 jmp     0x08:entry_pae
69 entry_pae:
70
71                 ; load the data selectors
72                 mov     ax,0x10
73                 mov     ds,ax
74                 mov     ax,0x18
75                 mov     es,ax
76                 mov     ax,0x20
77                 mov     ss,ax
78
79                 ; do the memcpy
80                 mov     edx,ecx
81                 and     edx,3
82                 shr     ecx,2
83                 cld
84
85                 es rep  a32 movsd
86
87                 mov     ecx,edx
88                 es rep  a32 movsb
89
90                 ; get out of protected mode
91                 mov     eax,cr0
92                 and     eax,0x7FFFFFFE
93                 mov     cr0,eax
94 exit_pae_patch:
95                 jmp     0:exit_pae
96 exit_pae:
97
98                 ; restore sregs
99                 pop     ss
100                 pop     ds
101                 pop     es
102
103                 retnative
104
105 global llmem_memcpy_16_inner_pse_
106 llmem_memcpy_16_inner_pse_:
107                 ; save sregs
108                 push    es
109                 push    ds
110                 push    ss
111
112                 ; patch exit jmp
113                 mov     ax,cs
114                 mov     word [cs:exit_pse_patch+1+2],ax
115
116                 ; jump into protected mode, with paging
117                 mov     eax,cr0
118                 or      eax,0x80000001
119                 mov     cr0,eax
120                 jmp     0x08:entry_pse
121 entry_pse:
122
123                 ; load the data selectors
124                 mov     ax,0x10
125                 mov     ds,ax
126                 mov     ax,0x18
127                 mov     es,ax
128                 mov     ax,0x20
129                 mov     ss,ax
130
131                 ; do the memcpy
132                 mov     edx,ecx
133                 and     edx,3
134                 shr     ecx,2
135                 cld
136
137                 es rep  a32 movsd
138
139                 mov     ecx,edx
140                 es rep  a32 movsb
141
142                 ; get out of protected mode
143                 mov     eax,cr0
144                 and     eax,0x7FFFFFFE
145                 mov     cr0,eax
146 exit_pse_patch:
147                 jmp     0:exit_pse
148 exit_pse:
149
150                 ; restore sregs
151                 pop     ss
152                 pop     ds
153                 pop     es
154
155                 retnative
156
157 ; alternate version to do PSE llmemcpy when VCPI/EMM386.EXE is active.
158 ; void __cdecl llmem_memcpy_16_inner_pse_vcpi(uint32_t dst,uint32_t src,uint32_t cpy);
159 global _llmem_memcpy_16_inner_pse_vcpi
160 _llmem_memcpy_16_inner_pse_vcpi:
161                 push    bp
162 ; extra vars
163                 push    cs      ; +14
164                 push    ds      ; +12
165                 push    es      ; +10
166                 push    ss      ; +8
167
168 ; we need to store _llmemcpy_vcpi_return on the stack. once we're in protected mode
169 ; the FAR pointers given by Watcom are not usable.
170                 mov     si,seg _llmemcpy_vcpi_return
171                 mov     fs,si
172                 mov     si,_llmemcpy_vcpi_return
173                 mov     eax,[fs:si+4] ; segment
174                 push    eax     ; +4
175                 xor     eax,eax
176                 push    eax     ; +0
177
178 %define extra           16      ; +16
179 ; end extra
180                 mov     bp,sp
181
182                 mov     ax,seg _llmemcpy_pagetables
183                 mov     fs,ax
184                 xor     edi,edi
185                 les     di,[fs:_llmemcpy_pagetables]
186                 add     edi,0x1000
187
188                 mov     ax,seg _llmemcpy_gdt
189                 mov     fs,ax
190                 xor     esi,esi
191                 lds     si,[fs:_llmemcpy_gdt]
192                 add     esi,5 << 3
193
194                 ; so: DS:SI = First GDT available to VCPI server
195                 ;     ES:DI = Page dir 0 page 0 4KB page
196                 mov     ax,0xDE01
197                 int     67h
198                 cmp     ah,0
199                 jz      .info_ok
200 ; ==ERROR==
201                 mov     eax,0xAABBCC01
202                 jmp     short $
203 ; ==END ERROR==
204 .info_ok:       ; we need EBX, the return entry point offset
205                 mov     [bp+0],ebx
206
207                 ; now enter VCPI protected mode
208                 mov     bx,seg _llmemcpy_vcpi
209                 mov     fs,bx
210                 mov     dword [fs:_llmemcpy_vcpi+0x10],.vcpi_entry
211
212                 xor     esi,esi
213                 mov     si,seg _llmemcpy_vcpi
214                 shl     esi,4
215                 add     esi,_llmemcpy_vcpi
216
217                 mov     ax,0xDE0C
218                 int     67h
219                 hlt             ; <- BRICK WALL in case of errant VCPI server
220
221 .vcpi_entry:    mov     ax,2 << 3
222                 mov     ds,ax
223
224                 mov     ax,3 << 3
225                 mov     es,ax
226                 mov     fs,ax
227                 mov     gs,ax
228
229                 mov     ax,4 << 3
230                 mov     ss,ax
231
232                 ; switch on PSE. note we couldn't do this from the real-mode side
233                 ; since the v86 monitor would likely not allow that
234                 mov     eax,cr4
235                 or      eax,0x10
236                 mov     cr4,eax
237
238                 mov     ecx,[bp+cdecl_param_offset+extra+8]     ; cpy
239                 mov     esi,[bp+cdecl_param_offset+extra+4]     ; src
240                 mov     edi,[bp+cdecl_param_offset+extra+0]     ; dst
241
242                 cld
243                 push    ecx
244                 shr     ecx,2
245                 a32 rep es movsd
246                 pop     ecx
247                 and     ecx,3
248                 a32 rep es movsb
249
250                 ; switch off PSE. once we're back in v86 mode we can't touch control regs
251                 mov     eax,cr4
252                 and     eax,~0x10
253                 mov     cr4,eax
254
255                 ; set up return to v86 mode
256                 and     esp,0xFFFF      ; <--- THIS IS VERY IMPORTANT ON RETURN FROM VCPI, UPPER BITS OF ESP CAN BE NONZERO
257                 xor     eax,eax
258                 mov     ax,[bp+12]      ; DS
259                 push    eax             ; SS:ESP+0x28 GS
260                 push    eax             ; SS:ESP+0x24 FS
261                 push    eax             ; SS:ESP+0x20 DS
262                 mov     ax,[bp+10]
263                 push    eax             ; SS:ESP+0x1C ES
264                 mov     ax,[bp+8]
265                 push    eax             ; SS:ESP+0x18 SS
266                 mov     eax,ebp
267                 push    eax             ; SS:ESP+0x14 ESP
268                 pushfd                  ; SS:ESP+0x10 EFLAGS
269                 mov     ax,[bp+14]
270                 push    eax             ; SS:ESP+0x0C CS
271                 push    dword .vcpi_exit; SS:ESP+0x08 EIP
272                 mov     eax,[bp+4]      ; VCPI code segment
273                 push    eax             ; SS:ESP+0x04 VCPI code segment
274                 mov     eax,[bp+0]      ; VCPI offset
275                 push    eax
276                 mov     eax,0xDE0C      ; switch back to v86
277                 jmp far dword [esp]     ; <--- 32-bit address mode required for direct use of SP, but only if we refer to ESP
278 .vcpi_exit:
279
280                 add     sp,extra
281                 pop     bp
282                 retnative
283 %undef extra
284
285 ; alternate version to do PAE llmemcpy when VCPI/EMM386.EXE is active.
286 ; void __cdecl llmem_memcpy_16_inner_pae_vcpi(uint32_t dst,uint32_t src,uint32_t cpy);
287 global _llmem_memcpy_16_inner_pae_vcpi
288 _llmem_memcpy_16_inner_pae_vcpi:
289                 push    bp
290 ; extra vars
291
292                 xor     esi,esi
293                 xor     edi,edi
294                 mov     si,seg _llmemcpy_pagetables
295                 mov     fs,si
296                 mov     si,[fs:_llmemcpy_pagetables+2]
297                 shl     esi,4
298                 mov     di,[fs:_llmemcpy_pagetables]
299                 add     esi,edi
300                 push    esi     ; +16
301
302                 push    cs      ; +14
303                 push    ds      ; +12
304                 push    es      ; +10
305                 push    ss      ; +8
306
307 ; we need to store _llmemcpy_vcpi_return on the stack. once we're in protected mode
308 ; the FAR pointers given by Watcom are not usable.
309                 mov     si,seg _llmemcpy_vcpi_return
310                 mov     fs,si
311                 mov     si,_llmemcpy_vcpi_return
312                 mov     eax,[fs:si+4] ; segment
313                 push    eax     ; +4
314                 xor     eax,eax
315                 push    eax     ; +0
316
317 %define extra           20      ; +20
318 ; end extra
319                 mov     bp,sp
320
321                 ; we're going to give the VCPI server the last 4KB page in the 36KB
322                 ; buffer allocated by the function, set aside for that purpose.
323                 ; what we're then going to do is copy and translate that page table
324                 ; to the 64-bit form required by PAE, initially starting from the
325                 ; 32-bit form in the last 8KB
326                 mov     ax,seg _llmemcpy_pagetables
327                 mov     fs,ax
328                 xor     edi,edi
329                 les     di,[fs:_llmemcpy_pagetables]
330                 add     edi,0x8000      ; +32KB
331
332                 mov     ax,seg _llmemcpy_gdt
333                 mov     fs,ax
334                 xor     esi,esi
335                 lds     si,[fs:_llmemcpy_gdt]
336                 add     esi,5 << 3
337
338                 ; so: DS:SI = First GDT available to VCPI server
339                 ;     ES:DI = Page dir 0 page 0 4KB page
340                 mov     ax,0xDE01
341                 int     67h
342                 cmp     ah,0
343                 jz      .info_ok
344 ; ==ERROR==
345                 mov     eax,0xAABBCC01
346                 jmp     short $
347 ; ==END ERROR==
348 .info_ok:       ; we need EBX, the return entry point offset
349                 mov     [bp+0],ebx
350
351                 ; now enter VCPI protected mode
352                 mov     bx,seg _llmemcpy_vcpi
353                 mov     fs,bx
354                 mov     dword [fs:_llmemcpy_vcpi+0x10],.vcpi_entry
355
356                 xor     esi,esi
357                 mov     si,seg _llmemcpy_vcpi
358                 shl     esi,4
359                 add     esi,_llmemcpy_vcpi
360
361                 mov     ax,0xDE0C
362                 int     67h
363                 hlt             ; <- BRICK WALL in case of errant VCPI server
364
365 .vcpi_entry:    mov     ax,2 << 3
366                 mov     ds,ax
367
368                 mov     ax,3 << 3
369                 mov     es,ax
370                 mov     fs,ax
371                 mov     gs,ax
372
373                 mov     ax,4 << 3
374                 mov     ss,ax
375
376                 ; switch on PSE. note we couldn't do this from the real-mode side
377                 ; since the v86 monitor would likely not allow that
378                 mov     eax,cr4
379                 or      eax,0x10
380                 mov     cr4,eax
381
382                 ; copy the first 4MB of 32-bit page tables and translate to 64-bit
383                 mov     eax,[bp+16]                             ; _llmemcpy_pagetables
384                 lea     esi,[eax+0x8000]                        ; source: 32-bit VCPI page zero
385                 lea     edi,[eax+0x5000]                        ; dest: 64-bit page zero and one
386                 mov     ecx,1024                                ; 1024 x 32-bit -> 1024 x 64-bit (4KB -> 8KB)
387                 cld
388 .xlate_loop:    a32 es  movsd                                   ; lower 32 bits -> 64 bits with upper bits zero
389                 xor     eax,eax
390                 a32 stosd
391                 loop    .xlate_loop
392
393                 ; switch on PAE, reload CR3. Temporarily shut down paging to accomplish that.
394                 ; most likely: as a DOS program in the 1MB area we're not remapped and it won't affect us.
395                 mov     ecx,cr0
396                 and     ecx,0x7FFFFFFF
397                 mov     cr0,ecx                                 ; CR0=Disable PE
398                 mov     ebx,[bp+16]                             ; _llmemcpy_pagetables
399                 mov     cr3,ebx                                 ; CR3=new 64-bit page table
400                 mov     eax,cr4
401                 or      eax,0x30
402                 mov     cr4,eax                                 ; CR4=PSE and PAE
403                 or      ecx,0x80000000
404                 mov     cr0,ecx                                 ; CR0=Enable PE
405
406                 mov     ecx,[bp+cdecl_param_offset+extra+8]     ; cpy
407                 mov     esi,[bp+cdecl_param_offset+extra+4]     ; src
408                 mov     edi,[bp+cdecl_param_offset+extra+0]     ; dst
409
410                 cld
411                 push    ecx
412                 shr     ecx,2
413                 a32 rep es movsd
414                 pop     ecx
415                 and     ecx,3
416                 a32 rep es movsb
417
418                 ; switch on PAE, reload CR3. Temporarily shut down paging to accomplish that.
419                 ; most likely: as a DOS program in the 1MB area we're not remapped and it won't affect us.
420                 mov     ecx,cr0
421                 and     ecx,0x7FFFFFFF
422                 mov     cr0,ecx                                 ; CR0=Disable PE
423                 mov     ebx,[bp+16]                             ; _llmemcpy_pagetables
424                 add     ebx,0x7000                              ; point at 32-bit tables
425                 mov     cr3,ebx                                 ; CR3=new 64-bit page table
426                 mov     eax,cr4
427                 and     eax,~0x30
428                 mov     cr4,eax                                 ; CR4=Disable PSE and PAE
429                 or      ecx,0x80000000
430                 mov     cr0,ecx                                 ; CR0=Enable PE
431
432                 ; set up return to v86 mode
433                 and     esp,0xFFFF      ; <--- THIS IS VERY IMPORTANT ON RETURN FROM VCPI, UPPER BITS OF ESP CAN BE NONZERO
434                 xor     eax,eax
435                 mov     ax,[bp+12]      ; DS
436                 push    eax             ; SS:ESP+0x28 GS
437                 push    eax             ; SS:ESP+0x24 FS
438                 push    eax             ; SS:ESP+0x20 DS
439                 mov     ax,[bp+10]
440                 push    eax             ; SS:ESP+0x1C ES
441                 mov     ax,[bp+8]
442                 push    eax             ; SS:ESP+0x18 SS
443                 mov     eax,ebp
444                 push    eax             ; SS:ESP+0x14 ESP
445                 pushfd                  ; SS:ESP+0x10 EFLAGS
446                 mov     ax,[bp+14]
447                 push    eax             ; SS:ESP+0x0C CS
448                 push    dword .vcpi_exit; SS:ESP+0x08 EIP
449                 mov     eax,[bp+4]      ; VCPI code segment
450                 push    eax             ; SS:ESP+0x04 VCPI code segment
451                 mov     eax,[bp+0]      ; VCPI offset
452                 push    eax
453                 mov     eax,0xDE0C      ; switch back to v86
454                 jmp far dword [esp]     ; <--- 32-bit address mode required for direct use of SP, but only if we refer to ESP
455 .vcpi_exit:
456
457                 add     sp,extra
458                 pop     bp
459                 retnative
460 %undef extra
461
462 %endif