source: GPL/trunk/lib32/memory.c@ 587

Last change on this file since 587 was 587, checked in by David Azarewicz, 9 years ago

Rearrange directory structure
rework makefiles
cleanup files

File size: 19.1 KB
Line 
1/* $Id: memory.cpp,v 1.1.1.1 2003/07/02 13:57:02 eleph Exp $ */
2/*
3 * OS/2 implementation of Linux memory kernel services
4 *
5 * (C) 2000-2002 InnoTek Systemberatung GmbH
6 * (C) 2000-2001 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
21 * USA.
22 *
23 */
24
25#define INCL_NOPMAPI
26#define INCL_DOSERRORS // for ERROR_INVALID_FUNCTION
27#include <os2.h>
28#include <devhelp.h>
29#include <ossidc.h>
30#include <string.h>
31#include <dbgos2.h>
32#include <stacktoflat.h>
33#include <limits.h>
34#ifdef KEE
35#include <kee.h>
36#endif
37#include "malloc.h"
38
39#pragma off (unreferenced)
40
41#define PAGE_SIZE 4096
42
43int free_pages(unsigned long addr, unsigned long order);
44int __compat_get_order(unsigned long size);
45#ifdef DEBUGHEAP
46void near *__kmalloc(int size, int flags, const char *filename, int lineno);
47void __kfree(const void near *ptr, const char *filename, int lineno);
48#else
49void near *__kmalloc(int size, int flags);
50void __kfree(const void near *ptr);
51#endif
52
53#ifdef DEBUGHEAP
54#define _kmalloc(a, b) __kmalloc(a, b, __FILE__, __LINE__)
55#define _kfree(a) __kfree(a, __FILE__, __LINE__)
56#else
57#define _kmalloc(a, b) __kmalloc(a, b)
58#define _kfree(a) __kfree(a)
59#endif
60
61typedef struct _BaseAddr {
62 ULONG base;
63 ULONG retaddr;
64 ULONG size;
65 struct _BaseAddr NEAR *next;
66} BaseAddr;
67
68static BaseAddr NEAR *pBaseAddrHead = NULL;
69
70//******************************************************************************
71//Very simple linked list for storing original addresses returned by VMAlloc
72//if returned address is different due to alignment requirements
73//Performance is not an issue as the alloc & free functions aren't called often.
74//(e.g. ALS4000 driver calls it 4 times (2 alloc during boot, 2 during shutdown)
75//******************************************************************************
76void AddBaseAddress(ULONG baseaddr, ULONG retaddr, ULONG size)
77{
78 BaseAddr NEAR *pBase;
79
80 pBase = (BaseAddr NEAR *)_kmalloc(sizeof(BaseAddr), 0);
81 if(pBase == NULL) {
82 DebugInt3();
83 return;
84 }
85 DevCli();
86 pBase->base = baseaddr;
87 pBase->retaddr = retaddr;
88 pBase->size = size;
89 pBase->next = pBaseAddrHead;
90 pBaseAddrHead = pBase;
91 DevSti();
92}
93//******************************************************************************
94//******************************************************************************
95ULONG GetBaseAddress(ULONG addr, ULONG *pSize)
96{
97 BaseAddr NEAR *pCur, NEAR *pTemp;
98
99 if(pBaseAddrHead == NULL) return addr;
100
101 DevCli();
102 pCur = pBaseAddrHead;
103
104 if(pCur->retaddr == addr)
105 {
106 addr = pCur->base;
107 if(pSize) *pSize = pCur->size;
108 pBaseAddrHead = pCur->next;
109 _kfree(pCur);
110 }
111 else
112 while(pCur->next) {
113 if(pCur->next->retaddr == addr) {
114 pTemp = pCur->next;
115 addr = pTemp->base;
116 if(pSize) *pSize = pTemp->size;
117 pCur->next = pTemp->next;
118
119 _kfree(pTemp);
120 break;
121 }
122 pCur = pCur->next;
123 }
124 DevSti();
125 return addr;
126}
127//******************************************************************************
128//NOTE: Assumes memory is continuous!!
129//******************************************************************************
130unsigned long virt_to_phys(void * address)
131{
132#ifdef KEE
133 KEEVMPageList pagelist;
134 ULONG nrpages;
135
136 if(KernLinToPageList(address, PAGE_SIZE, &pagelist, &nrpages)) {
137 DebugInt3();
138 return 0;
139 }
140 return pagelist.addr;
141#else
142 LINEAR addr = (LINEAR)address;
143 PAGELIST pagelist;
144
145 if(DevLinToPageList(addr, PAGE_SIZE, (PAGELIST NEAR *)__Stack32ToFlat((ULONG)&pagelist))) {
146 DebugInt3();
147 return 0;
148 }
149 return pagelist.physaddr;
150#endif
151}
152//******************************************************************************
153//******************************************************************************
154void * phys_to_virt(unsigned long address)
155{
156 APIRET rc = 0;
157 ULONG addr = 0;
158
159#ifdef KEE
160 SHORT sel;
161 rc = KernVMAlloc(PAGE_SIZE, VMDHA_PHYS, (PVOID*)&addr, (PVOID*)&address, &sel);
162#else
163 rc = DevVMAlloc(VMDHA_PHYS, PAGE_SIZE, (LINEAR)&address, __Stack32ToFlat((ULONG)&addr));
164#endif
165 if (rc != 0) {
166 DebugInt3();
167 return NULL;
168 }
169 return (void *)addr;
170}
171//******************************************************************************
172extern int fStrategyInit;
173//******************************************************************************
174APIRET VMAlloc(ULONG size, ULONG flags, LINEAR *pAddr)
175{
176 APIRET rc;
177 ULONG addr;
178 SHORT sel;
179
180 if(fStrategyInit && !(flags & VMDHA_16M)) {
181 flags |= VMDHA_USEHIGHMEM;
182 }
183
184__again:
185
186#ifdef KEE
187
188 rc = KernVMAlloc(size, flags, (PVOID*)&addr, (PVOID*)-1, &sel);
189#else
190 rc = DevVMAlloc(flags, size, (LINEAR)-1, __Stack32ToFlat((ULONG)&addr));
191#endif
192 if (rc == 0) {
193 *pAddr = (LINEAR)addr;
194 if (flags & VMDHA_USEHIGHMEM)
195 dprintf1((("allocated %X in HIGH memory\n"), size));
196 else dprintf1((("allocated %X in LOW memory\n"), size));
197 }
198 if ((rc == 87) && (flags & VMDHA_USEHIGHMEM))
199 {
200 // EARLYMEMINIT workaround
201 flags = flags & (~VMDHA_USEHIGHMEM);
202 goto __again;
203 }
204 return rc;
205}
206//******************************************************************************
207//******************************************************************************
208APIRET VMFree(LINEAR addr)
209{
210 APIRET rc;
211
212#ifdef KEE
213 rc = KernVMFree((PVOID)addr);
214#else
215 rc = DevVMFree((LINEAR)addr);
216#endif
217 if(rc) {
218 DebugInt3();
219 }
220
221 return rc;
222}
223//******************************************************************************
224ULONG ulget_free_pagesMemUsed = 0;
225
226#define GFP_DMA 0x80
227#define GFP_DMAHIGHMEM 0x100
228//******************************************************************************
229//******************************************************************************
230void *__get_free_dma_pages(unsigned long size, unsigned long flags)
231{
232 ULONG addr, physaddr, physaddr2, diff, tempaddr;
233 APIRET rc;
234
235 if(VMAlloc(size, flags, (LINEAR *)&addr)) {
236 DebugInt3();
237 return 0;
238 }
239 physaddr = virt_to_phys((void *)addr);
240 if(physaddr) {
241 ULONG startpage = (physaddr >> 16);
242 ULONG endpage = (physaddr + ((size < 0x10000) ? size : 63*1024)) >> 16;
243
244 if(startpage != endpage) {
245 //try once more
246 rc = VMAlloc(size, flags, (LINEAR *)&tempaddr);
247 VMFree((LINEAR)addr);
248 if(rc) {
249 DebugInt3();
250 return 0;
251 }
252 addr = tempaddr;
253
254 physaddr = virt_to_phys((void *)addr);
255 if(physaddr) {
256 ULONG startpage = (physaddr >> 16);
257 ULONG endpage = (physaddr + ((size < 0x10000) ? size : 63*1024)) >> 16;
258
259 if(startpage != endpage) {
260 //oops, this didn't work, fail
261 VMFree((LINEAR)addr);
262 dprintf(("get_free_dma_pages failed %x size:%x st:%x end:%x, trying wasteful method instead", physaddr, size, startpage, endpage));
263 return 0;
264 }
265 }
266 }
267 }
268 else {
269 DebugInt3();
270 VMFree((LINEAR)addr);
271 addr = 0;
272 }
273
274 if(addr) {
275 //only done to save size of memory block
276 AddBaseAddress(addr, addr, size);
277 ulget_free_pagesMemUsed += size;
278 dprintf(("get_free_dma_pages: size=%x adr=%x (phys %x) total alloc size=%x",
279 size, (ULONG)addr, virt_to_phys((void *)addr), ulget_free_pagesMemUsed));
280 }
281
282 return (void *)addr;
283}
284//******************************************************************************
285//******************************************************************************
286void *__get_free_pages(int gfp_mask, unsigned long order)
287{
288 ULONG addr;
289 ULONG flags = VMDHA_FIXED|VMDHA_CONTIG;
290 ULONG size, allocsize;
291
292 order = (1 << order); //TODO: Is this correct???
293 size = order * PAGE_SIZE;
294
295 if(gfp_mask & (GFP_DMA|GFP_DMAHIGHMEM))
296 {//below 16 mb for legacy DMA?
297 if(gfp_mask & GFP_DMA)
298 flags |= VMDHA_16M;
299
300 //these buffers must be aligned at 64kb boundary
301
302 //first try a less wasteful approach
303 void *pBlock;
304
305 pBlock = __get_free_dma_pages(size, flags);
306 if(pBlock) {
307 return pBlock;
308 }
309 //else allocate extra memory to make sure we can satisfy
310 //the alignment requirement
311 if(size < 0x10000) {
312 allocsize = size * 2;
313 }
314 else {
315 allocsize = size + 0x10000;
316 }
317 }
318 else allocsize = size;
319
320 if(VMAlloc(allocsize, flags, (LINEAR *)&addr)) {
321 DebugInt3();
322 return 0;
323 }
324 //dprintf(("__get_free_pages %d returned %x", order*PAGE_SIZE, addr));
325 if(gfp_mask & (GFP_DMA|GFP_DMAHIGHMEM))
326 {//must be aligned at 64kb boundary
327 ULONG physaddr = virt_to_phys((void *)addr);
328 ULONG physaddr2;
329
330 if(physaddr) {
331 ULONG startpage = (physaddr >> 16);
332 ULONG endpage = (physaddr + ((size < 0x10000) ? size : 63*1024)) >> 16;
333
334 if (startpage != endpage) {
335 physaddr2 = (startpage+1) << 16;
336
337 AddBaseAddress(addr, addr + (physaddr2 - physaddr), allocsize);
338 addr += (physaddr2 - physaddr);
339 }
340 }
341 else {
342 DebugInt3();
343 free_pages(addr, order);
344 addr = 0;
345 }
346 }
347 else {
348 //only done to save size of memory block
349 AddBaseAddress(addr, addr, allocsize);
350 }
351 if(addr) {
352 //dprintf(("get_free_pages %d (%d) -> %x (phys %x)", allocsize, size, (ULONG)addr, virt_to_phys((void *)addr)));
353 ulget_free_pagesMemUsed += allocsize;
354 //dprintf(("get_free_pages: total alloc size %d", ulget_free_pagesMemUsed));
355 }
356 return (void *)addr;
357}
358//******************************************************************************
359//******************************************************************************
360int free_pages(unsigned long addr, unsigned long order)
361{
362 ULONG rc, size = 0;
363
364 //check if it really is the base of the allocation (see above)
365 addr = GetBaseAddress(addr, (ULONG NEAR *)__Stack32ToFlat(&size));
366
367 if(VMFree((LINEAR)addr)) {
368 DebugInt3();
369 }
370 else {
371 //dprintf(("free_pages %x size %d", (ULONG)addr, size));
372 ulget_free_pagesMemUsed -= size;
373 //dprintf(("free_pages: total alloc size %d", ulget_free_pagesMemUsed));
374 }
375 //dprintf(("free_pages %x", addr));
376 return 0;
377}
378//******************************************************************************
379//******************************************************************************
380void *vmalloc(unsigned long size)
381{
382 ULONG addr = 0;
383 ULONG flags = VMDHA_FIXED|VMDHA_CONTIG;
384
385 //round to next page boundary
386 size = size + PAGE_SIZE - 1;
387 size &= 0xFFFFF000;
388
389 if(VMAlloc(size, flags, (LINEAR *)&addr)) {
390 DebugInt3();
391 return 0;
392 }
393 if(addr) {
394 //dprintf(("vmalloc %d -> %x (phys %x)", size, addr, virt_to_phys((void *)addr)));
395 //only done to save size of memory block
396 AddBaseAddress(addr, addr, size);
397 ulget_free_pagesMemUsed += size;
398 //dprintf(("vmalloc: total alloc size %d", ulget_free_pagesMemUsed));
399 }
400 return (void *)addr;
401}
402//******************************************************************************
403//******************************************************************************
404void vfree(void *ptr)
405{
406 APIRET rc;
407 ULONG size = 0;
408
409 GetBaseAddress((ULONG)ptr, (ULONG NEAR *)__Stack32ToFlat(&size));
410
411 if(VMFree((LINEAR)ptr)) {
412 DebugInt3();
413 }
414 else {
415 //dprintf(("vfree %x size %d", (ULONG)ptr, size));
416 ulget_free_pagesMemUsed -= size;
417 //dprintf(("vfree: total alloc size %d", ulget_free_pagesMemUsed));
418 }
419}
420//******************************************************************************
421//******************************************************************************
422struct page * alloc_pages(int gfp_mask, unsigned long order)
423{
424 DebugInt3();
425 return 0;
426}
427//******************************************************************************
428//******************************************************************************
429int remap_page_range(unsigned long from, unsigned long to, unsigned long size, unsigned long prot)
430{
431 DebugInt3();
432 return 0;
433}
434//******************************************************************************
435//Map physical address (memory mapped io range) to linear
436//******************************************************************************
437void * __ioremap(unsigned long physaddr, unsigned long size, unsigned long flags)
438{
439 ULONG addr = 0, Offset = 0, PhysicalAddress = 0, Length = 0;
440 APIRET rc;
441
442 PhysicalAddress = physaddr;
443 Length = size;
444
445 Offset = PhysicalAddress & (PAGE_SIZE - 1); // within Page
446 Length = (Length + Offset + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
447 PhysicalAddress &= ~(PAGE_SIZE - 1);
448 //dprintf(("ioremap: len %d phys %x off %x", Length, PhysicalAddress, Offset));
449
450 //round to next page boundary
451 //size = size + PAGE_SIZE - 1;
452 //size &= 0xFFFFF000;
453
454#ifdef KEE
455 SHORT sel;
456
457 //rc = KernVMAlloc(size, VMDHA_PHYS, (PVOID*)&addr, (PVOID*)&physaddr, &sel);
458 rc = KernVMAlloc(Length, VMDHA_PHYS, (PVOID*)&addr, (PVOID*)&PhysicalAddress, &sel);
459#else
460 //rc = DevVMAlloc(VMDHA_PHYS, size, (LINEAR)&physaddr, __Stack32ToFlat((ULONG)&addr));
461 rc = DevVMAlloc(VMDHA_PHYS, Length, (LINEAR)&PhysicalAddress, __Stack32ToFlat((ULONG)&addr));
462#endif
463 if (rc != 0) {
464 dprintf(("ioremap error: %x", rc));
465 DebugInt3();
466 return NULL;
467 }
468 return (void *)( addr + Offset) ; //PS
469}
470//******************************************************************************
471//******************************************************************************
472void iounmap(void *addr)
473{
474LINEAR ad;
475
476 ad=(LINEAR)addr;
477 // *ad &= ~(0xfff); // 12 Jun 07 SHL this looks wrong
478 ad = (LINEAR)((ULONG)ad & ~0xfff); // 12 Jun 07 SHL Round down to 4KiB
479 if(VMFree((LINEAR)ad)) {
480 DebugInt3();
481 }
482}
483//******************************************************************************
484//******************************************************************************
485int is_access_ok(int type, void *addr, unsigned long size)
486{
487 return 1;
488}
489//******************************************************************************
490//******************************************************************************
491void __copy_user(void *to, const void *from, unsigned long n)
492{
493 if(to == NULL || from == NULL) {
494 DebugInt3();
495 return;
496 }
497 if(n == 0) return;
498
499 kmemcpy(to, from, n);
500}
501//******************************************************************************
502//******************************************************************************
503unsigned long copy_to_user(void *to, const void *from, unsigned long n)
504{
505 if(to == NULL || from == NULL) {
506 DebugInt3();
507 return 0;
508 }
509 if(n == 0) return 0;
510
511 kmemcpy(to, from, n);
512 return 0;
513}
514//******************************************************************************
515//******************************************************************************
516void __copy_user_zeroing(void *to, const void *from, unsigned long n)
517{
518 if(to == NULL || from == NULL) {
519 DebugInt3();
520 return;
521 }
522 if(n == 0) return;
523
524 copy_to_user(to, from, n);
525}
526//******************************************************************************
527//******************************************************************************
528unsigned long copy_from_user(void *to, const void *from, unsigned long n)
529{
530 if(to == NULL || from == NULL) {
531 DebugInt3();
532 return 0;
533 }
534 if(n == 0) return 0;
535
536 kmemcpy(to, from, n);
537 return 0;
538}
539//******************************************************************************
540//******************************************************************************
541int __get_user(int size, void *dest, void *src)
542{
543 if(size == 0) return 0;
544
545 if(dest == NULL || src == NULL) {
546 DebugInt3();
547 return 0;
548 }
549 kmemcpy(dest, src, size);
550 return 0;
551}
552//******************************************************************************
553//******************************************************************************
554int _put_user(int size, int x, void *ptr)
555{
556 if(ptr == NULL || size == 0) {
557 DebugInt3();
558 return 0;
559 }
560
561 *(int *)ptr = x;
562 return 0;
563}
564
565//******************************************************************************
566#ifdef DEBUGHEAP
567void *__kmalloc(int size, int flags, const char *filename, int lineno)
568#else
569void *__kmalloc(int size, int flags)
570#endif
571{
572 LINEAR addr;
573
574 if(size == 0) {
575 DebugInt3();
576 return NULL;
577 }
578 if(flags & GFP_DMA) {
579 DebugInt3();
580 }
581 if(size >= 4096) {
582 return vmalloc(size);
583 }
584#ifdef DEBUGHEAP
585 addr = (LINEAR)malloc(size, filename, lineno);
586#else
587 addr = (LINEAR)malloc(size);
588#endif
589 if(addr == NULL) {
590 DebugInt3();
591 return 0;
592 }
593 //dprintf(("kmalloc %d returned %x", size, addr));
594 return addr;
595}
596
597//******************************************************************************
598#ifdef DEBUGHEAP
599void __kfree(const void *ptr, const char *filename, int lineno)
600#else
601void __kfree(const void *ptr)
602#endif
603{
604 ULONG addr;
605
606 addr = (ULONG)ptr;
607 if(addr == 0)
608 {
609 DebugInt3();
610 return;
611 }
612 //dprintf(("kfree %x", addr));
613 if(IsHeapAddr(addr)) {
614#ifdef DEBUGHEAP
615 free((void *)addr, filename, lineno);
616#else
617 free((void *)addr);
618#endif
619 }
620 else vfree((PVOID)addr);
621}
622
623//******************************************************************************
624void *kzalloc(size_t size, unsigned int flags)
625{
626 void *ret;
627 ret = _kmalloc(size, flags);
628 if (ret)
629 memset(ret, 0, size);
630 return ret;
631}
632//******************************************************************************
633//******************************************************************************
634void *kcalloc(size_t n, size_t size, unsigned int flags)
635{
636 if (n != 0 && size > INT_MAX / n)
637 return NULL;
638 return kzalloc(n * size, flags);
639}
640
Note: See TracBrowser for help on using the repository browser.