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

Last change on this file since 424 was 340, checked in by Paul Smedley, 17 years ago

Set SVN revision in uniaud.inc for 1.9.3 release

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