xref: /aosp_15_r20/external/pciutils/lib/physmem-djgpp.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker  *      The PCI Library -- Physical memory mapping for DJGPP
3*c2e0c6b5SAndroid Build Coastguard Worker  *
4*c2e0c6b5SAndroid Build Coastguard Worker  *      Copyright (c) 2023 Pali Rohár <[email protected]>
5*c2e0c6b5SAndroid Build Coastguard Worker  *
6*c2e0c6b5SAndroid Build Coastguard Worker  *      Can be freely distributed and used under the terms of the GNU GPL v2+
7*c2e0c6b5SAndroid Build Coastguard Worker  *
8*c2e0c6b5SAndroid Build Coastguard Worker  *      SPDX-License-Identifier: GPL-2.0-or-later
9*c2e0c6b5SAndroid Build Coastguard Worker  */
10*c2e0c6b5SAndroid Build Coastguard Worker 
11*c2e0c6b5SAndroid Build Coastguard Worker #include "internal.h"
12*c2e0c6b5SAndroid Build Coastguard Worker #include "physmem.h"
13*c2e0c6b5SAndroid Build Coastguard Worker 
14*c2e0c6b5SAndroid Build Coastguard Worker #include <errno.h>
15*c2e0c6b5SAndroid Build Coastguard Worker #include <stdlib.h>
16*c2e0c6b5SAndroid Build Coastguard Worker #include <stdio.h> /* for __DJGPP__ and __DJGPP_MINOR__, available since DJGPP v2.02 and defined indirectly via sys/version.h */
17*c2e0c6b5SAndroid Build Coastguard Worker #include <string.h> /* for ffs() */
18*c2e0c6b5SAndroid Build Coastguard Worker #include <malloc.h> /* for memalign() */
19*c2e0c6b5SAndroid Build Coastguard Worker 
20*c2e0c6b5SAndroid Build Coastguard Worker #include <dpmi.h>
21*c2e0c6b5SAndroid Build Coastguard Worker #include <crt0.h> /* for _crt0_startup_flags, __djgpp_memory_handle_list, __djgpp_memory_handle_size and __djgpp_memory_handle() */
22*c2e0c6b5SAndroid Build Coastguard Worker #include <sys/nearptr.h> /* for __djgpp_conventional_base, __djgpp_nearptr_enable() and __djgpp_nearptr_disable() */
23*c2e0c6b5SAndroid Build Coastguard Worker 
24*c2e0c6b5SAndroid Build Coastguard Worker #ifndef EOVERFLOW
25*c2e0c6b5SAndroid Build Coastguard Worker #define EOVERFLOW 40 /* defined since DJGPP v2.04 */
26*c2e0c6b5SAndroid Build Coastguard Worker #endif
27*c2e0c6b5SAndroid Build Coastguard Worker 
28*c2e0c6b5SAndroid Build Coastguard Worker /*
29*c2e0c6b5SAndroid Build Coastguard Worker  * For using __djgpp_conventional_base it is needed to ensure that Unix-like
30*c2e0c6b5SAndroid Build Coastguard Worker  * sbrk algorithm is not active (by setting _CRT0_FLAG_NONMOVE_SBRK startup flag)
31*c2e0c6b5SAndroid Build Coastguard Worker  * and avoiding to call functions like system, spawn*, or exec*.
32*c2e0c6b5SAndroid Build Coastguard Worker  */
33*c2e0c6b5SAndroid Build Coastguard Worker int _crt0_startup_flags = _CRT0_FLAG_NONMOVE_SBRK;
34*c2e0c6b5SAndroid Build Coastguard Worker 
35*c2e0c6b5SAndroid Build Coastguard Worker static void *
aligned_alloc(size_t alignment,size_t size)36*c2e0c6b5SAndroid Build Coastguard Worker aligned_alloc(size_t alignment, size_t size)
37*c2e0c6b5SAndroid Build Coastguard Worker {
38*c2e0c6b5SAndroid Build Coastguard Worker   /*
39*c2e0c6b5SAndroid Build Coastguard Worker    * Unfortunately DJGPP prior to 2.6 has broken memalign() function,
40*c2e0c6b5SAndroid Build Coastguard Worker    * so for older DJGPP versions use malloc() with manual aligning.
41*c2e0c6b5SAndroid Build Coastguard Worker    */
42*c2e0c6b5SAndroid Build Coastguard Worker #if !defined(__DJGPP__) || __DJGPP__ < 2 || (__DJGPP__ == 2 && __DJGPP_MINOR__ < 6)
43*c2e0c6b5SAndroid Build Coastguard Worker   void *ptr_alloc, *ptr_aligned;
44*c2e0c6b5SAndroid Build Coastguard Worker 
45*c2e0c6b5SAndroid Build Coastguard Worker   if (alignment < 8)
46*c2e0c6b5SAndroid Build Coastguard Worker     alignment = 8;
47*c2e0c6b5SAndroid Build Coastguard Worker 
48*c2e0c6b5SAndroid Build Coastguard Worker   ptr_alloc = malloc(size + alignment);
49*c2e0c6b5SAndroid Build Coastguard Worker   if (!ptr_alloc)
50*c2e0c6b5SAndroid Build Coastguard Worker     return NULL;
51*c2e0c6b5SAndroid Build Coastguard Worker 
52*c2e0c6b5SAndroid Build Coastguard Worker   ptr_aligned = (void *)(((unsigned long)ptr_alloc & ~(alignment-1)) + alignment);
53*c2e0c6b5SAndroid Build Coastguard Worker 
54*c2e0c6b5SAndroid Build Coastguard Worker   /*
55*c2e0c6b5SAndroid Build Coastguard Worker    * Store original pointer from malloc() before our aligned pointer.
56*c2e0c6b5SAndroid Build Coastguard Worker    * DJGPP malloc()'ed ptr_alloc is aligned to 8 bytes, our ptr_alloc is
57*c2e0c6b5SAndroid Build Coastguard Worker    * aligned at least to 8 bytes, so we have always 4 bytes of free space
58*c2e0c6b5SAndroid Build Coastguard Worker    * before memory where is pointing ptr_alloc.
59*c2e0c6b5SAndroid Build Coastguard Worker    */
60*c2e0c6b5SAndroid Build Coastguard Worker   *((unsigned long *)ptr_aligned-1) = (unsigned long)ptr_alloc;
61*c2e0c6b5SAndroid Build Coastguard Worker 
62*c2e0c6b5SAndroid Build Coastguard Worker   return ptr_aligned;
63*c2e0c6b5SAndroid Build Coastguard Worker #else
64*c2e0c6b5SAndroid Build Coastguard Worker   return memalign(alignment, size);
65*c2e0c6b5SAndroid Build Coastguard Worker #endif
66*c2e0c6b5SAndroid Build Coastguard Worker }
67*c2e0c6b5SAndroid Build Coastguard Worker 
68*c2e0c6b5SAndroid Build Coastguard Worker static void
aligned_free(void * ptr)69*c2e0c6b5SAndroid Build Coastguard Worker aligned_free(void *ptr)
70*c2e0c6b5SAndroid Build Coastguard Worker {
71*c2e0c6b5SAndroid Build Coastguard Worker #if !defined(__DJGPP__) || __DJGPP__ < 2 || (__DJGPP__ == 2 && __DJGPP_MINOR__ < 6)
72*c2e0c6b5SAndroid Build Coastguard Worker   /* Take original pointer returned by malloc() for releasing memory. */
73*c2e0c6b5SAndroid Build Coastguard Worker   ptr = (void *)*((unsigned long *)ptr-1);
74*c2e0c6b5SAndroid Build Coastguard Worker #endif
75*c2e0c6b5SAndroid Build Coastguard Worker   free(ptr);
76*c2e0c6b5SAndroid Build Coastguard Worker }
77*c2e0c6b5SAndroid Build Coastguard Worker 
78*c2e0c6b5SAndroid Build Coastguard Worker static int
find_sbrk_memory_handle(void * ptr,unsigned long max_length UNUSED,unsigned long pagesize UNUSED,const __djgpp_sbrk_handle ** sh,unsigned long * sh_size)79*c2e0c6b5SAndroid Build Coastguard Worker find_sbrk_memory_handle(void *ptr, unsigned long max_length UNUSED /*pre-v2.04*/, unsigned long pagesize UNUSED /*pre-v2.04*/, const __djgpp_sbrk_handle **sh, unsigned long *sh_size)
80*c2e0c6b5SAndroid Build Coastguard Worker {
81*c2e0c6b5SAndroid Build Coastguard Worker   /*
82*c2e0c6b5SAndroid Build Coastguard Worker    * Find a DJGPP's sbrk memory handle which belongs to the ptr address pointer
83*c2e0c6b5SAndroid Build Coastguard Worker    * and detects size of this memory handle. DJGPP since v2.04 has arrays
84*c2e0c6b5SAndroid Build Coastguard Worker    * __djgpp_memory_handle_list[] and __djgpp_memory_handle_size[] with sbrk
85*c2e0c6b5SAndroid Build Coastguard Worker    * ranges which can be simple traversed. Older DJGPP versions have only
86*c2e0c6b5SAndroid Build Coastguard Worker    * __djgpp_memory_handle() function which returns information to which handle
87*c2e0c6b5SAndroid Build Coastguard Worker    * passed pointer belongs. So finding the size of the memory handle for DJGPP
88*c2e0c6b5SAndroid Build Coastguard Worker    * pre-v2.04 version is slower, its time complexity is O(N^2).
89*c2e0c6b5SAndroid Build Coastguard Worker    */
90*c2e0c6b5SAndroid Build Coastguard Worker #if !defined(__DJGPP__) || __DJGPP__ < 2 || (__DJGPP__ == 2 && __DJGPP_MINOR__ < 4)
91*c2e0c6b5SAndroid Build Coastguard Worker 
92*c2e0c6b5SAndroid Build Coastguard Worker   const __djgpp_sbrk_handle *sh2;
93*c2e0c6b5SAndroid Build Coastguard Worker   unsigned long end_offset;
94*c2e0c6b5SAndroid Build Coastguard Worker 
95*c2e0c6b5SAndroid Build Coastguard Worker   *sh = __djgpp_memory_handle((unsigned long)ptr);
96*c2e0c6b5SAndroid Build Coastguard Worker 
97*c2e0c6b5SAndroid Build Coastguard Worker   for (end_offset = max_length-1; end_offset != 0; end_offset = end_offset > pagesize ? end_offset - pagesize : 0)
98*c2e0c6b5SAndroid Build Coastguard Worker     {
99*c2e0c6b5SAndroid Build Coastguard Worker       sh2 = __djgpp_memory_handle((unsigned long)ptr + end_offset);
100*c2e0c6b5SAndroid Build Coastguard Worker       if (!*sh || !sh2)
101*c2e0c6b5SAndroid Build Coastguard Worker         {
102*c2e0c6b5SAndroid Build Coastguard Worker           /*
103*c2e0c6b5SAndroid Build Coastguard Worker            * If sh or sh2 is NULL then it is probably a memory corruption in
104*c2e0c6b5SAndroid Build Coastguard Worker            * DJGPP's __djgpp_memory_handle_list[] structure.
105*c2e0c6b5SAndroid Build Coastguard Worker            */
106*c2e0c6b5SAndroid Build Coastguard Worker           return 0;
107*c2e0c6b5SAndroid Build Coastguard Worker         }
108*c2e0c6b5SAndroid Build Coastguard Worker       if ((*sh)->handle == sh2->handle)
109*c2e0c6b5SAndroid Build Coastguard Worker         break;
110*c2e0c6b5SAndroid Build Coastguard Worker     }
111*c2e0c6b5SAndroid Build Coastguard Worker 
112*c2e0c6b5SAndroid Build Coastguard Worker   if (end_offset == 0)
113*c2e0c6b5SAndroid Build Coastguard Worker     {
114*c2e0c6b5SAndroid Build Coastguard Worker       /*
115*c2e0c6b5SAndroid Build Coastguard Worker        * If end page of the sh handle was not found then it is probably a memory
116*c2e0c6b5SAndroid Build Coastguard Worker        * corruption in DJGPP's __djgpp_memory_handle_list[] structure.
117*c2e0c6b5SAndroid Build Coastguard Worker        */
118*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
119*c2e0c6b5SAndroid Build Coastguard Worker     }
120*c2e0c6b5SAndroid Build Coastguard Worker 
121*c2e0c6b5SAndroid Build Coastguard Worker   *sh_size = (unsigned long)ptr + end_offset+1 - (*sh)->address;
122*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
123*c2e0c6b5SAndroid Build Coastguard Worker 
124*c2e0c6b5SAndroid Build Coastguard Worker #else
125*c2e0c6b5SAndroid Build Coastguard Worker 
126*c2e0c6b5SAndroid Build Coastguard Worker   size_t i;
127*c2e0c6b5SAndroid Build Coastguard Worker 
128*c2e0c6b5SAndroid Build Coastguard Worker   for (i = 0; i < sizeof(__djgpp_memory_handle_list)/sizeof(__djgpp_memory_handle_list[0]) && (i == 0 || __djgpp_memory_handle_list[i].address != 0); i++)
129*c2e0c6b5SAndroid Build Coastguard Worker     {
130*c2e0c6b5SAndroid Build Coastguard Worker       if ((unsigned long)ptr >= __djgpp_memory_handle_list[i].address &&
131*c2e0c6b5SAndroid Build Coastguard Worker           (unsigned long)ptr < __djgpp_memory_handle_list[i].address + __djgpp_memory_handle_size[i])
132*c2e0c6b5SAndroid Build Coastguard Worker         break;
133*c2e0c6b5SAndroid Build Coastguard Worker     }
134*c2e0c6b5SAndroid Build Coastguard Worker 
135*c2e0c6b5SAndroid Build Coastguard Worker   if ((i != 0 && __djgpp_memory_handle_list[i].address == 0) || __djgpp_memory_handle_size[i] == 0)
136*c2e0c6b5SAndroid Build Coastguard Worker     {
137*c2e0c6b5SAndroid Build Coastguard Worker       /*
138*c2e0c6b5SAndroid Build Coastguard Worker        * If address range was not found in __djgpp_memory_handle_list[]
139*c2e0c6b5SAndroid Build Coastguard Worker        * then it is probably memory corruption in this list.
140*c2e0c6b5SAndroid Build Coastguard Worker        */
141*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
142*c2e0c6b5SAndroid Build Coastguard Worker     }
143*c2e0c6b5SAndroid Build Coastguard Worker 
144*c2e0c6b5SAndroid Build Coastguard Worker   *sh = &__djgpp_memory_handle_list[i];
145*c2e0c6b5SAndroid Build Coastguard Worker   *sh_size = __djgpp_memory_handle_size[i];
146*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
147*c2e0c6b5SAndroid Build Coastguard Worker 
148*c2e0c6b5SAndroid Build Coastguard Worker #endif
149*c2e0c6b5SAndroid Build Coastguard Worker }
150*c2e0c6b5SAndroid Build Coastguard Worker 
151*c2e0c6b5SAndroid Build Coastguard Worker static int
set_and_get_page_attributes(__dpmi_meminfo * mi,short * attributes)152*c2e0c6b5SAndroid Build Coastguard Worker set_and_get_page_attributes(__dpmi_meminfo *mi, short *attributes)
153*c2e0c6b5SAndroid Build Coastguard Worker {
154*c2e0c6b5SAndroid Build Coastguard Worker   unsigned long size;
155*c2e0c6b5SAndroid Build Coastguard Worker   int error;
156*c2e0c6b5SAndroid Build Coastguard Worker   size_t i;
157*c2e0c6b5SAndroid Build Coastguard Worker 
158*c2e0c6b5SAndroid Build Coastguard Worker   /* __dpmi_set_page_attributes modifies mi.size */
159*c2e0c6b5SAndroid Build Coastguard Worker   size = mi->size;
160*c2e0c6b5SAndroid Build Coastguard Worker   if (__dpmi_set_page_attributes(mi, attributes) != 0)
161*c2e0c6b5SAndroid Build Coastguard Worker     {
162*c2e0c6b5SAndroid Build Coastguard Worker       error = __dpmi_error;
163*c2e0c6b5SAndroid Build Coastguard Worker       free(attributes);
164*c2e0c6b5SAndroid Build Coastguard Worker       switch (error)
165*c2e0c6b5SAndroid Build Coastguard Worker         {
166*c2e0c6b5SAndroid Build Coastguard Worker         case 0x0507: /* Unsupported function (returned by DPMI 0.9 host, error number is same as DPMI function number) */
167*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8001: /* Unsupported function (returned by DPMI 1.0 host) */
168*c2e0c6b5SAndroid Build Coastguard Worker           errno = ENOSYS;
169*c2e0c6b5SAndroid Build Coastguard Worker           break;
170*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8010: /* Resource unavailable (DPMI host cannot allocate internal resources to complete an operation) */
171*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8013: /* Physical memory unavailable */
172*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8014: /* Backing store unavailable */
173*c2e0c6b5SAndroid Build Coastguard Worker           errno = ENOMEM;
174*c2e0c6b5SAndroid Build Coastguard Worker           break;
175*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8002: /* Invalid state (page in wrong state for request) */
176*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8021: /* Invalid value (illegal request in bits 0-2 of one or more page attribute words) */
177*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8023: /* Invalid handle (in ESI) */
178*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8025: /* Invalid linear address (specified range is not within specified block) */
179*c2e0c6b5SAndroid Build Coastguard Worker           errno = EINVAL;
180*c2e0c6b5SAndroid Build Coastguard Worker           break;
181*c2e0c6b5SAndroid Build Coastguard Worker         default: /* Other unspecified error */
182*c2e0c6b5SAndroid Build Coastguard Worker           errno = EACCES;
183*c2e0c6b5SAndroid Build Coastguard Worker           break;
184*c2e0c6b5SAndroid Build Coastguard Worker         }
185*c2e0c6b5SAndroid Build Coastguard Worker       return -1;
186*c2e0c6b5SAndroid Build Coastguard Worker     }
187*c2e0c6b5SAndroid Build Coastguard Worker   mi->size = size;
188*c2e0c6b5SAndroid Build Coastguard Worker 
189*c2e0c6b5SAndroid Build Coastguard Worker   /* Cleanup output buffer. */
190*c2e0c6b5SAndroid Build Coastguard Worker   for (i = 0; i < mi->size; i++)
191*c2e0c6b5SAndroid Build Coastguard Worker     attributes[i] = 0;
192*c2e0c6b5SAndroid Build Coastguard Worker 
193*c2e0c6b5SAndroid Build Coastguard Worker   if (__dpmi_get_page_attributes(mi, attributes) != 0)
194*c2e0c6b5SAndroid Build Coastguard Worker     {
195*c2e0c6b5SAndroid Build Coastguard Worker       error = __dpmi_error;
196*c2e0c6b5SAndroid Build Coastguard Worker       free(attributes);
197*c2e0c6b5SAndroid Build Coastguard Worker       switch (error)
198*c2e0c6b5SAndroid Build Coastguard Worker         {
199*c2e0c6b5SAndroid Build Coastguard Worker         case 0x0506: /* Unsupported function (returned by DPMI 0.9 host, error number is same as DPMI function number) */
200*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8001: /* Unsupported function (returned by DPMI 1.0 host) */
201*c2e0c6b5SAndroid Build Coastguard Worker           errno = ENOSYS;
202*c2e0c6b5SAndroid Build Coastguard Worker           break;
203*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8010: /* Resource unavailable (DPMI host cannot allocate internal resources to complete an operation) */
204*c2e0c6b5SAndroid Build Coastguard Worker           errno = ENOMEM;
205*c2e0c6b5SAndroid Build Coastguard Worker           break;
206*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8023: /* Invalid handle (in ESI) */
207*c2e0c6b5SAndroid Build Coastguard Worker         case 0x8025: /* Invalid linear address (specified range is not within specified block) */
208*c2e0c6b5SAndroid Build Coastguard Worker           errno = EINVAL;
209*c2e0c6b5SAndroid Build Coastguard Worker           break;
210*c2e0c6b5SAndroid Build Coastguard Worker         default: /* Other unspecified error */
211*c2e0c6b5SAndroid Build Coastguard Worker           errno = EACCES;
212*c2e0c6b5SAndroid Build Coastguard Worker           break;
213*c2e0c6b5SAndroid Build Coastguard Worker         }
214*c2e0c6b5SAndroid Build Coastguard Worker       return -1;
215*c2e0c6b5SAndroid Build Coastguard Worker     }
216*c2e0c6b5SAndroid Build Coastguard Worker 
217*c2e0c6b5SAndroid Build Coastguard Worker   return 0;
218*c2e0c6b5SAndroid Build Coastguard Worker }
219*c2e0c6b5SAndroid Build Coastguard Worker 
220*c2e0c6b5SAndroid Build Coastguard Worker void
physmem_init_config(struct pci_access * a)221*c2e0c6b5SAndroid Build Coastguard Worker physmem_init_config(struct pci_access *a)
222*c2e0c6b5SAndroid Build Coastguard Worker {
223*c2e0c6b5SAndroid Build Coastguard Worker   pci_define_param(a, "devmem.path", "auto", "DJGPP physical memory access method: auto, devmap, physmap");
224*c2e0c6b5SAndroid Build Coastguard Worker }
225*c2e0c6b5SAndroid Build Coastguard Worker 
226*c2e0c6b5SAndroid Build Coastguard Worker int
physmem_access(struct pci_access * a UNUSED,int w UNUSED)227*c2e0c6b5SAndroid Build Coastguard Worker physmem_access(struct pci_access *a UNUSED, int w UNUSED)
228*c2e0c6b5SAndroid Build Coastguard Worker {
229*c2e0c6b5SAndroid Build Coastguard Worker   return 0;
230*c2e0c6b5SAndroid Build Coastguard Worker }
231*c2e0c6b5SAndroid Build Coastguard Worker 
232*c2e0c6b5SAndroid Build Coastguard Worker #define PHYSMEM_DEVICE_MAPPING ((struct physmem *)1)
233*c2e0c6b5SAndroid Build Coastguard Worker #define PHYSMEM_PHYSADDR_MAPPING ((struct physmem *)2)
234*c2e0c6b5SAndroid Build Coastguard Worker 
235*c2e0c6b5SAndroid Build Coastguard Worker static int fat_ds_count;
236*c2e0c6b5SAndroid Build Coastguard Worker 
237*c2e0c6b5SAndroid Build Coastguard Worker struct physmem *
physmem_open(struct pci_access * a,int w UNUSED)238*c2e0c6b5SAndroid Build Coastguard Worker physmem_open(struct pci_access *a, int w UNUSED)
239*c2e0c6b5SAndroid Build Coastguard Worker {
240*c2e0c6b5SAndroid Build Coastguard Worker   const char *devmem = pci_get_param(a, "devmem.path");
241*c2e0c6b5SAndroid Build Coastguard Worker   __dpmi_version_ret version;
242*c2e0c6b5SAndroid Build Coastguard Worker   char vendor[128];
243*c2e0c6b5SAndroid Build Coastguard Worker   int capabilities;
244*c2e0c6b5SAndroid Build Coastguard Worker   int try_devmap;
245*c2e0c6b5SAndroid Build Coastguard Worker   int try_physmap;
246*c2e0c6b5SAndroid Build Coastguard Worker   int ret;
247*c2e0c6b5SAndroid Build Coastguard Worker 
248*c2e0c6b5SAndroid Build Coastguard Worker   if (strcmp(devmem, "auto") == 0)
249*c2e0c6b5SAndroid Build Coastguard Worker     {
250*c2e0c6b5SAndroid Build Coastguard Worker       try_devmap = 1;
251*c2e0c6b5SAndroid Build Coastguard Worker       try_physmap = 1;
252*c2e0c6b5SAndroid Build Coastguard Worker     }
253*c2e0c6b5SAndroid Build Coastguard Worker   else if (strcmp(devmem, "devmap") == 0)
254*c2e0c6b5SAndroid Build Coastguard Worker     {
255*c2e0c6b5SAndroid Build Coastguard Worker       try_devmap = 1;
256*c2e0c6b5SAndroid Build Coastguard Worker       try_physmap = 0;
257*c2e0c6b5SAndroid Build Coastguard Worker     }
258*c2e0c6b5SAndroid Build Coastguard Worker   else if (strcmp(devmem, "physmap") == 0)
259*c2e0c6b5SAndroid Build Coastguard Worker     {
260*c2e0c6b5SAndroid Build Coastguard Worker       try_devmap = 0;
261*c2e0c6b5SAndroid Build Coastguard Worker       try_physmap = 1;
262*c2e0c6b5SAndroid Build Coastguard Worker     }
263*c2e0c6b5SAndroid Build Coastguard Worker   else
264*c2e0c6b5SAndroid Build Coastguard Worker     {
265*c2e0c6b5SAndroid Build Coastguard Worker       try_devmap = 0;
266*c2e0c6b5SAndroid Build Coastguard Worker       try_physmap = 0;
267*c2e0c6b5SAndroid Build Coastguard Worker     }
268*c2e0c6b5SAndroid Build Coastguard Worker 
269*c2e0c6b5SAndroid Build Coastguard Worker   ret = __dpmi_get_version(&version);
270*c2e0c6b5SAndroid Build Coastguard Worker   if (ret != 0)
271*c2e0c6b5SAndroid Build Coastguard Worker     a->debug("detected unknown DPMI host...");
272*c2e0c6b5SAndroid Build Coastguard Worker   else
273*c2e0c6b5SAndroid Build Coastguard Worker     {
274*c2e0c6b5SAndroid Build Coastguard Worker       /*
275*c2e0c6b5SAndroid Build Coastguard Worker        * Call DPMI 1.0 function __dpmi_get_capabilities() for detecting if DPMI
276*c2e0c6b5SAndroid Build Coastguard Worker        * host supports Device mapping. Some DPMI 0.9 hosts like Windows's NTVDM
277*c2e0c6b5SAndroid Build Coastguard Worker        * do not support this function, so does not fill capabilities and vendor
278*c2e0c6b5SAndroid Build Coastguard Worker        * buffer, but returns success. Detect this kind of failure by checking
279*c2e0c6b5SAndroid Build Coastguard Worker        * if AX register (low 16-bits of capabilities variable) was not modified
280*c2e0c6b5SAndroid Build Coastguard Worker        * and contains the number of called DPMI function (0x0401).
281*c2e0c6b5SAndroid Build Coastguard Worker        */
282*c2e0c6b5SAndroid Build Coastguard Worker       vendor[0] = vendor[1] = vendor[2] = 0;
283*c2e0c6b5SAndroid Build Coastguard Worker       ret = __dpmi_get_capabilities(&capabilities, vendor);
284*c2e0c6b5SAndroid Build Coastguard Worker       if (ret == 0 && (capabilities & 0xffff) == 0x0401)
285*c2e0c6b5SAndroid Build Coastguard Worker         ret = -1;
286*c2e0c6b5SAndroid Build Coastguard Worker 
287*c2e0c6b5SAndroid Build Coastguard Worker       if (ret == 0)
288*c2e0c6b5SAndroid Build Coastguard Worker         a->debug("detected DPMI %u.%02u host %.126s %u.%u with flags 0x%x and capabilities 0x%x...",
289*c2e0c6b5SAndroid Build Coastguard Worker                   (unsigned)version.major, (unsigned)version.minor, vendor+2,
290*c2e0c6b5SAndroid Build Coastguard Worker                   (unsigned)(unsigned char)vendor[0], (unsigned)(unsigned char)vendor[1],
291*c2e0c6b5SAndroid Build Coastguard Worker                   (unsigned)version.flags, capabilities);
292*c2e0c6b5SAndroid Build Coastguard Worker       else
293*c2e0c6b5SAndroid Build Coastguard Worker         a->debug("detected DPMI %u.%02u host with flags 0x%x...",
294*c2e0c6b5SAndroid Build Coastguard Worker                   (unsigned)version.major, (unsigned)version.minor, (unsigned)version.flags);
295*c2e0c6b5SAndroid Build Coastguard Worker     }
296*c2e0c6b5SAndroid Build Coastguard Worker 
297*c2e0c6b5SAndroid Build Coastguard Worker   /*
298*c2e0c6b5SAndroid Build Coastguard Worker    * If device mapping was selected then use __dpmi_map_device_in_memory_block()
299*c2e0c6b5SAndroid Build Coastguard Worker    * for physical memory mapping. Does not have to be supported by DPMI 0.9 host.
300*c2e0c6b5SAndroid Build Coastguard Worker    * Device mapping is supported when capability bit 2 is set.
301*c2e0c6b5SAndroid Build Coastguard Worker    */
302*c2e0c6b5SAndroid Build Coastguard Worker   if (try_devmap)
303*c2e0c6b5SAndroid Build Coastguard Worker     {
304*c2e0c6b5SAndroid Build Coastguard Worker       if (ret == 0 && (capabilities & (1<<2)))
305*c2e0c6b5SAndroid Build Coastguard Worker         {
306*c2e0c6b5SAndroid Build Coastguard Worker           a->debug("using physical memory access via Device Mapping...");
307*c2e0c6b5SAndroid Build Coastguard Worker           return PHYSMEM_DEVICE_MAPPING;
308*c2e0c6b5SAndroid Build Coastguard Worker         }
309*c2e0c6b5SAndroid Build Coastguard Worker       a->debug("DPMI Device Mapping not supported...");
310*c2e0c6b5SAndroid Build Coastguard Worker     }
311*c2e0c6b5SAndroid Build Coastguard Worker 
312*c2e0c6b5SAndroid Build Coastguard Worker   /*
313*c2e0c6b5SAndroid Build Coastguard Worker    * If device mapping was not tried or not supported by DPMI host then fallback
314*c2e0c6b5SAndroid Build Coastguard Worker    * to __dpmi_physical_address_mapping(). But this requires Fat DS descriptor,
315*c2e0c6b5SAndroid Build Coastguard Worker    * meaning to increase DS descriptor limit to 4 GB, which does not have to be
316*c2e0c6b5SAndroid Build Coastguard Worker    * supported by some DPMI hosts.
317*c2e0c6b5SAndroid Build Coastguard Worker    */
318*c2e0c6b5SAndroid Build Coastguard Worker   if (try_physmap)
319*c2e0c6b5SAndroid Build Coastguard Worker     {
320*c2e0c6b5SAndroid Build Coastguard Worker       if (fat_ds_count != 0 || __djgpp_nearptr_enable())
321*c2e0c6b5SAndroid Build Coastguard Worker         {
322*c2e0c6b5SAndroid Build Coastguard Worker           fat_ds_count++;
323*c2e0c6b5SAndroid Build Coastguard Worker           a->debug("using physical memory access via Physical Address Mapping...");
324*c2e0c6b5SAndroid Build Coastguard Worker           return PHYSMEM_PHYSADDR_MAPPING;
325*c2e0c6b5SAndroid Build Coastguard Worker         }
326*c2e0c6b5SAndroid Build Coastguard Worker 
327*c2e0c6b5SAndroid Build Coastguard Worker       /*
328*c2e0c6b5SAndroid Build Coastguard Worker        * DJGPP prior to 2.6 has semi-broken __djgpp_nearptr_enable() function.
329*c2e0c6b5SAndroid Build Coastguard Worker        * On failure it may let DS descriptor limit in semi-broken state. So for
330*c2e0c6b5SAndroid Build Coastguard Worker        * older DJGPP versions call __djgpp_nearptr_disable() which fixes it.
331*c2e0c6b5SAndroid Build Coastguard Worker        */
332*c2e0c6b5SAndroid Build Coastguard Worker #if !defined(__DJGPP__) || __DJGPP__ < 2 || (__DJGPP__ == 2 && __DJGPP_MINOR__ < 6)
333*c2e0c6b5SAndroid Build Coastguard Worker       __djgpp_nearptr_disable();
334*c2e0c6b5SAndroid Build Coastguard Worker #endif
335*c2e0c6b5SAndroid Build Coastguard Worker       a->debug("DPMI Physical Address Mapping not usable because Fat DS descriptor not supported...");
336*c2e0c6b5SAndroid Build Coastguard Worker     }
337*c2e0c6b5SAndroid Build Coastguard Worker 
338*c2e0c6b5SAndroid Build Coastguard Worker   /*
339*c2e0c6b5SAndroid Build Coastguard Worker    * Otherwise we do not have access to physical memory mapping. Theoretically
340*c2e0c6b5SAndroid Build Coastguard Worker    * it could be possible to use __dpmi_physical_address_mapping() and then
341*c2e0c6b5SAndroid Build Coastguard Worker    * create new segment where mapped linear address would be available, but this
342*c2e0c6b5SAndroid Build Coastguard Worker    * would require to access memory in newly created segment via far pointers,
343*c2e0c6b5SAndroid Build Coastguard Worker    * which is not only mess in the native 32-bit application but also these far
344*c2e0c6b5SAndroid Build Coastguard Worker    * pointers are not supported by gcc. If DPMI host does not allow us to change
345*c2e0c6b5SAndroid Build Coastguard Worker    * DS descriptor limit to 4 GB then it is mostly due to security reasons and
346*c2e0c6b5SAndroid Build Coastguard Worker    * probably does not allow access to physical memory mapping. This applies
347*c2e0c6b5SAndroid Build Coastguard Worker    * for non-DOS OS systems with integrated DPMI hosts like in Windows NT NTVDM
348*c2e0c6b5SAndroid Build Coastguard Worker    * or older version of Linux dosemu.
349*c2e0c6b5SAndroid Build Coastguard Worker    */
350*c2e0c6b5SAndroid Build Coastguard Worker   a->debug("physical memory access not allowed...");
351*c2e0c6b5SAndroid Build Coastguard Worker   errno = EACCES;
352*c2e0c6b5SAndroid Build Coastguard Worker   return NULL;
353*c2e0c6b5SAndroid Build Coastguard Worker }
354*c2e0c6b5SAndroid Build Coastguard Worker 
355*c2e0c6b5SAndroid Build Coastguard Worker void
physmem_close(struct physmem * physmem)356*c2e0c6b5SAndroid Build Coastguard Worker physmem_close(struct physmem *physmem)
357*c2e0c6b5SAndroid Build Coastguard Worker {
358*c2e0c6b5SAndroid Build Coastguard Worker   /* Disable 4 GB limit on DS descriptor if it was the last user. */
359*c2e0c6b5SAndroid Build Coastguard Worker   if (physmem == PHYSMEM_PHYSADDR_MAPPING)
360*c2e0c6b5SAndroid Build Coastguard Worker     {
361*c2e0c6b5SAndroid Build Coastguard Worker       fat_ds_count--;
362*c2e0c6b5SAndroid Build Coastguard Worker       if (fat_ds_count == 0)
363*c2e0c6b5SAndroid Build Coastguard Worker         __djgpp_nearptr_disable();
364*c2e0c6b5SAndroid Build Coastguard Worker     }
365*c2e0c6b5SAndroid Build Coastguard Worker }
366*c2e0c6b5SAndroid Build Coastguard Worker 
367*c2e0c6b5SAndroid Build Coastguard Worker long
physmem_get_pagesize(struct physmem * physmem UNUSED)368*c2e0c6b5SAndroid Build Coastguard Worker physmem_get_pagesize(struct physmem *physmem UNUSED)
369*c2e0c6b5SAndroid Build Coastguard Worker {
370*c2e0c6b5SAndroid Build Coastguard Worker   static unsigned long pagesize;
371*c2e0c6b5SAndroid Build Coastguard Worker   if (!pagesize)
372*c2e0c6b5SAndroid Build Coastguard Worker     {
373*c2e0c6b5SAndroid Build Coastguard Worker       if (__dpmi_get_page_size(&pagesize) != 0)
374*c2e0c6b5SAndroid Build Coastguard Worker         pagesize = 0;
375*c2e0c6b5SAndroid Build Coastguard Worker       if (pagesize & (pagesize-1))
376*c2e0c6b5SAndroid Build Coastguard Worker         pagesize = 0;
377*c2e0c6b5SAndroid Build Coastguard Worker       if (!pagesize)
378*c2e0c6b5SAndroid Build Coastguard Worker         pagesize = 4096; /* Fallback value, the most commonly used on x86. */
379*c2e0c6b5SAndroid Build Coastguard Worker     }
380*c2e0c6b5SAndroid Build Coastguard Worker   return pagesize;
381*c2e0c6b5SAndroid Build Coastguard Worker }
382*c2e0c6b5SAndroid Build Coastguard Worker 
383*c2e0c6b5SAndroid Build Coastguard Worker void *
physmem_map(struct physmem * physmem,u64 addr,size_t length,int w)384*c2e0c6b5SAndroid Build Coastguard Worker physmem_map(struct physmem *physmem, u64 addr, size_t length, int w)
385*c2e0c6b5SAndroid Build Coastguard Worker {
386*c2e0c6b5SAndroid Build Coastguard Worker   long pagesize = physmem_get_pagesize(physmem);
387*c2e0c6b5SAndroid Build Coastguard Worker   unsigned pagesize_shift = ffs(pagesize)-1;
388*c2e0c6b5SAndroid Build Coastguard Worker   const __djgpp_sbrk_handle *sh;
389*c2e0c6b5SAndroid Build Coastguard Worker   unsigned long sh_size;
390*c2e0c6b5SAndroid Build Coastguard Worker   unsigned long size;
391*c2e0c6b5SAndroid Build Coastguard Worker   __dpmi_meminfo mi;
392*c2e0c6b5SAndroid Build Coastguard Worker   short *attributes;
393*c2e0c6b5SAndroid Build Coastguard Worker   short one_pg_attr;
394*c2e0c6b5SAndroid Build Coastguard Worker   size_t offset;
395*c2e0c6b5SAndroid Build Coastguard Worker   int error;
396*c2e0c6b5SAndroid Build Coastguard Worker   void *ptr;
397*c2e0c6b5SAndroid Build Coastguard Worker   size_t i;
398*c2e0c6b5SAndroid Build Coastguard Worker 
399*c2e0c6b5SAndroid Build Coastguard Worker   /* Align length to page size. */
400*c2e0c6b5SAndroid Build Coastguard Worker   if (length & (pagesize-1))
401*c2e0c6b5SAndroid Build Coastguard Worker     length = (length & ~(pagesize-1)) + pagesize;
402*c2e0c6b5SAndroid Build Coastguard Worker 
403*c2e0c6b5SAndroid Build Coastguard Worker   /* Mapping of physical memory above 4 GB is not possible. */
404*c2e0c6b5SAndroid Build Coastguard Worker   if (addr >= 0xffffffffUL || addr + length > 0xffffffffUL)
405*c2e0c6b5SAndroid Build Coastguard Worker     {
406*c2e0c6b5SAndroid Build Coastguard Worker       errno = EOVERFLOW;
407*c2e0c6b5SAndroid Build Coastguard Worker       return (void *)-1;
408*c2e0c6b5SAndroid Build Coastguard Worker     }
409*c2e0c6b5SAndroid Build Coastguard Worker 
410*c2e0c6b5SAndroid Build Coastguard Worker   if (physmem == PHYSMEM_DEVICE_MAPPING)
411*c2e0c6b5SAndroid Build Coastguard Worker     {
412*c2e0c6b5SAndroid Build Coastguard Worker       /*
413*c2e0c6b5SAndroid Build Coastguard Worker        * __dpmi_map_device_in_memory_block() maps physical memory to any
414*c2e0c6b5SAndroid Build Coastguard Worker        * page-aligned linear address for which we have DPMI memory handle. But
415*c2e0c6b5SAndroid Build Coastguard Worker        * DPMI host does not have to support mapping of memory below 1 MB which
416*c2e0c6b5SAndroid Build Coastguard Worker        * lies in RAM, and is not device memory.
417*c2e0c6b5SAndroid Build Coastguard Worker        *
418*c2e0c6b5SAndroid Build Coastguard Worker        * __djgpp_map_physical_memory() function is DJGPP wrapper around
419*c2e0c6b5SAndroid Build Coastguard Worker        * __dpmi_map_device_in_memory_block() which properly handles memory
420*c2e0c6b5SAndroid Build Coastguard Worker        * range that span multiple DPMI memory handles. It is common that
421*c2e0c6b5SAndroid Build Coastguard Worker        * DJGPP sbrk() or malloc() allocator returns continuous memory range
422*c2e0c6b5SAndroid Build Coastguard Worker        * which is backed by two or more DPMI memory handles which represents
423*c2e0c6b5SAndroid Build Coastguard Worker        * consecutive memory ranges without any gap.
424*c2e0c6b5SAndroid Build Coastguard Worker        *
425*c2e0c6b5SAndroid Build Coastguard Worker        * __dpmi_map_conventional_memory_in_memory_block() aliases memory range
426*c2e0c6b5SAndroid Build Coastguard Worker        * specified by page-aligned linear address to another page-aligned linear
427*c2e0c6b5SAndroid Build Coastguard Worker        * address. This can be used for mapping memory below 1 MB which lies in
428*c2e0c6b5SAndroid Build Coastguard Worker        * RAM and for which cannot be used __dpmi_map_device_in_memory_block().
429*c2e0c6b5SAndroid Build Coastguard Worker        * This function calls takes (virtual) linear address as opposite of the
430*c2e0c6b5SAndroid Build Coastguard Worker        * __dpmi_map_device_in_memory_block() which takes physical address.
431*c2e0c6b5SAndroid Build Coastguard Worker        *
432*c2e0c6b5SAndroid Build Coastguard Worker        * Unfortunately __djgpp_map_physical_memory() internally calls only
433*c2e0c6b5SAndroid Build Coastguard Worker        * __djgpp_map_physical_memory() function and does not return information
434*c2e0c6b5SAndroid Build Coastguard Worker        * for which memory range the call failed. So it cannot be used for
435*c2e0c6b5SAndroid Build Coastguard Worker        * generic memory mapping requests.
436*c2e0c6b5SAndroid Build Coastguard Worker        *
437*c2e0c6b5SAndroid Build Coastguard Worker        * Also it does not return usefull errno. And even in the latest released
438*c2e0c6b5SAndroid Build Coastguard Worker        * DJGPP version v2.5 this function has suboptimal implementation. Its
439*c2e0c6b5SAndroid Build Coastguard Worker        * time complexity is O(N^2) (where N is number of pages).
440*c2e0c6b5SAndroid Build Coastguard Worker        *
441*c2e0c6b5SAndroid Build Coastguard Worker        * So do not use __djgpp_map_physical_memory() function and instead write
442*c2e0c6b5SAndroid Build Coastguard Worker        * own logic handling virtual memory ranges which spans multiple DPMI
443*c2e0c6b5SAndroid Build Coastguard Worker        * memory handles and manually calls __dpmi_map_device_in_memory_block()
444*c2e0c6b5SAndroid Build Coastguard Worker        * or __dpmi_map_conventional_memory_in_memory_block() per every handle.
445*c2e0c6b5SAndroid Build Coastguard Worker        *
446*c2e0c6b5SAndroid Build Coastguard Worker        * We can easily access only linear addresses in our DS segment which
447*c2e0c6b5SAndroid Build Coastguard Worker        * is managed by DJGPP sbrk allocator. So allocate page-aligned range
448*c2e0c6b5SAndroid Build Coastguard Worker        * by aligned_alloc() (our wrapper around malloc()/memalign()) and then
449*c2e0c6b5SAndroid Build Coastguard Worker        * for every subrange which is backed by different DPMI memory handle
450*c2e0c6b5SAndroid Build Coastguard Worker        * call appropriate mapping function which correctly calculated offset
451*c2e0c6b5SAndroid Build Coastguard Worker        * and length to have continuous representation of physical memory range.
452*c2e0c6b5SAndroid Build Coastguard Worker        *
453*c2e0c6b5SAndroid Build Coastguard Worker        * This approach has disadvantage that for each mapping it is required
454*c2e0c6b5SAndroid Build Coastguard Worker        * to reserve and allocate committed memory in RAM with the size of the
455*c2e0c6b5SAndroid Build Coastguard Worker        * mapping itself. This has negative impact for mappings of large sizes.
456*c2e0c6b5SAndroid Build Coastguard Worker        * Unfortunately this is the only way because DJGPP sbrk allocator does
457*c2e0c6b5SAndroid Build Coastguard Worker        * not have any (public) function for directly allocating uncommitted
458*c2e0c6b5SAndroid Build Coastguard Worker        * memory which is not backed by the RAM. Even if DJGPP sbrk code is
459*c2e0c6b5SAndroid Build Coastguard Worker        * extended for this functionality, the corresponding DPMI function
460*c2e0c6b5SAndroid Build Coastguard Worker        * __dpmi_allocate_linear_memory() is DPMI 1.0 function and not widely
461*c2e0c6b5SAndroid Build Coastguard Worker        * supported by DPMI hosts, even the default DJGPP's CWSDPMI does not
462*c2e0c6b5SAndroid Build Coastguard Worker        * support it.
463*c2e0c6b5SAndroid Build Coastguard Worker        */
464*c2e0c6b5SAndroid Build Coastguard Worker 
465*c2e0c6b5SAndroid Build Coastguard Worker       ptr = aligned_alloc(pagesize, length);
466*c2e0c6b5SAndroid Build Coastguard Worker       if (!ptr)
467*c2e0c6b5SAndroid Build Coastguard Worker         {
468*c2e0c6b5SAndroid Build Coastguard Worker           errno = ENOMEM;
469*c2e0c6b5SAndroid Build Coastguard Worker           return (void *)-1;
470*c2e0c6b5SAndroid Build Coastguard Worker         }
471*c2e0c6b5SAndroid Build Coastguard Worker 
472*c2e0c6b5SAndroid Build Coastguard Worker       for (offset = 0; offset < length; offset += (mi.size << pagesize_shift))
473*c2e0c6b5SAndroid Build Coastguard Worker         {
474*c2e0c6b5SAndroid Build Coastguard Worker           /*
475*c2e0c6b5SAndroid Build Coastguard Worker            * Find a memory handle with its size which belongs to the pointer
476*c2e0c6b5SAndroid Build Coastguard Worker            * address ptr+offset. Base address and size of the memory handle
477*c2e0c6b5SAndroid Build Coastguard Worker            * must be page aligned for memory mapping support.
478*c2e0c6b5SAndroid Build Coastguard Worker            */
479*c2e0c6b5SAndroid Build Coastguard Worker           if (!find_sbrk_memory_handle(ptr + offset, length - offset, pagesize, &sh, &sh_size) ||
480*c2e0c6b5SAndroid Build Coastguard Worker               (sh->address & (pagesize-1)) || (sh_size & (pagesize-1)))
481*c2e0c6b5SAndroid Build Coastguard Worker             {
482*c2e0c6b5SAndroid Build Coastguard Worker               /*
483*c2e0c6b5SAndroid Build Coastguard Worker                * Failure detected. If we have some partial mapping, try to undo
484*c2e0c6b5SAndroid Build Coastguard Worker                * it via physmem_unmap() which also release ptr. If we do not
485*c2e0c6b5SAndroid Build Coastguard Worker                * have partial mapping, just release ptr.
486*c2e0c6b5SAndroid Build Coastguard Worker                */
487*c2e0c6b5SAndroid Build Coastguard Worker               if (offset != 0)
488*c2e0c6b5SAndroid Build Coastguard Worker                 physmem_unmap(physmem, ptr, offset);
489*c2e0c6b5SAndroid Build Coastguard Worker               else
490*c2e0c6b5SAndroid Build Coastguard Worker                 aligned_free(ptr);
491*c2e0c6b5SAndroid Build Coastguard Worker               errno = EINVAL;
492*c2e0c6b5SAndroid Build Coastguard Worker               return (void *)-1;
493*c2e0c6b5SAndroid Build Coastguard Worker             }
494*c2e0c6b5SAndroid Build Coastguard Worker 
495*c2e0c6b5SAndroid Build Coastguard Worker           mi.handle = sh->handle;
496*c2e0c6b5SAndroid Build Coastguard Worker           mi.address = (unsigned long)ptr + offset - sh->address;
497*c2e0c6b5SAndroid Build Coastguard Worker           mi.size = (length - offset) >> pagesize_shift;
498*c2e0c6b5SAndroid Build Coastguard Worker           if (mi.size > ((sh_size - mi.address) >> pagesize_shift))
499*c2e0c6b5SAndroid Build Coastguard Worker             mi.size = (sh_size - mi.address) >> pagesize_shift;
500*c2e0c6b5SAndroid Build Coastguard Worker           if (__dpmi_map_device_in_memory_block(&mi, addr + offset) != 0)
501*c2e0c6b5SAndroid Build Coastguard Worker             {
502*c2e0c6b5SAndroid Build Coastguard Worker               /*
503*c2e0c6b5SAndroid Build Coastguard Worker                * __dpmi_map_device_in_memory_block() may fail for memory range
504*c2e0c6b5SAndroid Build Coastguard Worker                * which belongs to non-device memory below 1 MB. DPMI host in
505*c2e0c6b5SAndroid Build Coastguard Worker                * this case returns DPMI error code 0x8003 (System integrity -
506*c2e0c6b5SAndroid Build Coastguard Worker                * invalid device address). For example this is behavior of DPMI
507*c2e0c6b5SAndroid Build Coastguard Worker                * host HX HDPMI32, which strictly differs between non-device and
508*c2e0c6b5SAndroid Build Coastguard Worker                * device memory. If the physical memory range belongs to the
509*c2e0c6b5SAndroid Build Coastguard Worker                * non-device conventional memory and DPMI host uses 1:1 mappings
510*c2e0c6b5SAndroid Build Coastguard Worker                * for memory below 1 MB then we can try to alias range of linear
511*c2e0c6b5SAndroid Build Coastguard Worker                * address below 1 MB to DJGPP's accessible linear address range.
512*c2e0c6b5SAndroid Build Coastguard Worker                * For this aliasing of linear (not the physical) memory address
513*c2e0c6b5SAndroid Build Coastguard Worker                * ranges below 1 MB boundary is there an additional DPMI 1.0
514*c2e0c6b5SAndroid Build Coastguard Worker                * function __dpmi_map_conventional_memory_in_memory_block().
515*c2e0c6b5SAndroid Build Coastguard Worker                * But DPMI host does not have to support it. HDPMI32 supports it.
516*c2e0c6b5SAndroid Build Coastguard Worker                * If the memory range crosses 1 MB boundary then call it only for
517*c2e0c6b5SAndroid Build Coastguard Worker                * the subrange of memory which below 1 MB boundary and let the
518*c2e0c6b5SAndroid Build Coastguard Worker                * remaining subrange for the next iteration of the outer loop.
519*c2e0c6b5SAndroid Build Coastguard Worker                * Because the remaining memory range is above 1 MB limit, only
520*c2e0c6b5SAndroid Build Coastguard Worker                * the __dpmi_map_device_in_memory_block() would be used. This
521*c2e0c6b5SAndroid Build Coastguard Worker                * approach makes continues linear range of the mapped memory.
522*c2e0c6b5SAndroid Build Coastguard Worker                */
523*c2e0c6b5SAndroid Build Coastguard Worker               if (__dpmi_error == 0x8003 && addr + offset < 1*1024*1024UL)
524*c2e0c6b5SAndroid Build Coastguard Worker                 {
525*c2e0c6b5SAndroid Build Coastguard Worker                   /* reuse mi */
526*c2e0c6b5SAndroid Build Coastguard Worker                   if (addr + offset + (mi.size << pagesize_shift) > 1*1024*1024UL)
527*c2e0c6b5SAndroid Build Coastguard Worker                     mi.size = (1*1024*1024UL - addr - offset) >> pagesize_shift;
528*c2e0c6b5SAndroid Build Coastguard Worker                   if (__dpmi_map_conventional_memory_in_memory_block(&mi, addr + offset) != 0)
529*c2e0c6b5SAndroid Build Coastguard Worker                     {
530*c2e0c6b5SAndroid Build Coastguard Worker                       /*
531*c2e0c6b5SAndroid Build Coastguard Worker                        * Save __dpmi_error because any DJGPP function may change
532*c2e0c6b5SAndroid Build Coastguard Worker                        * it. If we have some partial mapping, try to undo it via
533*c2e0c6b5SAndroid Build Coastguard Worker                        * physmem_unmap() which also release ptr. If we do not
534*c2e0c6b5SAndroid Build Coastguard Worker                        * have partial mapping, just release ptr.
535*c2e0c6b5SAndroid Build Coastguard Worker                        */
536*c2e0c6b5SAndroid Build Coastguard Worker                       error = __dpmi_error;
537*c2e0c6b5SAndroid Build Coastguard Worker                       if (offset != 0)
538*c2e0c6b5SAndroid Build Coastguard Worker                         physmem_unmap(physmem, ptr, offset);
539*c2e0c6b5SAndroid Build Coastguard Worker                       else
540*c2e0c6b5SAndroid Build Coastguard Worker                         aligned_free(ptr);
541*c2e0c6b5SAndroid Build Coastguard Worker                       switch (error)
542*c2e0c6b5SAndroid Build Coastguard Worker                         {
543*c2e0c6b5SAndroid Build Coastguard Worker                         case 0x0509: /* Unsupported function (returned by DPMI 0.9 host, error number is same as DPMI function number) */
544*c2e0c6b5SAndroid Build Coastguard Worker                         case 0x8001: /* Unsupported function (returned by DPMI 1.0 host) */
545*c2e0c6b5SAndroid Build Coastguard Worker                           /*
546*c2e0c6b5SAndroid Build Coastguard Worker                            * Conventional Memory Mapping is not supported.
547*c2e0c6b5SAndroid Build Coastguard Worker                            * Device Mapping is supported, but DPMI host rejected
548*c2e0c6b5SAndroid Build Coastguard Worker                            * Device Mapping request. So reports same errno value
549*c2e0c6b5SAndroid Build Coastguard Worker                            * as from the failed Device Mapping switch case,
550*c2e0c6b5SAndroid Build Coastguard Worker                            * which is ENXIO (because __dpmi_error == 0x8003).
551*c2e0c6b5SAndroid Build Coastguard Worker                            */
552*c2e0c6b5SAndroid Build Coastguard Worker                           errno = ENXIO;
553*c2e0c6b5SAndroid Build Coastguard Worker                           break;
554*c2e0c6b5SAndroid Build Coastguard Worker                         case 0x8003: /* System integrity (invalid conventional memory address) */
555*c2e0c6b5SAndroid Build Coastguard Worker                           errno = ENXIO;
556*c2e0c6b5SAndroid Build Coastguard Worker                           break;
557*c2e0c6b5SAndroid Build Coastguard Worker                         case 0x8010: /* Resource unavailable (DPMI host cannot allocate internal resources to complete an operation) */
558*c2e0c6b5SAndroid Build Coastguard Worker                           errno = ENOMEM;
559*c2e0c6b5SAndroid Build Coastguard Worker                           break;
560*c2e0c6b5SAndroid Build Coastguard Worker                         case 0x8023: /* Invalid handle (in ESI) */
561*c2e0c6b5SAndroid Build Coastguard Worker                         case 0x8025: /* Invalid linear address (specified range is not within specified block, or EBX/EDX is not page aligned) */
562*c2e0c6b5SAndroid Build Coastguard Worker                           errno = EINVAL;
563*c2e0c6b5SAndroid Build Coastguard Worker                           break;
564*c2e0c6b5SAndroid Build Coastguard Worker                         default: /* Other unspecified error */
565*c2e0c6b5SAndroid Build Coastguard Worker                           errno = EACCES;
566*c2e0c6b5SAndroid Build Coastguard Worker                           break;
567*c2e0c6b5SAndroid Build Coastguard Worker                         }
568*c2e0c6b5SAndroid Build Coastguard Worker                       return (void *)-1;
569*c2e0c6b5SAndroid Build Coastguard Worker                     }
570*c2e0c6b5SAndroid Build Coastguard Worker                 }
571*c2e0c6b5SAndroid Build Coastguard Worker               else
572*c2e0c6b5SAndroid Build Coastguard Worker                 {
573*c2e0c6b5SAndroid Build Coastguard Worker                   /*
574*c2e0c6b5SAndroid Build Coastguard Worker                    * Save __dpmi_error because any DJGPP function may change
575*c2e0c6b5SAndroid Build Coastguard Worker                    * it. If we have some partial mapping, try to undo it via
576*c2e0c6b5SAndroid Build Coastguard Worker                    * physmem_unmap() which also release ptr. If we do not
577*c2e0c6b5SAndroid Build Coastguard Worker                    * have partial mapping, just release ptr.
578*c2e0c6b5SAndroid Build Coastguard Worker                    */
579*c2e0c6b5SAndroid Build Coastguard Worker                   error = __dpmi_error;
580*c2e0c6b5SAndroid Build Coastguard Worker                   if (offset != 0)
581*c2e0c6b5SAndroid Build Coastguard Worker                     physmem_unmap(physmem, ptr, offset);
582*c2e0c6b5SAndroid Build Coastguard Worker                   else
583*c2e0c6b5SAndroid Build Coastguard Worker                     aligned_free(ptr);
584*c2e0c6b5SAndroid Build Coastguard Worker                   switch (error)
585*c2e0c6b5SAndroid Build Coastguard Worker                     {
586*c2e0c6b5SAndroid Build Coastguard Worker                     case 0x0508: /* Unsupported function (returned by DPMI 0.9 host, error number is same as DPMI function number) */
587*c2e0c6b5SAndroid Build Coastguard Worker                     case 0x8001: /* Unsupported function (returned by DPMI 1.0 host) */
588*c2e0c6b5SAndroid Build Coastguard Worker                       errno = ENOSYS;
589*c2e0c6b5SAndroid Build Coastguard Worker                       break;
590*c2e0c6b5SAndroid Build Coastguard Worker                     case 0x8003: /* System integrity (invalid device address) */
591*c2e0c6b5SAndroid Build Coastguard Worker                       errno = ENXIO;
592*c2e0c6b5SAndroid Build Coastguard Worker                       break;
593*c2e0c6b5SAndroid Build Coastguard Worker                     case 0x8010: /* Resource unavailable (DPMI host cannot allocate internal resources to complete an operation) */
594*c2e0c6b5SAndroid Build Coastguard Worker                       errno = ENOMEM;
595*c2e0c6b5SAndroid Build Coastguard Worker                       break;
596*c2e0c6b5SAndroid Build Coastguard Worker                     case 0x8023: /* Invalid handle (in ESI) */
597*c2e0c6b5SAndroid Build Coastguard Worker                     case 0x8025: /* Invalid linear address (specified range is not within specified block or EBX/EDX is not page-aligned) */
598*c2e0c6b5SAndroid Build Coastguard Worker                       errno = EINVAL;
599*c2e0c6b5SAndroid Build Coastguard Worker                       break;
600*c2e0c6b5SAndroid Build Coastguard Worker                     default: /* Other unspecified error */
601*c2e0c6b5SAndroid Build Coastguard Worker                       errno = EACCES;
602*c2e0c6b5SAndroid Build Coastguard Worker                       break;
603*c2e0c6b5SAndroid Build Coastguard Worker                     }
604*c2e0c6b5SAndroid Build Coastguard Worker                   return (void *)-1;
605*c2e0c6b5SAndroid Build Coastguard Worker                 }
606*c2e0c6b5SAndroid Build Coastguard Worker             }
607*c2e0c6b5SAndroid Build Coastguard Worker 
608*c2e0c6b5SAndroid Build Coastguard Worker           /*
609*c2e0c6b5SAndroid Build Coastguard Worker            * For read-only mapping try to change page attributes with not changing
610*c2e0c6b5SAndroid Build Coastguard Worker            * page type (3) and setting read-only access (bit 3 unset). Ignore any
611*c2e0c6b5SAndroid Build Coastguard Worker            * failure as this function requires DPMI 1.0 host and so it does not have
612*c2e0c6b5SAndroid Build Coastguard Worker            * to be supported by other DPMI 0.9 hosts. Note that by default newly
613*c2e0c6b5SAndroid Build Coastguard Worker            * created mapping has read/write access and so we can use it also for
614*c2e0c6b5SAndroid Build Coastguard Worker            * mappings which were requested as read-only too.
615*c2e0c6b5SAndroid Build Coastguard Worker            */
616*c2e0c6b5SAndroid Build Coastguard Worker           if (!w)
617*c2e0c6b5SAndroid Build Coastguard Worker             {
618*c2e0c6b5SAndroid Build Coastguard Worker               attributes = malloc(mi.size * sizeof(*attributes));
619*c2e0c6b5SAndroid Build Coastguard Worker               if (attributes)
620*c2e0c6b5SAndroid Build Coastguard Worker                 {
621*c2e0c6b5SAndroid Build Coastguard Worker                   /* reuse mi */
622*c2e0c6b5SAndroid Build Coastguard Worker                   for (i = 0; i < mi.size; i++)
623*c2e0c6b5SAndroid Build Coastguard Worker                     attributes[i] = (0<<3) | 3;
624*c2e0c6b5SAndroid Build Coastguard Worker 
625*c2e0c6b5SAndroid Build Coastguard Worker                   /* __dpmi_set_page_attributes modifies mi.size */
626*c2e0c6b5SAndroid Build Coastguard Worker                   size = mi.size;
627*c2e0c6b5SAndroid Build Coastguard Worker                   __dpmi_set_page_attributes(&mi, attributes);
628*c2e0c6b5SAndroid Build Coastguard Worker                   mi.size = size;
629*c2e0c6b5SAndroid Build Coastguard Worker 
630*c2e0c6b5SAndroid Build Coastguard Worker                   free(attributes);
631*c2e0c6b5SAndroid Build Coastguard Worker                 }
632*c2e0c6b5SAndroid Build Coastguard Worker             }
633*c2e0c6b5SAndroid Build Coastguard Worker         }
634*c2e0c6b5SAndroid Build Coastguard Worker 
635*c2e0c6b5SAndroid Build Coastguard Worker       return ptr;
636*c2e0c6b5SAndroid Build Coastguard Worker     }
637*c2e0c6b5SAndroid Build Coastguard Worker   else if (physmem == PHYSMEM_PHYSADDR_MAPPING)
638*c2e0c6b5SAndroid Build Coastguard Worker     {
639*c2e0c6b5SAndroid Build Coastguard Worker       /*
640*c2e0c6b5SAndroid Build Coastguard Worker        * __dpmi_physical_address_mapping() is DPMI 0.9 function and so does not
641*c2e0c6b5SAndroid Build Coastguard Worker        * require device mapping support. But DPMI hosts often allow to used it
642*c2e0c6b5SAndroid Build Coastguard Worker        * only for memory above 1 MB and also we do not have control where DPMI
643*c2e0c6b5SAndroid Build Coastguard Worker        * host maps physical memory. Because this is DPMI 0.9 function, error
644*c2e0c6b5SAndroid Build Coastguard Worker        * code on failure does not have to be provided. If DPMI host does not
645*c2e0c6b5SAndroid Build Coastguard Worker        * provide error code then in __dpmi_error variable is stored the called
646*c2e0c6b5SAndroid Build Coastguard Worker        * DPMI function number (0x0800 is for Physical Address Mapping).
647*c2e0c6b5SAndroid Build Coastguard Worker        * Error codes are provided only by DPMI 1.0 hosts.
648*c2e0c6b5SAndroid Build Coastguard Worker        */
649*c2e0c6b5SAndroid Build Coastguard Worker 
650*c2e0c6b5SAndroid Build Coastguard Worker       mi.address = addr;
651*c2e0c6b5SAndroid Build Coastguard Worker       mi.size = length;
652*c2e0c6b5SAndroid Build Coastguard Worker       if (__dpmi_physical_address_mapping(&mi) != 0)
653*c2e0c6b5SAndroid Build Coastguard Worker         {
654*c2e0c6b5SAndroid Build Coastguard Worker           /*
655*c2e0c6b5SAndroid Build Coastguard Worker            * __dpmi_physical_address_mapping() may fail for memory range which
656*c2e0c6b5SAndroid Build Coastguard Worker            * starts below 1 MB. DPMI 1.0 host in this case returns DPMI error
657*c2e0c6b5SAndroid Build Coastguard Worker            * code 0x8021 (Invalid value - address is below 1 MB boundary).
658*c2e0c6b5SAndroid Build Coastguard Worker            * DPMI 0.9 host does not provide error code, so __dpmi_error contains
659*c2e0c6b5SAndroid Build Coastguard Worker            * value 0x0800. For example this is behavior of the default DJGPP's
660*c2e0c6b5SAndroid Build Coastguard Worker            * DPMI host CWSDPMI and also of Windows 3.x DPMI host. On the other
661*c2e0c6b5SAndroid Build Coastguard Worker            * hand DPMI host HX HDPMI32 or Windows 9x DPMI host allow requests
662*c2e0c6b5SAndroid Build Coastguard Worker            * for memory ranges below 1 MB and do not fail.
663*c2e0c6b5SAndroid Build Coastguard Worker            */
664*c2e0c6b5SAndroid Build Coastguard Worker           if ((__dpmi_error == 0x0800 || __dpmi_error == 0x8021) && addr < 1*1024*1024UL)
665*c2e0c6b5SAndroid Build Coastguard Worker             {
666*c2e0c6b5SAndroid Build Coastguard Worker               /*
667*c2e0c6b5SAndroid Build Coastguard Worker                * Expects that conventional memory below 1 MB is always 1:1
668*c2e0c6b5SAndroid Build Coastguard Worker                * mapped. On non-paging DPMI hosts it is always truth and paging
669*c2e0c6b5SAndroid Build Coastguard Worker                * DPMI hosts should do it too or at least provide mapping with
670*c2e0c6b5SAndroid Build Coastguard Worker                * compatible or emulated content for compatibility with existing
671*c2e0c6b5SAndroid Build Coastguard Worker                * DOS applications. So check that requested range is below 1 MB.
672*c2e0c6b5SAndroid Build Coastguard Worker                */
673*c2e0c6b5SAndroid Build Coastguard Worker               if (addr + length > 1*1024*1024UL)
674*c2e0c6b5SAndroid Build Coastguard Worker                 {
675*c2e0c6b5SAndroid Build Coastguard Worker                   errno = ENXIO;
676*c2e0c6b5SAndroid Build Coastguard Worker                   return (void *)-1;
677*c2e0c6b5SAndroid Build Coastguard Worker                 }
678*c2e0c6b5SAndroid Build Coastguard Worker 
679*c2e0c6b5SAndroid Build Coastguard Worker               /*
680*c2e0c6b5SAndroid Build Coastguard Worker                * Simulate successful __dpmi_physical_address_mapping() call by
681*c2e0c6b5SAndroid Build Coastguard Worker                * setting the 1:1 mapped address.
682*c2e0c6b5SAndroid Build Coastguard Worker                */
683*c2e0c6b5SAndroid Build Coastguard Worker               mi.address = addr;
684*c2e0c6b5SAndroid Build Coastguard Worker             }
685*c2e0c6b5SAndroid Build Coastguard Worker           else
686*c2e0c6b5SAndroid Build Coastguard Worker             {
687*c2e0c6b5SAndroid Build Coastguard Worker               switch (__dpmi_error)
688*c2e0c6b5SAndroid Build Coastguard Worker                 {
689*c2e0c6b5SAndroid Build Coastguard Worker                 case 0x0800: /* Error code was not provided (returned by DPMI 0.9 host, error number is same as DPMI function number) */
690*c2e0c6b5SAndroid Build Coastguard Worker                   errno = EACCES;
691*c2e0c6b5SAndroid Build Coastguard Worker                   break;
692*c2e0c6b5SAndroid Build Coastguard Worker                 case 0x8003: /* System integrity (DPMI host memory region) */
693*c2e0c6b5SAndroid Build Coastguard Worker                 case 0x8021: /* Invalid value (address is below 1 MB boundary) */
694*c2e0c6b5SAndroid Build Coastguard Worker                   errno = ENXIO;
695*c2e0c6b5SAndroid Build Coastguard Worker                   break;
696*c2e0c6b5SAndroid Build Coastguard Worker                 case 0x8010: /* Resource unavailable (DPMI host cannot allocate internal resources to complete an operation) */
697*c2e0c6b5SAndroid Build Coastguard Worker                   errno = ENOMEM;
698*c2e0c6b5SAndroid Build Coastguard Worker                   break;
699*c2e0c6b5SAndroid Build Coastguard Worker                 default: /* Other unspecified error */
700*c2e0c6b5SAndroid Build Coastguard Worker                   errno = EACCES;
701*c2e0c6b5SAndroid Build Coastguard Worker                   break;
702*c2e0c6b5SAndroid Build Coastguard Worker                 }
703*c2e0c6b5SAndroid Build Coastguard Worker               return (void *)-1;
704*c2e0c6b5SAndroid Build Coastguard Worker             }
705*c2e0c6b5SAndroid Build Coastguard Worker         }
706*c2e0c6b5SAndroid Build Coastguard Worker 
707*c2e0c6b5SAndroid Build Coastguard Worker       /*
708*c2e0c6b5SAndroid Build Coastguard Worker        * Function returns linear address of the mapping. On non-paging DPMI
709*c2e0c6b5SAndroid Build Coastguard Worker        * hosts it does nothing and just returns same passed physical address.
710*c2e0c6b5SAndroid Build Coastguard Worker        * With DS descriptor limit set to 4 GB (set by __djgpp_nearptr_enable())
711*c2e0c6b5SAndroid Build Coastguard Worker        * we have direct access to any linear address. Direct access to specified
712*c2e0c6b5SAndroid Build Coastguard Worker        * linear address is from the __djgpp_conventional_base offset. Note that
713*c2e0c6b5SAndroid Build Coastguard Worker        * this is always read/write access, and there is no way to make access
714*c2e0c6b5SAndroid Build Coastguard Worker        * just read-only.
715*c2e0c6b5SAndroid Build Coastguard Worker        */
716*c2e0c6b5SAndroid Build Coastguard Worker       ptr = (void *)(mi.address + __djgpp_conventional_base);
717*c2e0c6b5SAndroid Build Coastguard Worker 
718*c2e0c6b5SAndroid Build Coastguard Worker       /*
719*c2e0c6b5SAndroid Build Coastguard Worker        * DJGPP CRT code on paging DPMI hosts enables NULL pointer protection by
720*c2e0c6b5SAndroid Build Coastguard Worker        * disabling access to the zero page. If we are running on DPMI host which
721*c2e0c6b5SAndroid Build Coastguard Worker        * does 1:1 mapping and we were asked for physical address range mapping
722*c2e0c6b5SAndroid Build Coastguard Worker        * which includes also our zero page, then we have to disable NULL pointer
723*c2e0c6b5SAndroid Build Coastguard Worker        * protection to allow access to that mapped page. Detect this by checking
724*c2e0c6b5SAndroid Build Coastguard Worker        * that our zero page [0, pagesize-1] does not conflict with the returned
725*c2e0c6b5SAndroid Build Coastguard Worker        * address range [ptr, ptr+length] (note that length is already multiply
726*c2e0c6b5SAndroid Build Coastguard Worker        * of pagesize) and change page attributes to committed page type (1) and
727*c2e0c6b5SAndroid Build Coastguard Worker        * set read/write access (bit 3 set). Ignore any failure as this function
728*c2e0c6b5SAndroid Build Coastguard Worker        * requires DPMI 1.0 host and so it does not have to be supported by other
729*c2e0c6b5SAndroid Build Coastguard Worker        * DPMI 0.9 hosts. In this case DJGPP CRT code did not enable NULL pointer
730*c2e0c6b5SAndroid Build Coastguard Worker        * protection and so zero page can be normally accessed.
731*c2e0c6b5SAndroid Build Coastguard Worker        */
732*c2e0c6b5SAndroid Build Coastguard Worker       if ((unsigned long)ptr - 1 > (unsigned long)ptr - 1 + length)
733*c2e0c6b5SAndroid Build Coastguard Worker         {
734*c2e0c6b5SAndroid Build Coastguard Worker           mi.handle = __djgpp_memory_handle_list[0].handle;
735*c2e0c6b5SAndroid Build Coastguard Worker           mi.address = 0;
736*c2e0c6b5SAndroid Build Coastguard Worker           mi.size = 1; /* number of pages */
737*c2e0c6b5SAndroid Build Coastguard Worker           one_pg_attr = (1<<3) | 1;
738*c2e0c6b5SAndroid Build Coastguard Worker           /* __dpmi_set_page_attributes modifies mi.size */
739*c2e0c6b5SAndroid Build Coastguard Worker           __dpmi_set_page_attributes(&mi, &one_pg_attr);
740*c2e0c6b5SAndroid Build Coastguard Worker         }
741*c2e0c6b5SAndroid Build Coastguard Worker 
742*c2e0c6b5SAndroid Build Coastguard Worker       return ptr;
743*c2e0c6b5SAndroid Build Coastguard Worker     }
744*c2e0c6b5SAndroid Build Coastguard Worker 
745*c2e0c6b5SAndroid Build Coastguard Worker   /* invalid physmem parameter */
746*c2e0c6b5SAndroid Build Coastguard Worker   errno = EBADF;
747*c2e0c6b5SAndroid Build Coastguard Worker   return (void *)-1;
748*c2e0c6b5SAndroid Build Coastguard Worker }
749*c2e0c6b5SAndroid Build Coastguard Worker 
750*c2e0c6b5SAndroid Build Coastguard Worker int
physmem_unmap(struct physmem * physmem,void * ptr,size_t length)751*c2e0c6b5SAndroid Build Coastguard Worker physmem_unmap(struct physmem *physmem, void *ptr, size_t length)
752*c2e0c6b5SAndroid Build Coastguard Worker {
753*c2e0c6b5SAndroid Build Coastguard Worker   long pagesize = physmem_get_pagesize(physmem);
754*c2e0c6b5SAndroid Build Coastguard Worker   unsigned pagesize_shift = ffs(pagesize)-1;
755*c2e0c6b5SAndroid Build Coastguard Worker   const __djgpp_sbrk_handle *sh;
756*c2e0c6b5SAndroid Build Coastguard Worker   unsigned long sh_size;
757*c2e0c6b5SAndroid Build Coastguard Worker   __dpmi_meminfo mi;
758*c2e0c6b5SAndroid Build Coastguard Worker   short *attributes;
759*c2e0c6b5SAndroid Build Coastguard Worker   size_t offset;
760*c2e0c6b5SAndroid Build Coastguard Worker   size_t i;
761*c2e0c6b5SAndroid Build Coastguard Worker 
762*c2e0c6b5SAndroid Build Coastguard Worker   /* Align length to page size. */
763*c2e0c6b5SAndroid Build Coastguard Worker   if (length & (pagesize-1))
764*c2e0c6b5SAndroid Build Coastguard Worker     length = (length & ~(pagesize-1)) + pagesize;
765*c2e0c6b5SAndroid Build Coastguard Worker 
766*c2e0c6b5SAndroid Build Coastguard Worker   if (physmem == PHYSMEM_DEVICE_MAPPING)
767*c2e0c6b5SAndroid Build Coastguard Worker     {
768*c2e0c6b5SAndroid Build Coastguard Worker       /*
769*c2e0c6b5SAndroid Build Coastguard Worker        * Memory mapped by __dpmi_map_conventional_memory_in_memory_block() or by
770*c2e0c6b5SAndroid Build Coastguard Worker        * __dpmi_map_device_in_memory_block() can be unmapped by changing page
771*c2e0c6b5SAndroid Build Coastguard Worker        * attributes back to the what allocator use: page type to committed (1),
772*c2e0c6b5SAndroid Build Coastguard Worker        * access to read/write (bit 3 set) and not setting initial page access
773*c2e0c6b5SAndroid Build Coastguard Worker        * and dirty bits (bit 4 unset).
774*c2e0c6b5SAndroid Build Coastguard Worker        *
775*c2e0c6b5SAndroid Build Coastguard Worker        * There is a DJGPP function __djgpp_set_page_attributes() which sets page
776*c2e0c6b5SAndroid Build Coastguard Worker        * attributes for the memory range specified by ptr pointer, but it has
777*c2e0c6b5SAndroid Build Coastguard Worker        * same disadvantages as __djgpp_map_physical_memory() function (see
778*c2e0c6b5SAndroid Build Coastguard Worker        * comment in map functionality). So use __dpmi_set_page_attributes()
779*c2e0c6b5SAndroid Build Coastguard Worker        * instead.
780*c2e0c6b5SAndroid Build Coastguard Worker        *
781*c2e0c6b5SAndroid Build Coastguard Worker        * If changing page attributes fails then do not return memory back to the
782*c2e0c6b5SAndroid Build Coastguard Worker        * malloc pool because it is still mapped to physical memory and cannot be
783*c2e0c6b5SAndroid Build Coastguard Worker        * used by allocator for general purpose anymore.
784*c2e0c6b5SAndroid Build Coastguard Worker        *
785*c2e0c6b5SAndroid Build Coastguard Worker        * Some DPMI hosts like HDPMI pre-v3.22 (part of HX pre-v2.22) or DPMIONE
786*c2e0c6b5SAndroid Build Coastguard Worker        * do not support changing page type directly from mapped to committed.
787*c2e0c6b5SAndroid Build Coastguard Worker        * But they support changing it indirectly: first from mapped to uncommitted
788*c2e0c6b5SAndroid Build Coastguard Worker        * and then from uncommitted to committed. So if direct change from mapped
789*c2e0c6b5SAndroid Build Coastguard Worker        * to committed fails then try workaround via indirect change.
790*c2e0c6b5SAndroid Build Coastguard Worker        */
791*c2e0c6b5SAndroid Build Coastguard Worker 
792*c2e0c6b5SAndroid Build Coastguard Worker       static int do_indirect_change = 0;
793*c2e0c6b5SAndroid Build Coastguard Worker 
794*c2e0c6b5SAndroid Build Coastguard Worker       for (offset = 0; offset < length; offset += (mi.size << pagesize_shift))
795*c2e0c6b5SAndroid Build Coastguard Worker         {
796*c2e0c6b5SAndroid Build Coastguard Worker           /*
797*c2e0c6b5SAndroid Build Coastguard Worker            * Find a memory handle with its size which belongs to the pointer
798*c2e0c6b5SAndroid Build Coastguard Worker            * address ptr+offset. Base address and size of the memory handle
799*c2e0c6b5SAndroid Build Coastguard Worker            * must be page aligned for changing page attributes.
800*c2e0c6b5SAndroid Build Coastguard Worker            */
801*c2e0c6b5SAndroid Build Coastguard Worker           if (!find_sbrk_memory_handle(ptr + offset, length - offset, pagesize, &sh, &sh_size) ||
802*c2e0c6b5SAndroid Build Coastguard Worker               (sh->address & (pagesize-1)) || (sh_size & (pagesize-1)))
803*c2e0c6b5SAndroid Build Coastguard Worker             {
804*c2e0c6b5SAndroid Build Coastguard Worker               errno = EINVAL;
805*c2e0c6b5SAndroid Build Coastguard Worker               return -1;
806*c2e0c6b5SAndroid Build Coastguard Worker             }
807*c2e0c6b5SAndroid Build Coastguard Worker 
808*c2e0c6b5SAndroid Build Coastguard Worker           mi.handle = sh->handle;
809*c2e0c6b5SAndroid Build Coastguard Worker           mi.address = (unsigned long)ptr + offset - sh->address;
810*c2e0c6b5SAndroid Build Coastguard Worker           mi.size = (length - offset) >> pagesize_shift;
811*c2e0c6b5SAndroid Build Coastguard Worker           if (mi.size > ((sh_size - mi.address) >> pagesize_shift))
812*c2e0c6b5SAndroid Build Coastguard Worker             mi.size = (sh_size - mi.address) >> pagesize_shift;
813*c2e0c6b5SAndroid Build Coastguard Worker 
814*c2e0c6b5SAndroid Build Coastguard Worker           attributes = malloc(mi.size * sizeof(*attributes));
815*c2e0c6b5SAndroid Build Coastguard Worker           if (!attributes)
816*c2e0c6b5SAndroid Build Coastguard Worker             {
817*c2e0c6b5SAndroid Build Coastguard Worker               errno = ENOMEM;
818*c2e0c6b5SAndroid Build Coastguard Worker               return -1;
819*c2e0c6b5SAndroid Build Coastguard Worker             }
820*c2e0c6b5SAndroid Build Coastguard Worker 
821*c2e0c6b5SAndroid Build Coastguard Worker retry_via_indirect_change:
822*c2e0c6b5SAndroid Build Coastguard Worker           if (do_indirect_change)
823*c2e0c6b5SAndroid Build Coastguard Worker             {
824*c2e0c6b5SAndroid Build Coastguard Worker               for (i = 0; i < mi.size; i++)
825*c2e0c6b5SAndroid Build Coastguard Worker                 attributes[i] = (0<<4) | (0<<3) | 0; /* 0 = page type uncommitted */
826*c2e0c6b5SAndroid Build Coastguard Worker 
827*c2e0c6b5SAndroid Build Coastguard Worker               if (set_and_get_page_attributes(&mi, attributes) != 0)
828*c2e0c6b5SAndroid Build Coastguard Worker                 return -1;
829*c2e0c6b5SAndroid Build Coastguard Worker 
830*c2e0c6b5SAndroid Build Coastguard Worker               for (i = 0; i < mi.size; i++)
831*c2e0c6b5SAndroid Build Coastguard Worker                 {
832*c2e0c6b5SAndroid Build Coastguard Worker                   /* Check that every page type is uncommitted (0). */
833*c2e0c6b5SAndroid Build Coastguard Worker                   if ((attributes[i] & 0x7) != 0)
834*c2e0c6b5SAndroid Build Coastguard Worker                     {
835*c2e0c6b5SAndroid Build Coastguard Worker                       free(attributes);
836*c2e0c6b5SAndroid Build Coastguard Worker                       errno = EACCES;
837*c2e0c6b5SAndroid Build Coastguard Worker                       return -1;
838*c2e0c6b5SAndroid Build Coastguard Worker                     }
839*c2e0c6b5SAndroid Build Coastguard Worker                 }
840*c2e0c6b5SAndroid Build Coastguard Worker             }
841*c2e0c6b5SAndroid Build Coastguard Worker 
842*c2e0c6b5SAndroid Build Coastguard Worker           for (i = 0; i < mi.size; i++)
843*c2e0c6b5SAndroid Build Coastguard Worker             attributes[i] = (0<<4) | (1<<3) | 1; /* 1 = page type committed */
844*c2e0c6b5SAndroid Build Coastguard Worker 
845*c2e0c6b5SAndroid Build Coastguard Worker           if (set_and_get_page_attributes(&mi, attributes) != 0)
846*c2e0c6b5SAndroid Build Coastguard Worker             return -1;
847*c2e0c6b5SAndroid Build Coastguard Worker 
848*c2e0c6b5SAndroid Build Coastguard Worker           for (i = 0; i < mi.size; i++)
849*c2e0c6b5SAndroid Build Coastguard Worker             {
850*c2e0c6b5SAndroid Build Coastguard Worker               /* Check that every page type is committed (1) and has read/write access (bit 3 set). */
851*c2e0c6b5SAndroid Build Coastguard Worker               if (((attributes[i] & 0x7) != 1) || !(attributes[i] & (1<<3)))
852*c2e0c6b5SAndroid Build Coastguard Worker                 {
853*c2e0c6b5SAndroid Build Coastguard Worker                   if (!do_indirect_change)
854*c2e0c6b5SAndroid Build Coastguard Worker                     {
855*c2e0c6b5SAndroid Build Coastguard Worker                       /*
856*c2e0c6b5SAndroid Build Coastguard Worker                        * Some DPMI hosts do not support changing page type
857*c2e0c6b5SAndroid Build Coastguard Worker                        * from mapped to committed but for such change request
858*c2e0c6b5SAndroid Build Coastguard Worker                        * do not report any error. Try following workaround:
859*c2e0c6b5SAndroid Build Coastguard Worker                        * Change page type indirectly. First change page type
860*c2e0c6b5SAndroid Build Coastguard Worker                        * from mapped to uncommitted and then to committed.
861*c2e0c6b5SAndroid Build Coastguard Worker                        */
862*c2e0c6b5SAndroid Build Coastguard Worker                       do_indirect_change = 1;
863*c2e0c6b5SAndroid Build Coastguard Worker                       goto retry_via_indirect_change;
864*c2e0c6b5SAndroid Build Coastguard Worker                     }
865*c2e0c6b5SAndroid Build Coastguard Worker                   free(attributes);
866*c2e0c6b5SAndroid Build Coastguard Worker                   errno = EACCES;
867*c2e0c6b5SAndroid Build Coastguard Worker                   return -1;
868*c2e0c6b5SAndroid Build Coastguard Worker                 }
869*c2e0c6b5SAndroid Build Coastguard Worker             }
870*c2e0c6b5SAndroid Build Coastguard Worker 
871*c2e0c6b5SAndroid Build Coastguard Worker           free(attributes);
872*c2e0c6b5SAndroid Build Coastguard Worker         }
873*c2e0c6b5SAndroid Build Coastguard Worker 
874*c2e0c6b5SAndroid Build Coastguard Worker       /*
875*c2e0c6b5SAndroid Build Coastguard Worker        * Now we are sure that ptr is backed by committed memory which can be
876*c2e0c6b5SAndroid Build Coastguard Worker        * returned back to the DJGPP sbrk pool.
877*c2e0c6b5SAndroid Build Coastguard Worker        */
878*c2e0c6b5SAndroid Build Coastguard Worker       aligned_free(ptr);
879*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
880*c2e0c6b5SAndroid Build Coastguard Worker     }
881*c2e0c6b5SAndroid Build Coastguard Worker   else if (physmem == PHYSMEM_PHYSADDR_MAPPING)
882*c2e0c6b5SAndroid Build Coastguard Worker     {
883*c2e0c6b5SAndroid Build Coastguard Worker       /*
884*c2e0c6b5SAndroid Build Coastguard Worker        * Physical address mapping done by __dpmi_physical_address_mapping() can
885*c2e0c6b5SAndroid Build Coastguard Worker        * be unmapped only by __dpmi_free_physical_address_mapping() function.
886*c2e0c6b5SAndroid Build Coastguard Worker        * This function takes linear address of the mapped region. Direct access
887*c2e0c6b5SAndroid Build Coastguard Worker        * pointer refers to linear address from the __djgpp_conventional_base
888*c2e0c6b5SAndroid Build Coastguard Worker        * offset. On non-paging DPMI hosts, physical memory cannot be unmapped at
889*c2e0c6b5SAndroid Build Coastguard Worker        * all because whole physical memory is always available and so this
890*c2e0c6b5SAndroid Build Coastguard Worker        * function either fails or does nothing. Moreover this unmapping function
891*c2e0c6b5SAndroid Build Coastguard Worker        * requires DPMI 1.0 host as opposite of the mapping function which is
892*c2e0c6b5SAndroid Build Coastguard Worker        * available also in DPMI 0.9. It means that DPMI 0.9 hosts do not provide
893*c2e0c6b5SAndroid Build Coastguard Worker        * ability to unmap already mapped physical addresses. This DPMI unmapping
894*c2e0c6b5SAndroid Build Coastguard Worker        * function is not commonly supported by DPMI hosts, even the default
895*c2e0c6b5SAndroid Build Coastguard Worker        * DJGPP's CWSDPMI does not support it. But few alternative DPMI host like
896*c2e0c6b5SAndroid Build Coastguard Worker        * PMODE/DJ, WDOSX, HDPMI32 or DPMIONE support it. So expects failure from
897*c2e0c6b5SAndroid Build Coastguard Worker        * this function call, in most cases it is not possible to unmap physical
898*c2e0c6b5SAndroid Build Coastguard Worker        * memory which was previously mapped by __dpmi_physical_address_mapping().
899*c2e0c6b5SAndroid Build Coastguard Worker        */
900*c2e0c6b5SAndroid Build Coastguard Worker       mi.address = (unsigned long)ptr - __djgpp_conventional_base;
901*c2e0c6b5SAndroid Build Coastguard Worker       if (__dpmi_free_physical_address_mapping(&mi) != 0)
902*c2e0c6b5SAndroid Build Coastguard Worker         {
903*c2e0c6b5SAndroid Build Coastguard Worker           /*
904*c2e0c6b5SAndroid Build Coastguard Worker            * Do not report error when DPMI function failed with error code
905*c2e0c6b5SAndroid Build Coastguard Worker            * 0x8025 (invalid linear address) and linear address is below 1 MB.
906*c2e0c6b5SAndroid Build Coastguard Worker            * First 1 MB of memory space should stay always mapped.
907*c2e0c6b5SAndroid Build Coastguard Worker            */
908*c2e0c6b5SAndroid Build Coastguard Worker           if (__dpmi_error != 0x8025 || mi.address >= 1*1024*1024UL)
909*c2e0c6b5SAndroid Build Coastguard Worker             {
910*c2e0c6b5SAndroid Build Coastguard Worker               switch (__dpmi_error)
911*c2e0c6b5SAndroid Build Coastguard Worker                 {
912*c2e0c6b5SAndroid Build Coastguard Worker                 case 0x0801: /* Unsupported function (returned by DPMI 0.9 host, error number is same as DPMI function number) */
913*c2e0c6b5SAndroid Build Coastguard Worker                 case 0x8001: /* Unsupported function (returned by DPMI 1.0 host) */
914*c2e0c6b5SAndroid Build Coastguard Worker                   errno = ENOSYS;
915*c2e0c6b5SAndroid Build Coastguard Worker                   break;
916*c2e0c6b5SAndroid Build Coastguard Worker                 case 0x8010: /* Resource unavailable (DPMI host cannot allocate internal resources to complete an operation) */
917*c2e0c6b5SAndroid Build Coastguard Worker                   errno = ENOMEM;
918*c2e0c6b5SAndroid Build Coastguard Worker                   break;
919*c2e0c6b5SAndroid Build Coastguard Worker                 case 0x8025: /* Invalid linear address */
920*c2e0c6b5SAndroid Build Coastguard Worker                   errno = EINVAL;
921*c2e0c6b5SAndroid Build Coastguard Worker                   break;
922*c2e0c6b5SAndroid Build Coastguard Worker                 default: /* Other unspecified error */
923*c2e0c6b5SAndroid Build Coastguard Worker                   errno = EACCES;
924*c2e0c6b5SAndroid Build Coastguard Worker                   break;
925*c2e0c6b5SAndroid Build Coastguard Worker                 }
926*c2e0c6b5SAndroid Build Coastguard Worker               return -1;
927*c2e0c6b5SAndroid Build Coastguard Worker             }
928*c2e0c6b5SAndroid Build Coastguard Worker         }
929*c2e0c6b5SAndroid Build Coastguard Worker 
930*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
931*c2e0c6b5SAndroid Build Coastguard Worker     }
932*c2e0c6b5SAndroid Build Coastguard Worker 
933*c2e0c6b5SAndroid Build Coastguard Worker   /* invalid physmem parameter */
934*c2e0c6b5SAndroid Build Coastguard Worker   errno = EBADF;
935*c2e0c6b5SAndroid Build Coastguard Worker   return -1;
936*c2e0c6b5SAndroid Build Coastguard Worker }
937