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

Last change on this file since 76 was 76, checked in by vladest, 19 years ago

Latest ALSA patches
HDA patches
Patch for Intel from Rudy's
Fixes locks on NM256 chipsets
Fixes PM on Maestro3 chipsets

File size: 19.0 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"), size);
199 else dprintf(("allocated %X in LOW memory"), 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, trying wasteful method instead"));
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);
502 if(VMFree((LINEAR)ad)) {
503 DebugInt3();
504 }
505}
506//******************************************************************************
507//******************************************************************************
508int is_access_ok(int type, void *addr, unsigned long size)
509{
510 return 1;
511}
512//******************************************************************************
513//******************************************************************************
514void __copy_user(void *to, const void *from, unsigned long n)
515{
516 if(to == NULL || from == NULL) {
517 DebugInt3();
518 return;
519 }
520 if(n == 0) return;
521
522 kmemcpy(to, from, n);
523}
524//******************************************************************************
525//******************************************************************************
526unsigned long copy_to_user(void *to, const void *from, unsigned long n)
527{
528 if(to == NULL || from == NULL) {
529 DebugInt3();
530 return 0;
531 }
532 if(n == 0) return 0;
533
534 kmemcpy(to, from, n);
535 return 0;
536}
537//******************************************************************************
538//******************************************************************************
539void __copy_user_zeroing(void *to, const void *from, unsigned long n)
540{
541 if(to == NULL || from == NULL) {
542 DebugInt3();
543 return;
544 }
545 if(n == 0) return;
546
547 copy_to_user(to, from, n);
548}
549//******************************************************************************
550//******************************************************************************
551unsigned long copy_from_user(void *to, const void *from, unsigned long n)
552{
553 if(to == NULL || from == NULL) {
554 DebugInt3();
555 return 0;
556 }
557 if(n == 0) return 0;
558
559 kmemcpy(to, from, n);
560 return 0;
561}
562//******************************************************************************
563//******************************************************************************
564int __get_user(int size, void *dest, void *src)
565{
566 if(size == 0) return 0;
567
568 if(dest == NULL || src == NULL) {
569 DebugInt3();
570 return 0;
571 }
572 kmemcpy(dest, src, size);
573 return 0;
574}
575//******************************************************************************
576//******************************************************************************
577int _put_user(int size, int x, void *ptr)
578{
579 if(ptr == NULL || size == 0) {
580 DebugInt3();
581 return 0;
582 }
583
584 *(int *)ptr = x;
585 return 0;
586}
587//******************************************************************************
588//******************************************************************************
589#ifdef DEBUGHEAP
590void *__kmalloc(int size, int flags, const char *filename, int lineno)
591#else
592void *__kmalloc(int size, int flags)
593#endif
594{
595 LINEAR addr;
596
597 if(size == 0) {
598 DebugInt3();
599 return NULL;
600 }
601 if(flags & GFP_DMA) {
602 DebugInt3();
603 }
604 if(size >= 4096) {
605 return vmalloc(size);
606 }
607#ifdef DEBUGHEAP
608 addr = (LINEAR)malloc(size, filename, lineno);
609#else
610 addr = (LINEAR)malloc(size);
611#endif
612 if(addr == NULL) {
613 DebugInt3();
614 return 0;
615 }
616//// dprintf(("kmalloc %d returned %x", size, addr));
617 return addr;
618}
619//******************************************************************************
620//******************************************************************************
621#ifdef DEBUGHEAP
622void __kfree(const void *ptr, const char *filename, int lineno)
623#else
624void __kfree(const void *ptr)
625#endif
626{
627 ULONG addr;
628
629 addr = (ULONG)ptr;
630 if(addr == NULL) {
631 DebugInt3();
632 return;
633 }
634//// dprintf(("kfree %x", addr));
635 if(IsHeapAddr(addr)) {
636#ifdef DEBUGHEAP
637 free((void *)addr, filename, lineno);
638#else
639 free((void *)addr);
640#endif
641 }
642 else vfree((PVOID)addr);
643}
644//******************************************************************************
645//******************************************************************************
646
647}
Note: See TracBrowser for help on using the repository browser.