]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/dos/himemsys.c
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / dos / himemsys.c
1 /* himemsys.c
2  *
3  * Support calls to use HIMEM.SYS
4  * (C) 2009-2012 Jonathan Campbell.
5  * Hackipedia DOS library.
6  *
7  * This code is licensed under the LGPL.
8  * <insert LGPL legal text here>
9  */
10
11 /* HIMEM.SYS api for DOS programs library
12  *
13  *
14  *
15  *
16  * Testing:
17  *
18  * System/configuration                 Works?   Supports >= 64MB?
19  * DOSBox 0.74                          YES      NO, BUGS
20  * DOSBox 0.74 +
21  *   Microsoft Windows 3.0
22  *     Real mode                        YES      --
23  *     Standard mode                    NO       --                      Reports 0KB free memory (why?)
24  *     386 Enhanced mode                YES      --
25  *   Microsoft Windows 3.1
26  *     Standard mode                    NO       --                      Reports 0KB free memory (why?)
27  *     386 Enhanced mode                YES      --
28  *   Microsoft Windows 3.11
29  *     Standard mode                    NO       --                      Reports 0KB free memory (why?)
30  *     386 Enhanced mode                YES      --
31  * QEMU +
32  *   Microsoft Windows 95 (4.00.950)
33  *     Normal mode                      YES      YES                     Allows my program to request more memory than available, then triggers the "needs MS-DOS mode" warning (PIF: XMS memory setting on "auto")
34  *     Normal mode (PIF: XMS=2MB)       YES      YES                     This program's attempts to alloc > 1MB fail (correctly). It still triggers the "needs MS-DOS mode" dialog
35  *     Safe mode                        YES      YES                     Allows my program to request more memory than available, then triggers the "needs MS-DOS mode" warning (PIF: XMS memory setting on "auto")
36  *     MS-DOS mode (official)           YES      YES
37  *     MS-DOS mode (gui=0)              YES      YES
38  *       * NOTE: I also noticed that within the DOS box the Windows kernel denies all requests to lock a handle
39  *   Microsoft Windows 98 (4.10.1998)
40  *     Normal mode                      YES      YES                     Same problem as Windows 95
41  *     MS-DOS mode (gui=0)              YES      YES
42  *   Microsoft Windows ME (4.90.3000)
43  *     Normal mode                      YES      YES                     Same problem as Windows 95, triggers "needs MS-DOS mode" warning----Hey wait, Windows ME doesn't have a "DOS mode". A hilarious oversight by Microsoft.
44  *   Microsoft Windows 2000 Professional
45  *     Normal mode                      YES      NO                      NTVDM is very conservative about HIMEM.SYS allocation, listing the largest block size as 919KB. So apparently the default is that MS-DOS
46  *                                                                       applications are allowed up to 1MB of extended memory? The usual MS-DOS configuration options are there, suggesting that in reality the
47  *                                                                       program should have NO extended memory (?). Apparently when you say "none" what it really means is "1MB". Locking the handle is permitted though.
48  *                                                                       The highest value you can enter in the PIF through the GUI is 65534. Setting to 65535 somehow triggers internally the "auto" setting, and is
49  *                                                                       the highest value the editor will let you type in.
50  *   Microsoft Windows XP Professional
51  *     Normal mode                      YES      NO                      Same problems as Windows 2000
52  */
53
54 #include <stdlib.h>
55 #include <string.h>
56 #include <stdint.h>
57 #include <assert.h>
58 #include <stdio.h>
59 #include <conio.h>
60 #include <dos.h>
61
62 #include <hw/cpu/cpu.h>
63 #include <hw/dos/dos.h>
64 #include <hw/dos/himemsys.h>
65
66 #if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
67 /*===================================== MS-DOS only ===================================*/
68
69 unsigned long himem_sys_largest_free = 0;
70 unsigned long himem_sys_total_free = 0;
71 unsigned char himem_sys_present = 0;
72 unsigned int himem_sys_version = 0;
73 unsigned long himem_sys_entry = 0;
74 unsigned char himem_sys_flags = 0;
75
76 #if TARGET_MSDOS == 32
77 static void himem_sys_realmode_2F_call(struct dpmi_realmode_call *rc) {
78         __asm {
79                 mov     ax,0x0300
80                 mov     bx,0x002F
81                 xor     cx,cx
82                 mov     edi,rc          ; we trust Watcom has left ES == DS
83                 int     0x31            ; call DPMI
84         }
85 }
86
87 /* WARNING: If this code is run under DOS4/GW it will silently fail.
88             If the HIMEM.SYS test program spouts nonsense about a
89             HIMEM.SYS that is v0.00 and has some random amount of memory
90             open, that's why. Make sure you link with dos32a. If that's
91             not possible, then run your program with dos32 like this:
92
93             dos32a <program> */
94 static void himem_sys_realmode_entry_call(struct dpmi_realmode_call *rc) {
95         rc->ip = himem_sys_entry & 0xFFFF;
96         rc->cs = (himem_sys_entry >> 16UL);
97
98         if (dpmi_no_0301h > 0) {
99                 /* Fuck you DOS4/GW! */
100                 dpmi_alternate_rm_call(rc);
101         }
102         else {
103                 __asm {
104                         mov     ax,0x0301
105                         xor     bx,bx
106                         xor     cx,cx
107                         mov     edi,rc          ; we trust Watcom has left ES == DS
108                         int     0x31            ; call DPMI
109                 }
110         }
111 }
112
113 int probe_himem_sys() {
114         struct dpmi_realmode_call rc={0};
115         union REGS regs;
116
117         himem_sys_present = 0;
118
119 #if TARGET_MSDOS == 32
120         /* WAIT!!! We might be running under DOS4/GW. Make sure we can
121            call real-mode subroutines with the DPMI server. */
122         if (dpmi_no_0301h < 0) probe_dpmi();
123 #endif
124
125         regs.w.ax = 0x4300;
126         int386(0x2F,&regs,&regs);
127         if (regs.h.al != 0x80) return 0;
128         himem_sys_present = 1;
129
130         /* use the realmode DPMI call to ensure the DPMI server does not screw up (translate) the segment register */
131         rc.eax = 0x4310;
132         himem_sys_realmode_2F_call(&rc);
133         himem_sys_entry =
134                 ((unsigned long)rc.es << 16UL) |
135                 ((unsigned long)rc.ebx & 0xFFFFUL);
136
137         /* get version info, and autodetect whether it supports extended functions */
138         rc.eax = 0;
139         himem_sys_realmode_entry_call(&rc);
140         himem_sys_version = rc.eax & 0xFFFF;
141         himem_sys_flags = (rc.edx & 1) ? HIMEM_F_HMA : 0; /* FIXME: Am I crazy, or does HIMEM.SYS suddenly stop mentioning HMA when we call from protected mode? */
142
143         rc.ebx = 0;
144         rc.eax = 0x8800;
145         himem_sys_realmode_entry_call(&rc);
146         himem_sys_flags = (rc.ebx & 0xFF == 0x80) ? 0 : HIMEM_F_4GB;
147
148         return 1;
149 }
150
151 int himem_sys_global_a20(int enable) {
152         struct dpmi_realmode_call rc={0};
153         if (!himem_sys_present) return 0;
154         rc.eax = ((enable > 0) ? 3 : 4) << 8;
155         himem_sys_realmode_entry_call(&rc);
156         return rc.eax;
157 }
158
159 int himem_sys_local_a20(int enable) {
160         struct dpmi_realmode_call rc={0};
161         if (!himem_sys_present) return 0;
162         rc.eax = ((enable > 0) ? 5 : 6) << 8;
163         himem_sys_realmode_entry_call(&rc);
164         return rc.eax;
165 }
166
167 int himem_sys_query_a20() {
168         struct dpmi_realmode_call rc={0};
169         if (!himem_sys_present) return 0;
170         rc.eax = 7 << 8;
171         himem_sys_realmode_entry_call(&rc);
172         return rc.eax;
173 }
174
175 /* NTS: This function will likely set largest & free variables to zero,
176  *      because most 32-bit DOS extenders take up all extended memory to do their work */
177 void himem_sys_update_free_memory_status() {
178         struct dpmi_realmode_call rc={0};
179         if (!himem_sys_present) return;
180
181         if (himem_sys_flags & HIMEM_F_4GB) {
182                 rc.eax = 0x88 << 8;
183                 himem_sys_realmode_entry_call(&rc);
184                 himem_sys_largest_free = rc.eax;
185                 himem_sys_total_free = rc.edx;
186         }
187         else {
188                 rc.eax = 8 << 8;
189                 himem_sys_realmode_entry_call(&rc);
190                 himem_sys_largest_free = rc.eax & 0xFFFF;
191                 himem_sys_total_free = rc.edx & 0xFFFF;
192         }
193 }
194
195 int __cdecl himem_sys_alloc(unsigned long size/* in KB---not bytes*/) {
196         struct dpmi_realmode_call rc={0};
197         int handle = -1;
198
199         if (himem_sys_present) {
200                 if (himem_sys_flags & HIMEM_F_4GB) {
201                         rc.eax = 0x89 << 8;
202                         rc.edx = size;
203                         himem_sys_realmode_entry_call(&rc);
204                         if ((rc.eax & 0xFFFF) == 1) handle = rc.edx & 0xFFFF;
205                 }
206                 else {
207                         if (size >= 65535UL) return -1;
208                         rc.eax = 9 << 8;
209                         rc.edx = size & 0xFFFF;
210                         himem_sys_realmode_entry_call(&rc);
211                         if ((rc.eax & 0xFFFF) == 1) handle = rc.edx & 0xFFFF;
212                 }
213         }
214
215         return handle;
216 }
217
218 int himem_sys_free(int handle) {
219         struct dpmi_realmode_call rc={0};
220         rc.eax = 10 << 8;
221         rc.edx = handle & 0xFFFF;
222         himem_sys_realmode_entry_call(&rc);
223         return (int)(rc.eax & 0xFFFF);
224 }
225
226 int himem_sys_move(unsigned int dst_handle,uint32_t dst_offset,unsigned int src_handle,uint32_t src_offset,uint32_t length) {
227         struct dpmi_realmode_call rc={0};
228         unsigned char *tmp;
229         uint16_t tmpsel=0;
230         int retv = 0;
231
232         if ((tmp = (unsigned char*)dpmi_alloc_dos(16,&tmpsel)) == NULL)
233                 return 0;
234
235         if (himem_sys_present) {
236                 /* for src or dest references with handle == 0 the HIMEM.SYS driver actually
237                  * takes SEG:OFFSET but we allow the caller to give us a physical memory addr. */
238                 if (src_handle == 0)
239                         src_offset = ((src_offset << 12) & 0xFFFF0000UL) | (src_offset & 0xFUL);
240                 if (dst_handle == 0)
241                         dst_offset = ((dst_offset << 12) & 0xFFFF0000UL) | (dst_offset & 0xFUL);
242
243                 *((uint32_t*)(tmp+0x0)) = length;
244                 *((uint16_t*)(tmp+0x4)) = src_handle;
245                 *((uint32_t*)(tmp+0x6)) = src_offset;
246                 *((uint16_t*)(tmp+0xA)) = dst_handle;
247                 *((uint32_t*)(tmp+0xC)) = dst_offset;
248                 {
249                         const uint16_t ofsv = (uint16_t)tmp & 0xFUL;
250                         const uint16_t segv = (uint16_t)((size_t)tmp >> 4UL);
251                         rc.eax = 0x0B << 8;
252                         rc.esi = ofsv;
253                         rc.ds = segv;
254                         rc.es = segv;
255                         himem_sys_realmode_entry_call(&rc);
256                         retv = rc.eax & 0xFFFF;
257                 }
258         }
259
260         dpmi_free_dos(tmpsel);
261         return retv;
262 }
263
264 uint32_t himem_sys_lock(unsigned int handle) {
265         struct dpmi_realmode_call rc={0};
266         uint32_t o = 0UL;
267
268         if (himem_sys_present) {
269                 rc.eax = 0x0C << 8;
270                 rc.edx = handle & 0xFFFF;
271                 himem_sys_realmode_entry_call(&rc);
272                 if (rc.eax & 1) o = ((rc.edx & 0xFFFF) << 16) | (rc.ebx & 0xFFFF);
273         }
274
275         return o;
276 }
277
278 int himem_sys_unlock(unsigned int handle) {
279         struct dpmi_realmode_call rc={0};
280         int retv = 0;
281
282         if (himem_sys_present) {
283                 rc.eax = 0x0D << 8;
284                 rc.edx = handle & 0xFFFF;
285                 himem_sys_realmode_entry_call(&rc);
286                 retv = rc.eax & 0xFFFF;
287         }
288
289         return retv;
290 }
291
292 int himem_sys_realloc(unsigned int handle,unsigned long size/* in KB---not bytes*/) {
293         struct dpmi_realmode_call rc={0};
294         int retv = 0;
295
296         if (himem_sys_present) {
297                 if (himem_sys_flags & HIMEM_F_4GB) {
298                         rc.eax = 0x8F << 8;
299                         rc.ebx = size;
300                         rc.edx = handle & 0xFFFF;
301                         himem_sys_realmode_entry_call(&rc);
302                         retv = rc.eax & 0xFFFF;
303                 }
304                 if (retv == 0) {
305                         if (size >= 65535UL) return 0;
306                         rc.eax = 0x0F << 8;
307                         rc.ebx = size;
308                         rc.edx = handle & 0xFFFF;
309                         himem_sys_realmode_entry_call(&rc);
310                         retv = rc.eax & 0xFFFF;
311                 }
312         }
313
314         return retv;
315 }
316
317 int himem_sys_get_handle_info(unsigned int handle,struct himem_block_info *b) {
318         struct dpmi_realmode_call rc={0};
319         int retv = 0;
320
321         if (himem_sys_present) {
322                 if (himem_sys_flags & HIMEM_F_4GB) {
323                         rc.eax = 0x8E << 8;
324                         rc.edx = handle & 0xFFFF;
325                         himem_sys_realmode_entry_call(&rc);
326                         b->block_length_kb = rc.edx;
327                         b->lock_count = (rc.ebx >> 8) & 0xFF;
328                         b->free_handles = rc.ebx & 0xFF;
329                         retv = rc.eax & 0xFFFF;
330                 }
331                 if (retv == 0) {
332                         rc.eax = 0x0E << 8;
333                         rc.edx = handle & 0xFFFF;
334                         himem_sys_realmode_entry_call(&rc);
335                         b->block_length_kb = rc.edx & 0xFFFF;
336                         b->lock_count = (rc.ebx >> 8) & 0xFF;
337                         b->free_handles = rc.ebx & 0xFF;
338                         retv = rc.eax & 0xFFFF;
339                 }
340         }
341
342         return retv;
343 }
344 #else /* 16-bit real mode */
345 int probe_himem_sys() {
346         struct SREGS sregs;
347         union REGS regs;
348
349         himem_sys_present = 0;
350         /* NTS: If this is an 8086, then there is no extended memory, and therefore no reason to call HIMEM.SYS */
351         if (cpu_basic_level < 0) cpu_probe();
352         if (cpu_basic_level < 2) return 0;
353
354         regs.w.ax = 0x4300;
355         int86(0x2F,&regs,&regs);
356         if (regs.h.al != 0x80) return 0;
357         himem_sys_present = 1;
358
359         regs.w.ax = 0x4310;
360         int86x(0x2F,&regs,&regs,&sregs);
361         himem_sys_entry =
362                 ((unsigned long)sregs.es << 16UL) |
363                 ((unsigned long)regs.w.bx);
364
365         __asm {
366                 xor     ah,ah           ; function 0x00
367                 call    [himem_sys_entry]
368                 mov     himem_sys_version,ax
369                 and     dl,1            ; DX=1 if HMA present, else 0 if not. Your HIMEM.SYS is noncompliant if any other values were put here
370                 mov     himem_sys_flags,dl ; this maps to HIMEM_F_HMA
371         }
372
373         /* does this HIMEM.SYS support the extended functions to address more than 64MB of memory? */
374         __asm {
375                 mov     ah,0x88         ; function 0x88: query any free memory
376                 mov     bl,0x80
377                 call    [himem_sys_entry]
378                 cmp     bl,0x80         ; BL=0x80 if error (unsupported)
379                 jz      label1
380                 or      himem_sys_flags,2 ; <- HIMEM_F_4GB
381 label1:
382         }
383
384         /* Unfortunately, there are HIMEM.SYS implementations that will respond to the extended commands, but fail
385            to read or make use of the upper 16 bits of the registers. These broken implementations are easy to check
386            for: just allocate a block that is 64MB in size (DX == 0 but EDX == 0x00010000) and if the allocation
387            succeeds, use the Get Block Info command to verify that it is in fact 64MB in size. The broken implementation
388            will create a zero-length block (which is legal in the HIMEM.SYS standard) and will say so when we ask.
389           
390            Known HIMEM.SYS broken emulation:
391                 DOSBox 0.74:
392                     - Responds to extended commands as if newer HIMEM.SYS but ignores upper 16 bits. You might as well
393                       just call the original API functions you'll get just as far. DOSBox doesn't emulate more than 64MB
394                       anyway. */
395         if (himem_sys_flags & HIMEM_F_4GB) {
396                 int h = himem_sys_alloc(0x10000UL);
397                 if (h != -1) {
398                         struct himem_block_info binf;
399                         if (himem_sys_get_handle_info(h,&binf)) {
400                                 if (binf.block_length_kb == 0 || binf.block_length_kb == 1) {
401                                         /* Nope. Our 64MB allocation was mis-interpreted as a zero-length allocation request */
402                                         himem_sys_flags &= ~HIMEM_F_4GB;
403                                 }
404                         }
405                         himem_sys_free(h);
406                 }
407         }
408
409         return 1;
410 }
411
412 int himem_sys_global_a20(int enable) {
413         int retv=0;
414
415         if (!himem_sys_present) return 0;
416         enable = (enable > 0) ? 3 : 4;
417
418         __asm {
419                 mov     ah,byte ptr enable
420                 call    [himem_sys_entry]
421                 mov     retv,ax
422         }
423
424         return retv;
425 }
426
427 int himem_sys_local_a20(int enable) {
428         int retv=0;
429
430         if (!himem_sys_present) return 0;
431         enable = (enable > 0) ? 5 : 6;
432
433         __asm {
434                 mov     ah,byte ptr enable
435                 call    [himem_sys_entry]
436                 mov     retv,ax
437         }
438
439         return retv;
440 }
441
442 int himem_sys_query_a20() {
443         int retv=0;
444
445         if (!himem_sys_present) return 0;
446
447         __asm {
448                 mov     ah,7
449                 call    [himem_sys_entry]
450                 mov     retv,ax
451         }
452
453         return retv;
454 }
455
456 void himem_sys_update_free_memory_status() {
457         if (!himem_sys_present) return;
458
459         if (himem_sys_flags & HIMEM_F_4GB) {
460                 __asm {
461                         mov     ah,0x88
462                         call    [himem_sys_entry]
463
464                         mov     word ptr himem_sys_largest_free,ax
465                         db      0x66,0xC1,0xE8,0x10 ; shr eax,16
466                         mov     word ptr himem_sys_largest_free+2,ax
467
468                         mov     word ptr himem_sys_total_free,dx
469                         db      0x66,0xC1,0xEA,0x10 ; shr edx,16
470                         mov     word ptr himem_sys_total_free+2,dx
471                 }
472         }
473         else {
474                 __asm {
475                         mov     ah,8
476                         call    [himem_sys_entry]
477
478                         mov     word ptr himem_sys_largest_free,ax
479                         mov     word ptr himem_sys_largest_free+2,0
480
481                         mov     word ptr himem_sys_total_free,dx
482                         mov     word ptr himem_sys_total_free+2,0
483                 }
484         }
485 }
486
487 /* WARNING: do not remove the __cdecl declaration, the hack below relies on it.
488  *          Watcom's native register protocol will copy the long value to a 16-bit
489  *          word on stack and then we won't get the full value. */
490 int __cdecl himem_sys_alloc(unsigned long size/* in KB---not bytes*/) {
491         int handle = -1;
492
493         if (himem_sys_present) {
494                 if (himem_sys_flags & HIMEM_F_4GB) {
495                         __asm {
496                                 mov     ah,0x89
497                                 db      0x66
498                                 mov     dx,word ptr size ; the 0x66 makes it 'mov edx,size'
499                                 call    [himem_sys_entry]
500                                 test    al,1
501                                 jnz     alloc_ok
502                                 xor     dx,dx
503                                 dec     dx
504 alloc_ok:                       mov     handle,dx
505                         }
506                 }
507                 if (handle == -1) {
508                         if (size >= 65535UL) return -1;
509
510                         __asm {
511                                 mov     ah,9
512                                 mov     dx,word ptr size
513                                 call    [himem_sys_entry]
514                                 test    al,1
515                                 jnz     alloc_ok
516                                 xor     dx,dx
517                                 dec     dx
518 alloc_ok:                       mov     handle,dx
519                         }
520                 }
521         }
522
523         return handle;
524 }
525
526 int himem_sys_free(int handle) {
527         int retv = 0;
528
529         if (himem_sys_present) {
530                 __asm {
531                         mov     ah,10
532                         mov     dx,handle
533                         call    [himem_sys_entry]
534                         mov     retv,ax
535                 }
536         }
537
538         return retv;
539 }
540
541 int himem_sys_move(unsigned int dst_handle,uint32_t dst_offset,unsigned int src_handle,uint32_t src_offset,uint32_t length) {
542         unsigned char tmp[16]; /* struct */
543         int retv = 0;
544
545         if (himem_sys_present) {
546                 /* for src or dest references with handle == 0 the HIMEM.SYS driver actually
547                  * takes SEG:OFFSET but we allow the caller to give us a physical memory addr. */
548                 if (src_handle == 0)
549                         src_offset = ((src_offset << 12) & 0xFFFF0000UL) | (src_offset & 0xFUL);
550                 if (dst_handle == 0)
551                         dst_offset = ((dst_offset << 12) & 0xFFFF0000UL) | (dst_offset & 0xFUL);
552
553                 *((uint32_t*)(tmp+0x0)) = length;
554                 *((uint16_t*)(tmp+0x4)) = src_handle;
555                 *((uint32_t*)(tmp+0x6)) = src_offset;
556                 *((uint16_t*)(tmp+0xA)) = dst_handle;
557                 *((uint32_t*)(tmp+0xC)) = dst_offset;
558                 {
559                         const void far *x = (void far*)tmp;
560                         const uint16_t ofsv = FP_OFF(x);
561                         const uint16_t segv = FP_SEG(x);
562                         const uint16_t dsseg = 0;
563                         __asm {
564                                 mov ax,ds
565                                 mov dsseg,ax
566                         }
567                         assert(segv == dsseg);
568                         __asm {
569                                 mov     ah,11
570                                 mov     si,ofsv
571                                 call    [himem_sys_entry]
572                                 mov     retv,ax
573                         }
574                 }
575         }
576
577         return retv;
578 }
579
580 uint32_t himem_sys_lock(unsigned int handle) {
581         uint32_t o = 0UL;
582
583         if (himem_sys_present) {
584                 __asm {
585                         mov     ah,12
586                         mov     dx,handle
587                         call    [himem_sys_entry]
588                         test    al,1
589                         jnz     lockend
590                         xor     bx,bx
591                         mov     dx,bx
592 lockend:                mov     word ptr o,bx
593                         mov     word ptr o+2,dx
594                 }
595         }
596
597         return o;
598 }
599
600 int himem_sys_unlock(unsigned int handle) {
601         int retv = 0;
602
603         if (himem_sys_present) {
604                 __asm {
605                         mov     ah,13
606                         mov     dx,handle
607                         call    [himem_sys_entry]
608                         mov     retv,ax
609                 }
610         }
611
612         return retv;
613 }
614
615 int __cdecl himem_sys_realloc(unsigned int handle,unsigned long size/* in KB---not bytes*/) {
616         int retv = 0;
617
618         if (himem_sys_present) {
619                 if (himem_sys_flags & HIMEM_F_4GB) {
620                         __asm {
621                                 mov     ah,0x8F
622                                 db      0x66
623                                 mov     bx,word ptr size ; the 0x66 makes it 'mov ebx,size'
624                                 mov     dx,handle
625                                 call    [himem_sys_entry]
626                                 mov     retv,ax
627                         }
628                 }
629                 if (retv == 0) {
630                         if (size >= 65535UL) return 0;
631
632                         __asm {
633                                 mov     ah,15
634                                 mov     bx,word ptr size
635                                 mov     dx,handle
636                                 call    [himem_sys_entry]
637                                 mov     retv,ax
638                         }
639                 }
640         }
641
642         return retv;
643 }
644
645 int himem_sys_get_handle_info(unsigned int handle,struct himem_block_info *b) {
646         int retv = 0;
647
648         if (himem_sys_present) {
649                 if (himem_sys_flags & HIMEM_F_4GB) {
650                         __asm {
651                                 mov     ah,0x8E
652                                 mov     dx,handle
653                                 call    [himem_sys_entry]
654                                 mov     si,word ptr b
655                                 db      0x66
656                                 mov     word ptr [si],dx        ; becomes dword ptr [esi]
657                                 mov     byte ptr [si+4],bh      ; lock count
658                                 mov     byte ptr [si+5],bl      ; free handles
659                                 mov     retv,ax
660                         }
661                 }
662                 if (retv == 0) {
663                         __asm {
664                                 mov     ah,14
665                                 mov     dx,handle
666                                 call    [himem_sys_entry]
667                                 mov     si,word ptr b
668                                 mov     word ptr [si],dx
669                                 mov     word ptr [si+2],0
670                                 mov     byte ptr [si+4],bh      ; lock count
671                                 mov     byte ptr [si+5],bl      ; free handles
672                                 mov     retv,ax
673                         }
674                 }
675         }
676
677         return retv;
678 }
679 #endif
680
681 #endif /* !defined(TARGET_WINDOWS) && !defined(TARGET_OS2) */
682