source: GPL/lib32/memory.cpp@ 18

Last change on this file since 18 was 18, checked in by vladest, 20 years ago

initial import

File size: 18.9 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 }
198 if ((rc == 87) &&
199 (flags & VMDHA_USEHIGHMEM))
200 {
201 // EARLYMEMINIT workaround
202 flags = flags & (~VMDHA_USEHIGHMEM);
203 goto __again;
204 }
205 return rc;
206}
207//******************************************************************************
208//******************************************************************************
209APIRET VMFree(LINEAR addr)
210{
211 APIRET rc;
212
213#ifdef KEE
214 rc = KernVMFree((PVOID)addr);
215#else
216 rc = DevVMFree((LINEAR)addr);
217#endif
218 if(rc) {
219 DebugInt3();
220 }
221
222 return rc;
223}
224//******************************************************************************
225ULONG ulget_free_pagesMemUsed = 0;
226
227#define GFP_DMA 0x80
228#define GFP_DMAHIGHMEM 0x100
229//******************************************************************************
230//******************************************************************************
231void *__get_free_dma_pages(unsigned long size, unsigned long flags)
232{
233 ULONG addr, physaddr, physaddr2, diff, tempaddr;
234 APIRET rc;
235
236 if(VMAlloc(size, flags, (LINEAR *)&addr)) {
237 DebugInt3();
238 return 0;
239 }
240 physaddr = virt_to_phys((void *)addr);
241 if(physaddr) {
242 ULONG startpage = (physaddr >> 16);
243 ULONG endpage = (physaddr + ((size < 0x10000) ? size : 63*1024)) >> 16;
244
245 if(startpage != endpage) {
246 //try once more
247 rc = VMAlloc(size, flags, (LINEAR *)&tempaddr);
248 VMFree((LINEAR)addr);
249 if(rc) {
250 DebugInt3();
251 return 0;
252 }
253 addr = tempaddr;
254
255 physaddr = virt_to_phys((void *)addr);
256 if(physaddr) {
257 ULONG startpage = (physaddr >> 16);
258 ULONG endpage = (physaddr + ((size < 0x10000) ? size : 63*1024)) >> 16;
259
260 if(startpage != endpage) {
261 //oops, this didn't work, fail
262 VMFree((LINEAR)addr);
263 dprintf(("get_free_dma_pages failed, trying wasteful method instead"));
264 return 0;
265 }
266 }
267 }
268 }
269 else {
270 DebugInt3();
271 VMFree((LINEAR)addr);
272 addr = 0;
273 }
274
275 if(addr) {
276 //only done to save size of memory block
277 AddBaseAddress(addr, addr, size);
278#ifdef DEBUG
279 dprintf(("get_free_dma_pages %d -> %x (phys %x)", size, (ULONG)addr, virt_to_phys((void *)addr)));
280#endif
281 ulget_free_pagesMemUsed += size;
282#ifdef DEBUG
283 dprintf(("get_free_dma_pages: total alloc size %d", ulget_free_pagesMemUsed));
284#endif
285 }
286
287 return (void *)addr;
288}
289//******************************************************************************
290//******************************************************************************
291void *__get_free_pages(int gfp_mask, unsigned long order)
292{
293 ULONG addr;
294 ULONG flags = VMDHA_FIXED|VMDHA_CONTIG;
295 ULONG size, allocsize;
296
297 order = (1 << order); //TODO: Is this correct???
298 size = order * PAGE_SIZE;
299
300 if(gfp_mask & (GFP_DMA|GFP_DMAHIGHMEM))
301 {//below 16 mb for legacy DMA?
302 if(gfp_mask & GFP_DMA)
303 flags |= VMDHA_16M;
304
305 //these buffers must be aligned at 64kb boundary
306
307 //first try a less wasteful approach
308 void *pBlock;
309
310 pBlock = __get_free_dma_pages(size, flags);
311 if(pBlock) {
312 return pBlock;
313 }
314 //else allocate extra memory to make sure we can satisfy
315 //the alignment requirement
316 if(size < 0x10000) {
317 allocsize = size * 2;
318 }
319 else {
320 allocsize = size + 0x10000;
321 }
322 }
323 else allocsize = size;
324
325 if(VMAlloc(allocsize, flags, (LINEAR *)&addr)) {
326 DebugInt3();
327 return 0;
328 }
329//// dprintf(("__get_free_pages %d returned %x", order*PAGE_SIZE, addr));
330 if(gfp_mask & (GFP_DMA|GFP_DMAHIGHMEM))
331 {//must be aligned at 64kb boundary
332 ULONG physaddr = virt_to_phys((void *)addr);
333 ULONG physaddr2;
334
335 if(physaddr) {
336 ULONG startpage = (physaddr >> 16);
337 ULONG endpage = (physaddr + ((size < 0x10000) ? size : 63*1024)) >> 16;
338
339 if (startpage != endpage) {
340 physaddr2 = (startpage+1) << 16;
341
342 AddBaseAddress(addr, addr + (physaddr2 - physaddr), allocsize);
343 addr += (physaddr2 - physaddr);
344 }
345 }
346 else {
347 DebugInt3();
348 free_pages(addr, order);
349 addr = 0;
350 }
351 }
352 else {
353 //only done to save size of memory block
354 AddBaseAddress(addr, addr, allocsize);
355 }
356 if(addr) {
357#ifdef DEBUG
358 dprintf(("get_free_pages %d (%d) -> %x (phys %x)", allocsize, size, (ULONG)addr, virt_to_phys((void *)addr)));
359#endif
360 ulget_free_pagesMemUsed += allocsize;
361#ifdef DEBUG
362 dprintf(("get_free_pages: total alloc size %d", ulget_free_pagesMemUsed));
363#endif
364 }
365 return (void *)addr;
366}
367//******************************************************************************
368//******************************************************************************
369int free_pages(unsigned long addr, unsigned long order)
370{
371 ULONG rc, size = 0;
372
373 //check if it really is the base of the allocation (see above)
374 addr = GetBaseAddress(addr, (ULONG NEAR *)__Stack32ToFlat(&size));
375
376 if(VMFree((LINEAR)addr)) {
377 DebugInt3();
378 }
379 else {
380#ifdef DEBUG
381 dprintf(("free_pages %x size %d", (ULONG)addr, size));
382#endif
383 ulget_free_pagesMemUsed -= size;
384#ifdef DEBUG
385 dprintf(("free_pages: total alloc size %d", ulget_free_pagesMemUsed));
386#endif
387 }
388//// dprintf(("free_pages %x", addr));
389 return 0;
390}
391//******************************************************************************
392//******************************************************************************
393void *vmalloc(unsigned long size)
394{
395 ULONG addr = 0;
396 ULONG flags = VMDHA_FIXED|VMDHA_CONTIG;
397
398 //round to next page boundary
399 size = size + PAGE_SIZE - 1;
400 size &= 0xFFFFF000;
401
402 if(VMAlloc(size, flags, (LINEAR *)&addr)) {
403 DebugInt3();
404 return 0;
405 }
406 if(addr) {
407#ifdef DEBUG
408 dprintf(("vmalloc %d -> %x (phys %x)", size, addr, virt_to_phys((void *)addr)));
409#endif
410 //only done to save size of memory block
411 AddBaseAddress(addr, addr, size);
412 ulget_free_pagesMemUsed += size;
413#ifdef DEBUG
414 dprintf(("vmalloc: total alloc size %d", ulget_free_pagesMemUsed));
415#endif
416 }
417 return (void *)addr;
418}
419//******************************************************************************
420//******************************************************************************
421void vfree(void *ptr)
422{
423 APIRET rc;
424 ULONG size = 0;
425
426 GetBaseAddress((ULONG)ptr, (ULONG NEAR *)__Stack32ToFlat(&size));
427
428 if(VMFree((LINEAR)ptr)) {
429 DebugInt3();
430 }
431 else {
432#ifdef DEBUG
433 dprintf(("vfree %x size %d", (ULONG)ptr, size));
434#endif
435 ulget_free_pagesMemUsed -= size;
436#ifdef DEBUG
437 dprintf(("vfree: total alloc size %d", ulget_free_pagesMemUsed));
438#endif
439 }
440}
441//******************************************************************************
442//******************************************************************************
443struct page * alloc_pages(int gfp_mask, unsigned long order)
444{
445 DebugInt3();
446 return 0;
447}
448//******************************************************************************
449//******************************************************************************
450int remap_page_range(unsigned long from, unsigned long to, unsigned long size, unsigned long prot)
451{
452 DebugInt3();
453 return 0;
454}
455//******************************************************************************
456//Map physical address (memory mapped io range) to linear
457//******************************************************************************
458void * __ioremap(unsigned long physaddr, unsigned long size, unsigned long flags)
459{
460 ULONG addr = 0, Offset = 0, PhysicalAddress = 0, Length = 0;
461 APIRET rc;
462
463 PhysicalAddress = physaddr;
464 Length = size;
465
466 Offset = PhysicalAddress & (PAGE_SIZE - 1); // within Page
467 Length = (Length + Offset + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
468 PhysicalAddress &= ~(PAGE_SIZE - 1);
469 //dprintf(("ioremap: len %d phys %x off %x", Length, PhysicalAddress, Offset));
470
471 //round to next page boundary
472// size = size + PAGE_SIZE - 1;
473// size &= 0xFFFFF000;
474
475#ifdef KEE
476 SHORT sel;
477
478// rc = KernVMAlloc(size, VMDHA_PHYS, (PVOID*)&addr, (PVOID*)&physaddr, &sel);
479 rc = KernVMAlloc(Length, VMDHA_PHYS, (PVOID*)&addr, (PVOID*)&PhysicalAddress, &sel);
480#else
481 //rc = DevVMAlloc(VMDHA_PHYS, size, (LINEAR)&physaddr, __Stack32ToFlat((ULONG)&addr));
482 rc = DevVMAlloc(VMDHA_PHYS, Length, (LINEAR)&PhysicalAddress, __Stack32ToFlat((ULONG)&addr));
483#endif
484 if (rc != 0) {
485 dprintf(("ioremap error: %x", rc));
486 DebugInt3();
487 return NULL;
488 }
489 return (void *)( addr + Offset) ; //PS
490}
491//******************************************************************************
492//******************************************************************************
493void iounmap(void *addr)
494{
495LINEAR ad;
496
497 ad=(LINEAR)addr;
498 *ad &= ~(0xfff);
499 if(VMFree((LINEAR)ad)) {
500 DebugInt3();
501 }
502}
503//******************************************************************************
504//******************************************************************************
505int is_access_ok(int type, void *addr, unsigned long size)
506{
507 return 1;
508}
509//******************************************************************************
510//******************************************************************************
511void __copy_user(void *to, const void *from, unsigned long n)
512{
513 if(to == NULL || from == NULL) {
514 DebugInt3();
515 return;
516 }
517 if(n == 0) return;
518
519 kmemcpy(to, from, n);
520}
521//******************************************************************************
522//******************************************************************************
523unsigned long copy_to_user(void *to, const void *from, unsigned long n)
524{
525 if(to == NULL || from == NULL) {
526 DebugInt3();
527 return 0;
528 }
529 if(n == 0) return 0;
530
531 kmemcpy(to, from, n);
532 return 0;
533}
534//******************************************************************************
535//******************************************************************************
536void __copy_user_zeroing(void *to, const void *from, unsigned long n)
537{
538 if(to == NULL || from == NULL) {
539 DebugInt3();
540 return;
541 }
542 if(n == 0) return;
543
544 copy_to_user(to, from, n);
545}
546//******************************************************************************
547//******************************************************************************
548unsigned long copy_from_user(void *to, const void *from, unsigned long n)
549{
550 if(to == NULL || from == NULL) {
551 DebugInt3();
552 return 0;
553 }
554 if(n == 0) return 0;
555
556 kmemcpy(to, from, n);
557 return 0;
558}
559//******************************************************************************
560//******************************************************************************
561int __get_user(int size, void *dest, void *src)
562{
563 if(size == 0) return 0;
564
565 if(dest == NULL || src == NULL) {
566 DebugInt3();
567 return 0;
568 }
569 kmemcpy(dest, src, size);
570 return 0;
571}
572//******************************************************************************
573//******************************************************************************
574int _put_user(int size, int x, void *ptr)
575{
576 if(ptr == NULL || size == 0) {
577 DebugInt3();
578 return 0;
579 }
580
581 *(int *)ptr = x;
582 return 0;
583}
584//******************************************************************************
585//******************************************************************************
586#ifdef DEBUGHEAP
587void *__kmalloc(int size, int flags, const char *filename, int lineno)
588#else
589void *__kmalloc(int size, int flags)
590#endif
591{
592 LINEAR addr;
593
594 if(size == 0) {
595 DebugInt3();
596 return NULL;
597 }
598 if(flags & GFP_DMA) {
599 DebugInt3();
600 }
601 if(size >= 4096) {
602 return vmalloc(size);
603 }
604#ifdef DEBUGHEAP
605 addr = (LINEAR)malloc(size, filename, lineno);
606#else
607 addr = (LINEAR)malloc(size);
608#endif
609 if(addr == NULL) {
610 DebugInt3();
611 return 0;
612 }
613//// dprintf(("kmalloc %d returned %x", size, addr));
614 return addr;
615}
616//******************************************************************************
617//******************************************************************************
618#ifdef DEBUGHEAP
619void __kfree(const void *ptr, const char *filename, int lineno)
620#else
621void __kfree(const void *ptr)
622#endif
623{
624 ULONG addr;
625
626 addr = (ULONG)ptr;
627 if(addr == NULL) {
628 DebugInt3();
629 return;
630 }
631//// dprintf(("kfree %x", addr));
632 if(IsHeapAddr(addr)) {
633#ifdef DEBUGHEAP
634 free((void *)addr, filename, lineno);
635#else
636 free((void *)addr);
637#endif
638 }
639 else vfree((PVOID)addr);
640}
641//******************************************************************************
642//******************************************************************************
643
644}
Note: See TracBrowser for help on using the repository browser.