- Fixed potential memory leaks and use of freed memory.
[AROS.git] / workbench / devs / monitors / IntelGMA / intelG45_memory.c
blobfe7c92557f6c0c990b523d442e0b3a5868fb1bc7
1 /*
2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <exec/memory.h>
7 #include <proto/exec.h>
8 #include <inttypes.h>
9 #include <aros/debug.h>
11 #include "intelG45_intern.h"
12 #include "intelG45_regs.h"
14 static void G45_AttachMemory(struct g45staticdata *sd, intptr_t physical,
15 intptr_t virtual, intptr_t length);
16 static void G45_DetachMemory(struct g45staticdata *sd, intptr_t virtual,
17 intptr_t length);
18 static APTR AllocAlignedMem(IPTR size, UWORD alignment);
19 static VOID FreeAlignedMem(APTR mem);
21 APTR AllocGfxMem(struct g45staticdata *sd, ULONG size)
23 APTR result = NULL;
24 struct MemHeader *header, *next_header, *gap_header = NULL, *tail;
26 header = (APTR)sd->CardMem.mlh_Head;
27 tail = (APTR)&sd->CardMem.mlh_Tail;
29 while (header != tail && result == NULL)
31 Forbid();
32 result = Allocate(header, size);
33 Permit();
35 next_header = (APTR)header->mh_Node.ln_Succ;
36 if (next_header != tail)
38 if (gap_header == NULL
39 && header->mh_Upper != next_header->mh_Lower)
40 gap_header = header;
42 header = next_header;
45 if (result == NULL)
47 /* If a header with a gap after it wasn't found, we use the last one */
48 if (gap_header == NULL)
49 gap_header = (APTR)sd->CardMem.mlh_TailPred;
51 Forbid();
52 /* Choose first 16MB block that isn't represented by an existing
53 * memory header */
54 header = ObtainGfxMemory(sd,
55 gap_header->mh_Upper - (APTR)sd->Card.Framebuffer, 16 * MBYTES,
56 FALSE);
57 if (header != NULL)
59 Insert((APTR)&sd->CardMem, &header->mh_Node,
60 &gap_header->mh_Node);
61 result = Allocate(header, size);
63 Permit();
66 return result;
69 VOID FreeGfxMem(struct g45staticdata *sd, APTR ptr, ULONG size)
71 struct MemHeader *header, *tail;
72 BOOL freed = FALSE;
74 header = (APTR)sd->CardMem.mlh_Head;
75 tail = (APTR)&sd->CardMem.mlh_Tail;
77 while (header != tail && !freed)
79 /* Check if this is the header containing the memory to be freed */
80 if (ptr >= header->mh_Lower && ptr < header->mh_Upper)
82 Forbid();
83 Deallocate(header, ptr, size);
84 Permit();
86 freed = TRUE;
88 /* Unmap memory from graphics chip if it's unused. We don't unmap
89 * the first header because it's the initial BIOS-stolen memory */
90 if (header->mh_Free == header->mh_Upper - header->mh_Lower
91 && (struct MinNode *)header != sd->CardMem.mlh_Head)
93 Remove(&header->mh_Node);
94 ReleaseGfxMemory(sd, header);
98 if (!freed)
99 header = (APTR)header->mh_Node.ln_Succ;
103 intptr_t G45_VirtualToPhysical(struct g45staticdata *sd, intptr_t virtual)
105 intptr_t page = virtual >> 12; /* get page number */
106 intptr_t result = -1;
108 if (page >= 0 && page < sd->Card.GATT_size / 4)
110 uint32_t pte = readl(&sd->Card.GATT[page]);
111 if (pte & 1)
113 result = pte & 0xfffff000;
114 result |= virtual & 0xfff;
118 return result;
121 struct MemHeader *ObtainGfxMemory(struct g45staticdata *sd, intptr_t virtual,
122 intptr_t length, BOOL stolen)
124 BOOL success = TRUE;
125 APTR sys_mem = NULL;
126 struct MemHeader *header = NULL;
127 struct MemChunk *chunk;
129 /* Ensure we don't over-extend graphics memory into scratch area at end
130 * of aperture */
131 if (virtual + length >= sd->ScratchArea)
133 length = sd->ScratchArea - virtual;
134 if (length == 0)
135 success = FALSE;
138 if (success)
140 /* Get memory (aligned to page size) */
141 if (!stolen)
143 sys_mem = AllocAlignedMem(length, 4096);
144 D(bug("[GMA] Got %08x\n", sys_mem));
147 header = AllocVec(sizeof(struct MemHeader), MEMF_CLEAR);
148 if ((sys_mem == NULL && !stolen) || header == NULL)
149 success = FALSE;
152 if (success)
154 D(bug("[GMA] Mapping system memory %08x to graphics virtual %08x "
155 "with size %08x\n", sys_mem, virtual, length));
156 if (!stolen)
158 /* Mirror allocated system memory in graphics memory window */
159 G45_AttachMemory(sd, (IPTR)sys_mem, virtual, length);
162 /* Set up a memory header to allocate from within graphics memory
163 * window */
164 chunk = (struct MemChunk *)(sd->Card.Framebuffer + virtual);
165 chunk->mc_Next = NULL;
166 chunk->mc_Bytes = length;
168 header->mh_Node.ln_Type = NT_MEMORY;
169 header->mh_Node.ln_Name = sys_mem;
170 header->mh_First = chunk;
171 header->mh_Lower = chunk;
172 header->mh_Free = length;
173 header->mh_Upper = (UBYTE *)chunk + length;
176 if (!success)
178 FreeVec(header);
179 FreeAlignedMem(sys_mem);
180 header = NULL;
183 return header;
186 void ReleaseGfxMemory(struct g45staticdata *sd, struct MemHeader *header)
188 D(bug("[GMA] Releasing memory block to system (header=%p)\n", header));
189 D(bug("[GMA] mh_Lower=%p mh_Upper=%p mh_Free=%p\n",
190 header->mh_Lower, header->mh_Upper, header->mh_Free));
192 G45_DetachMemory(sd, (char *)header->mh_Lower - sd->Card.Framebuffer,
193 header->mh_Free);
194 FreeAlignedMem(header->mh_Node.ln_Name);
195 FreeVec(header);
198 static void G45_AttachMemory(struct g45staticdata *sd, intptr_t physical,
199 intptr_t virtual, intptr_t length)
201 intptr_t page = virtual >> 12;
203 if (page > 0)
205 physical &= 0xfffff000;
206 length &= 0xfffff000;
210 writel(physical | 1, &sd->Card.GATT[page]);
212 physical += 4096;
213 length -= 4096;
214 page++;
216 while ((page < sd->Card.GATT_size / 4) && length);
218 CacheClearU();
221 void G45_AttachCacheableMemory(struct g45staticdata *sd, intptr_t physical,
222 intptr_t virtual, intptr_t length)
224 intptr_t page = virtual >> 12;
226 if (page > 0)
228 physical &= 0xfffff000;
229 length &= 0xfffff000;
233 writel(physical | 7, &sd->Card.GATT[page]);
235 physical += 4096;
236 length -= 4096;
237 page++;
239 while ((page < sd->Card.GATT_size / 4) && length);
241 CacheClearU();
244 static void G45_DetachMemory(struct g45staticdata *sd, intptr_t virtual,
245 intptr_t length)
247 intptr_t page = virtual >> 12;
249 if (page >= 0)
253 writel(0, &sd->Card.GATT[page]);
255 length -= 4096;
256 page++;
258 while ((page < sd->Card.GATT_size / 4) && length);
260 CacheClearU();
263 static APTR AllocAlignedMem(IPTR size, UWORD alignment)
265 APTR mem = NULL, original_mem;
267 size += 2 * sizeof(APTR) + alignment;
268 original_mem = AllocMem(size, MEMF_REVERSE);
269 if (original_mem != NULL)
271 mem = (APTR)((IPTR)(original_mem + 2 * sizeof(APTR) + alignment - 1)
272 & ~(alignment - 1));
273 *((APTR *)mem - 1) = original_mem;
274 *((IPTR *)mem - 2) = size;
277 return mem;
280 static VOID FreeAlignedMem(APTR mem)
282 if (mem != NULL)
283 FreeMem(*((APTR *)mem - 1), *((IPTR *)mem - 2));
285 return;