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

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

Added quirk for Gateway 2000 ICH2/AD1885

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