source: GPL/trunk/lib32/memory.cpp@ 577

Last change on this file since 577 was 518, checked in by David Azarewicz, 15 years ago

Some of my updates from the 2.1.x branch

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