blob: 098b2132e940c03b7059ef98156bb853eabaf899 [file] [log] [blame]
Kevin O'Connore54ee382009-07-26 19:33:13 -04001// Post memory manager (PMM) calls
2//
3// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
4//
5// This file may be distributed under the terms of the GNU LGPLv3 license.
6
7#include "util.h" // checksum
8#include "config.h" // BUILD_BIOS_ADDR
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -04009#include "memmap.h" // struct e820entry
Kevin O'Connor0bf92702009-08-01 11:45:37 -040010#include "farptr.h" // GET_FARVAR
Kevin O'Connorf416fe92009-09-24 20:51:55 -040011#include "biosvar.h" // GET_BDA
Kevin O'Connor9c985172012-05-12 23:49:33 -040012#include "optionroms.h" // OPTION_ROM_ALIGN
Kevin O'Connor0bf92702009-08-01 11:45:37 -040013
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -040014// Information on a reserved area.
15struct allocinfo_s {
16 struct allocinfo_s *next, **pprev;
17 void *data, *dataend, *allocend;
Kevin O'Connor0bf92702009-08-01 11:45:37 -040018};
19
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -040020// Information on a tracked memory allocation.
21struct allocdetail_s {
22 struct allocinfo_s detailinfo;
23 struct allocinfo_s datainfo;
24 u32 handle;
25};
26
27// The various memory zones.
28struct zone_s {
29 struct allocinfo_s *info;
30};
31
Kevin O'Connor1313b782011-07-16 13:39:26 -040032struct zone_s ZoneLow, ZoneHigh, ZoneFSeg, ZoneTmpLow, ZoneTmpHigh;
Kevin O'Connor0bf92702009-08-01 11:45:37 -040033
Kevin O'Connor1313b782011-07-16 13:39:26 -040034static struct zone_s *Zones[] = {
Kevin O'Connor0e9fd612009-08-22 21:31:58 -040035 &ZoneTmpLow, &ZoneLow, &ZoneFSeg, &ZoneTmpHigh, &ZoneHigh
Kevin O'Connor0bf92702009-08-01 11:45:37 -040036};
37
Kevin O'Connorf416fe92009-09-24 20:51:55 -040038
39/****************************************************************
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -040040 * low-level memory reservations
41 ****************************************************************/
42
43// Find and reserve space from a given zone
44static void *
45allocSpace(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill)
46{
47 struct allocinfo_s *info;
Kevin O'Connor1313b782011-07-16 13:39:26 -040048 for (info = zone->info; info; info = info->next) {
49 void *dataend = info->dataend;
50 void *allocend = info->allocend;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -040051 void *newallocend = (void*)ALIGN_DOWN((u32)allocend - size, align);
52 if (newallocend >= dataend && newallocend <= allocend) {
53 // Found space - now reserve it.
Kevin O'Connor1313b782011-07-16 13:39:26 -040054 struct allocinfo_s **pprev = info->pprev;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -040055 if (!fill)
56 fill = newallocend;
Kevin O'Connor1313b782011-07-16 13:39:26 -040057 fill->next = info;
58 fill->pprev = pprev;
59 fill->data = newallocend;
60 fill->dataend = newallocend + size;
61 fill->allocend = allocend;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -040062
Kevin O'Connor1313b782011-07-16 13:39:26 -040063 info->allocend = newallocend;
64 info->pprev = &fill->next;
65 *pprev = fill;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -040066 return newallocend;
67 }
68 }
69 return NULL;
70}
71
72// Release space allocated with allocSpace()
73static void
74freeSpace(struct allocinfo_s *info)
75{
Kevin O'Connor1313b782011-07-16 13:39:26 -040076 struct allocinfo_s *next = info->next;
77 struct allocinfo_s **pprev = info->pprev;
78 *pprev = next;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -040079 if (next) {
Kevin O'Connor1313b782011-07-16 13:39:26 -040080 if (next->allocend == info->data)
81 next->allocend = info->allocend;
82 next->pprev = pprev;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -040083 }
84}
85
86// Add new memory to a zone
87static void
88addSpace(struct zone_s *zone, void *start, void *end)
89{
90 // Find position to add space
91 struct allocinfo_s **pprev = &zone->info, *info;
92 for (;;) {
Kevin O'Connor1313b782011-07-16 13:39:26 -040093 info = *pprev;
94 if (!info || info->data < start)
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -040095 break;
96 pprev = &info->next;
97 }
98
99 // Add space using temporary allocation info.
100 struct allocdetail_s tempdetail;
101 tempdetail.datainfo.next = info;
102 tempdetail.datainfo.pprev = pprev;
103 tempdetail.datainfo.data = tempdetail.datainfo.dataend = start;
104 tempdetail.datainfo.allocend = end;
Kevin O'Connor1313b782011-07-16 13:39:26 -0400105 *pprev = &tempdetail.datainfo;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400106 if (info)
Kevin O'Connor1313b782011-07-16 13:39:26 -0400107 info->pprev = &tempdetail.datainfo.next;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400108
109 // Allocate final allocation info.
110 struct allocdetail_s *detail = allocSpace(
111 &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
112 if (!detail) {
113 detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
114 , MALLOC_MIN_ALIGN, NULL);
115 if (!detail) {
Kevin O'Connor1313b782011-07-16 13:39:26 -0400116 *tempdetail.datainfo.pprev = tempdetail.datainfo.next;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400117 if (tempdetail.datainfo.next)
Kevin O'Connor1313b782011-07-16 13:39:26 -0400118 tempdetail.datainfo.next->pprev = tempdetail.datainfo.pprev;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400119 warn_noalloc();
120 return;
121 }
122 }
123
124 // Replace temp alloc space with final alloc space
Kevin O'Connor1313b782011-07-16 13:39:26 -0400125 memcpy(&detail->datainfo, &tempdetail.datainfo, sizeof(detail->datainfo));
126 detail->handle = PMM_DEFAULT_HANDLE;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400127
Kevin O'Connor1313b782011-07-16 13:39:26 -0400128 *tempdetail.datainfo.pprev = &detail->datainfo;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400129 if (tempdetail.datainfo.next)
Kevin O'Connor1313b782011-07-16 13:39:26 -0400130 tempdetail.datainfo.next->pprev = &detail->datainfo.next;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400131}
132
133// Search all zones for an allocation obtained from allocSpace()
134static struct allocinfo_s *
135findAlloc(void *data)
136{
137 int i;
138 for (i=0; i<ARRAY_SIZE(Zones); i++) {
Kevin O'Connor1313b782011-07-16 13:39:26 -0400139 struct zone_s *zone = Zones[i];
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400140 struct allocinfo_s *info;
Kevin O'Connor1313b782011-07-16 13:39:26 -0400141 for (info = zone->info; info; info = info->next)
142 if (info->data == data)
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400143 return info;
144 }
145 return NULL;
146}
147
148// Return the last sentinal node of a zone
149static struct allocinfo_s *
150findLast(struct zone_s *zone)
151{
Kevin O'Connor1313b782011-07-16 13:39:26 -0400152 struct allocinfo_s *info = zone->info;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400153 if (!info)
154 return NULL;
155 for (;;) {
Kevin O'Connor1313b782011-07-16 13:39:26 -0400156 struct allocinfo_s *next = info->next;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400157 if (!next)
158 return info;
159 info = next;
160 }
161}
162
163
164/****************************************************************
Kevin O'Connor5e019082012-05-20 21:11:43 -0400165 * 0xc0000-0xf0000 management
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400166 ****************************************************************/
167
Kevin O'Connor5e019082012-05-20 21:11:43 -0400168static u32 RomEnd = BUILD_ROM_START;
169static struct allocinfo_s *RomBase;
170
171#define OPROM_HEADER_RESERVE 16
172
Kevin O'Connor5e019082012-05-20 21:11:43 -0400173// Return the memory position up to which roms may be located.
174u32
175rom_get_top(void)
176{
177 return ALIGN_DOWN((u32)RomBase->allocend - OPROM_HEADER_RESERVE
178 , OPTION_ROM_ALIGN);
179}
180
181// Return the end of the last deployed rom.
182u32
183rom_get_last(void)
184{
185 return RomEnd;
186}
187
188// Request space for an optionrom in 0xc0000-0xf0000 area.
189struct rom_header *
190rom_reserve(u32 size)
191{
192 u32 newend = ALIGN(RomEnd + size, OPTION_ROM_ALIGN) + OPROM_HEADER_RESERVE;
193 if (newend > (u32)RomBase->allocend)
194 return NULL;
Kevin O'Connorc91da7a2012-06-08 21:14:19 -0400195 if (newend < (u32)datalow_base + OPROM_HEADER_RESERVE)
196 newend = (u32)datalow_base + OPROM_HEADER_RESERVE;
Kevin O'Connor5e019082012-05-20 21:11:43 -0400197 RomBase->data = RomBase->dataend = (void*)newend;
198 return (void*)RomEnd;
199}
200
201// Confirm space as in use by an optionrom.
202int
203rom_confirm(u32 size)
204{
205 void *new = rom_reserve(size);
206 if (!new) {
207 warn_noalloc();
208 return -1;
209 }
210 RomEnd = ALIGN(RomEnd + size, OPTION_ROM_ALIGN);
211 return 0;
212}
213
214
215/****************************************************************
216 * Setup
217 ****************************************************************/
Kevin O'Connor9c985172012-05-12 23:49:33 -0400218
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400219void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500220malloc_preinit(void)
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400221{
222 ASSERT32FLAT();
223 dprintf(3, "malloc setup\n");
224
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400225 // Populate temp high ram
226 u32 highram = 0;
227 int i;
228 for (i=e820_count-1; i>=0; i--) {
229 struct e820entry *en = &e820_list[i];
230 u64 end = en->start + en->size;
231 if (end < 1024*1024)
232 break;
233 if (en->type != E820_RAM || end > 0xffffffff)
234 continue;
235 u32 s = en->start, e = end;
236 if (!highram) {
237 u32 newe = ALIGN_DOWN(e - CONFIG_MAX_HIGHTABLE, MALLOC_MIN_ALIGN);
238 if (newe <= e && newe >= s) {
239 highram = newe;
240 e = newe;
241 }
242 }
243 addSpace(&ZoneTmpHigh, (void*)s, (void*)e);
244 }
245
246 // Populate other regions
247 addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM);
248 addSpace(&ZoneFSeg, BiosTableSpace, &BiosTableSpace[CONFIG_MAX_BIOSTABLE]);
Kevin O'Connorc91da7a2012-06-08 21:14:19 -0400249 extern u8 final_datalow_start[];
250 addSpace(&ZoneLow, datalow_base + OPROM_HEADER_RESERVE, final_datalow_start);
Kevin O'Connor5e019082012-05-20 21:11:43 -0400251 RomBase = findLast(&ZoneLow);
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400252 if (highram) {
253 addSpace(&ZoneHigh, (void*)highram
254 , (void*)highram + CONFIG_MAX_HIGHTABLE);
255 add_e820(highram, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
256 }
257}
258
Kevin O'Connor533b6282011-07-16 13:13:12 -0400259// Update pointers after code relocation.
260void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500261malloc_fixupreloc_init(void)
Kevin O'Connor533b6282011-07-16 13:13:12 -0400262{
263 ASSERT32FLAT();
264 if (!CONFIG_RELOCATE_INIT)
265 return;
266 dprintf(3, "malloc fixup reloc\n");
267
268 int i;
269 for (i=0; i<ARRAY_SIZE(Zones); i++) {
270 struct zone_s *zone = Zones[i];
Kevin O'Connor890d9852012-02-15 20:13:05 -0500271 if (zone->info)
272 zone->info->pprev = &zone->info;
Kevin O'Connor533b6282011-07-16 13:13:12 -0400273 }
Kevin O'Connor8b9137d2011-08-03 20:15:26 -0400274
275 // Add space free'd during relocation in f-segment to ZoneFSeg
276 extern u8 code32init_end[];
277 if ((u32)code32init_end > BUILD_BIOS_ADDR) {
278 memset((void*)BUILD_BIOS_ADDR, 0, (u32)code32init_end - BUILD_BIOS_ADDR);
279 addSpace(&ZoneFSeg, (void*)BUILD_BIOS_ADDR, code32init_end);
280 }
Kevin O'Connor533b6282011-07-16 13:13:12 -0400281}
282
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400283void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500284malloc_prepboot(void)
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400285{
Kevin O'Connor1313b782011-07-16 13:39:26 -0400286 ASSERT32FLAT();
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400287 dprintf(3, "malloc finalize\n");
288
Kevin O'Connor9c985172012-05-12 23:49:33 -0400289 // Place an optionrom signature around used low mem area.
Kevin O'Connor5e019082012-05-20 21:11:43 -0400290 u32 base = rom_get_top();
291 struct rom_header *dummyrom = (void*)base;
292 dummyrom->signature = OPTION_ROM_SIGNATURE;
Kevin O'Connor33d51182012-05-23 23:58:11 -0400293 int size = (BUILD_BIOS_ADDR - base) / 512;
294 dummyrom->size = (size > 255) ? 255 : size;
Kevin O'Connor9c985172012-05-12 23:49:33 -0400295 memset((void*)RomEnd, 0, base-RomEnd);
296 dprintf(1, "Space available for UMB: %08x-%08x\n", RomEnd, base);
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400297
Kevin O'Connor65802ad2012-07-21 11:56:09 -0400298 // Clear unused f-seg ram.
299 struct allocinfo_s *info = findLast(&ZoneFSeg);
300 memset(info->dataend, 0, info->allocend - info->dataend);
301
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400302 // Give back unused high ram.
Kevin O'Connor9c985172012-05-12 23:49:33 -0400303 info = findLast(&ZoneHigh);
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400304 if (info) {
305 u32 giveback = ALIGN_DOWN(info->allocend - info->dataend, PAGE_SIZE);
306 add_e820((u32)info->dataend, giveback, E820_RAM);
307 dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback);
308 }
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400309}
310
311
312/****************************************************************
Kevin O'Connor8f4409b2009-11-25 18:51:46 -0500313 * tracked memory allocations
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400314 ****************************************************************/
315
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400316// Allocate memory from the given zone and track it as a PMM allocation
Kevin O'Connorf9a774c2010-04-17 16:58:32 -0400317void * __malloc
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400318pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align)
319{
Kevin O'Connor1313b782011-07-16 13:39:26 -0400320 ASSERT32FLAT();
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400321 if (!size)
322 return NULL;
323
324 // Find and reserve space for bookkeeping.
325 struct allocdetail_s *detail = allocSpace(
326 &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
327 if (!detail) {
328 detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
329 , MALLOC_MIN_ALIGN, NULL);
330 if (!detail)
Kevin O'Connord948e2b2009-10-12 12:54:56 -0400331 return NULL;
332 }
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400333
334 // Find and reserve space for main allocation
Kevin O'Connor9c985172012-05-12 23:49:33 -0400335 void *data = allocSpace(zone, size, align, &detail->datainfo);
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400336 if (!data) {
337 freeSpace(&detail->detailinfo);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400338 return NULL;
339 }
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400340
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400341 dprintf(8, "pmm_malloc zone=%p handle=%x size=%d align=%x"
342 " ret=%p (detail=%p)\n"
343 , zone, handle, size, align
344 , data, detail);
Kevin O'Connor1313b782011-07-16 13:39:26 -0400345 detail->handle = handle;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400346
347 return data;
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400348}
349
350// Free a data block allocated with pmm_malloc
Kevin O'Connord948e2b2009-10-12 12:54:56 -0400351int
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400352pmm_free(void *data)
353{
Kevin O'Connor1313b782011-07-16 13:39:26 -0400354 ASSERT32FLAT();
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400355 struct allocinfo_s *info = findAlloc(data);
Kevin O'Connor1313b782011-07-16 13:39:26 -0400356 if (!info || data == (void*)info || data == info->dataend)
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400357 return -1;
358 struct allocdetail_s *detail = container_of(
359 info, struct allocdetail_s, datainfo);
360 dprintf(8, "pmm_free %p (detail=%p)\n", data, detail);
361 freeSpace(info);
362 freeSpace(&detail->detailinfo);
363 return 0;
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400364}
365
366// Find the amount of free space in a given zone.
367static u32
368pmm_getspace(struct zone_s *zone)
369{
Kevin O'Connorf416fe92009-09-24 20:51:55 -0400370 // XXX - doesn't account for ZoneLow being able to grow.
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400371 // XXX - results not reliable when CONFIG_THREAD_OPTIONROMS
372 u32 maxspace = 0;
373 struct allocinfo_s *info;
Kevin O'Connor1313b782011-07-16 13:39:26 -0400374 for (info = zone->info; info; info = info->next) {
375 u32 space = info->allocend - info->dataend;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400376 if (space > maxspace)
377 maxspace = space;
378 }
379
Kevin O'Connord948e2b2009-10-12 12:54:56 -0400380 if (zone != &ZoneTmpHigh && zone != &ZoneTmpLow)
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400381 return maxspace;
Kevin O'Connord948e2b2009-10-12 12:54:56 -0400382 // Account for space needed for PMM tracking.
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400383 u32 reserve = ALIGN(sizeof(struct allocdetail_s), MALLOC_MIN_ALIGN);
384 if (maxspace <= reserve)
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400385 return 0;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400386 return maxspace - reserve;
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400387}
388
389// Find the data block allocated with pmm_malloc with a given handle.
390static void *
391pmm_find(u32 handle)
392{
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400393 int i;
394 for (i=0; i<ARRAY_SIZE(Zones); i++) {
Kevin O'Connor1313b782011-07-16 13:39:26 -0400395 struct zone_s *zone = Zones[i];
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400396 struct allocinfo_s *info;
Kevin O'Connor1313b782011-07-16 13:39:26 -0400397 for (info = zone->info; info; info = info->next) {
398 if (info->data != (void*)info)
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400399 continue;
400 struct allocdetail_s *detail = container_of(
401 info, struct allocdetail_s, detailinfo);
Kevin O'Connor1313b782011-07-16 13:39:26 -0400402 if (detail->handle == handle)
403 return detail->datainfo.data;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400404 }
Kevin O'Connor8f4409b2009-11-25 18:51:46 -0500405 }
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400406 return NULL;
Kevin O'Connor8f4409b2009-11-25 18:51:46 -0500407}
408
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400409
410/****************************************************************
411 * pmm interface
412 ****************************************************************/
Kevin O'Connore54ee382009-07-26 19:33:13 -0400413
414struct pmmheader {
415 u32 signature;
416 u8 version;
417 u8 length;
418 u8 checksum;
Kevin O'Connor6156afe2013-01-20 10:43:54 -0500419 struct segoff_s entry;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400420 u8 reserved[5];
421} PACKED;
422
423extern struct pmmheader PMMHEADER;
424
425#define PMM_SIGNATURE 0x4d4d5024 // $PMM
426
427#if CONFIG_PMM
428struct pmmheader PMMHEADER __aligned(16) VAR16EXPORT = {
Kevin O'Connor6156afe2013-01-20 10:43:54 -0500429 .signature = PMM_SIGNATURE,
Kevin O'Connore54ee382009-07-26 19:33:13 -0400430 .version = 0x01,
431 .length = sizeof(PMMHEADER),
Kevin O'Connore54ee382009-07-26 19:33:13 -0400432};
433#endif
434
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400435#define PMM_FUNCTION_NOT_SUPPORTED 0xffffffff
Kevin O'Connore54ee382009-07-26 19:33:13 -0400436
437// PMM - allocate
438static u32
439handle_pmm00(u16 *args)
440{
441 u32 length = *(u32*)&args[1], handle = *(u32*)&args[3];
442 u16 flags = args[5];
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400443 dprintf(3, "pmm00: length=%x handle=%x flags=%x\n"
Kevin O'Connore54ee382009-07-26 19:33:13 -0400444 , length, handle, flags);
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400445 struct zone_s *lowzone = &ZoneTmpLow, *highzone = &ZoneTmpHigh;
446 if (flags & 8) {
447 // Permanent memory request.
448 lowzone = &ZoneLow;
449 highzone = &ZoneHigh;
450 }
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400451 if (!length) {
452 // Memory size request
453 switch (flags & 3) {
454 default:
455 case 0:
456 return 0;
457 case 1:
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400458 return pmm_getspace(lowzone);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400459 case 2:
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400460 return pmm_getspace(highzone);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400461 case 3: {
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400462 u32 spacelow = pmm_getspace(lowzone);
463 u32 spacehigh = pmm_getspace(highzone);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400464 if (spacelow > spacehigh)
465 return spacelow;
466 return spacehigh;
467 }
468 }
469 }
470 u32 size = length * 16;
471 if ((s32)size <= 0)
472 return 0;
473 u32 align = MALLOC_MIN_ALIGN;
474 if (flags & 4) {
475 align = 1<<__ffs(size);
476 if (align < MALLOC_MIN_ALIGN)
477 align = MALLOC_MIN_ALIGN;
478 }
479 switch (flags & 3) {
480 default:
481 case 0:
482 return 0;
483 case 1:
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400484 return (u32)pmm_malloc(lowzone, handle, size, align);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400485 case 2:
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400486 return (u32)pmm_malloc(highzone, handle, size, align);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400487 case 3: {
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400488 void *data = pmm_malloc(lowzone, handle, size, align);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400489 if (data)
490 return (u32)data;
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400491 return (u32)pmm_malloc(highzone, handle, size, align);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400492 }
493 }
Kevin O'Connore54ee382009-07-26 19:33:13 -0400494}
495
496// PMM - find
497static u32
498handle_pmm01(u16 *args)
499{
500 u32 handle = *(u32*)&args[1];
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400501 dprintf(3, "pmm01: handle=%x\n", handle);
Kevin O'Connord948e2b2009-10-12 12:54:56 -0400502 if (handle == PMM_DEFAULT_HANDLE)
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400503 return 0;
504 return (u32)pmm_find(handle);
Kevin O'Connore54ee382009-07-26 19:33:13 -0400505}
506
507// PMM - deallocate
508static u32
509handle_pmm02(u16 *args)
510{
511 u32 buffer = *(u32*)&args[1];
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400512 dprintf(3, "pmm02: buffer=%x\n", buffer);
513 int ret = pmm_free((void*)buffer);
514 if (ret)
515 // Error
516 return 1;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400517 return 0;
518}
519
520static u32
521handle_pmmXX(u16 *args)
522{
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400523 return PMM_FUNCTION_NOT_SUPPORTED;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400524}
525
Kevin O'Connor533b6282011-07-16 13:13:12 -0400526u32 VISIBLE32INIT
Kevin O'Connore54ee382009-07-26 19:33:13 -0400527handle_pmm(u16 *args)
528{
Kevin O'Connor1313b782011-07-16 13:39:26 -0400529 ASSERT32FLAT();
Kevin O'Connore54ee382009-07-26 19:33:13 -0400530 if (! CONFIG_PMM)
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400531 return PMM_FUNCTION_NOT_SUPPORTED;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400532
533 u16 arg1 = args[0];
534 dprintf(DEBUG_HDL_pmm, "pmm call arg1=%x\n", arg1);
535
Kevin O'Connor533b6282011-07-16 13:13:12 -0400536 u32 ret;
537 switch (arg1) {
538 case 0x00: ret = handle_pmm00(args); break;
539 case 0x01: ret = handle_pmm01(args); break;
540 case 0x02: ret = handle_pmm02(args); break;
541 default: ret = handle_pmmXX(args); break;
542 }
543
Kevin O'Connor533b6282011-07-16 13:13:12 -0400544 return ret;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400545}
546
Kevin O'Connore54ee382009-07-26 19:33:13 -0400547void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500548pmm_init(void)
Kevin O'Connore54ee382009-07-26 19:33:13 -0400549{
550 if (! CONFIG_PMM)
551 return;
552
553 dprintf(3, "init PMM\n");
554
Kevin O'Connor6156afe2013-01-20 10:43:54 -0500555 PMMHEADER.entry = FUNC16(entry_pmm);
Kevin O'Connore54ee382009-07-26 19:33:13 -0400556 PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER));
557}
558
559void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500560pmm_prepboot(void)
Kevin O'Connore54ee382009-07-26 19:33:13 -0400561{
562 if (! CONFIG_PMM)
563 return;
564
565 dprintf(3, "finalize PMM\n");
566
567 PMMHEADER.signature = 0;
Kevin O'Connor6156afe2013-01-20 10:43:54 -0500568 PMMHEADER.entry.segoff = 0;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400569}