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