blob: 4cee4016b4ded7a096ffc9689e470331a9fb7078 [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
173// Return maximum address of read/writable "low mem" space.
Kevin O'Connor9c985172012-05-12 23:49:33 -0400174static inline u32 lowmemend(void) {
175 extern u8 code32flat_start[], code32init_end[];
176 u32 end = CONFIG_RELOCATE_INIT ? (u32)code32init_end : (u32)code32flat_start;
177 return end > BUILD_BIOS_ADDR ? BUILD_BIOS_ADDR : end;
178}
179
Kevin O'Connor5e019082012-05-20 21:11:43 -0400180// Return the memory position up to which roms may be located.
181u32
182rom_get_top(void)
183{
184 return ALIGN_DOWN((u32)RomBase->allocend - OPROM_HEADER_RESERVE
185 , OPTION_ROM_ALIGN);
186}
187
188// Return the end of the last deployed rom.
189u32
190rom_get_last(void)
191{
192 return RomEnd;
193}
194
195// Request space for an optionrom in 0xc0000-0xf0000 area.
196struct rom_header *
197rom_reserve(u32 size)
198{
199 u32 newend = ALIGN(RomEnd + size, OPTION_ROM_ALIGN) + OPROM_HEADER_RESERVE;
200 if (newend > (u32)RomBase->allocend)
201 return NULL;
202 if (newend < (u32)_datalow_base + OPROM_HEADER_RESERVE)
203 newend = (u32)_datalow_base + OPROM_HEADER_RESERVE;
204 RomBase->data = RomBase->dataend = (void*)newend;
205 return (void*)RomEnd;
206}
207
208// Confirm space as in use by an optionrom.
209int
210rom_confirm(u32 size)
211{
212 void *new = rom_reserve(size);
213 if (!new) {
214 warn_noalloc();
215 return -1;
216 }
217 RomEnd = ALIGN(RomEnd + size, OPTION_ROM_ALIGN);
218 return 0;
219}
220
221
222/****************************************************************
223 * Setup
224 ****************************************************************/
Kevin O'Connor9c985172012-05-12 23:49:33 -0400225
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400226void
227malloc_setup(void)
228{
229 ASSERT32FLAT();
230 dprintf(3, "malloc setup\n");
231
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400232 // Populate temp high ram
233 u32 highram = 0;
234 int i;
235 for (i=e820_count-1; i>=0; i--) {
236 struct e820entry *en = &e820_list[i];
237 u64 end = en->start + en->size;
238 if (end < 1024*1024)
239 break;
240 if (en->type != E820_RAM || end > 0xffffffff)
241 continue;
242 u32 s = en->start, e = end;
243 if (!highram) {
244 u32 newe = ALIGN_DOWN(e - CONFIG_MAX_HIGHTABLE, MALLOC_MIN_ALIGN);
245 if (newe <= e && newe >= s) {
246 highram = newe;
247 e = newe;
248 }
249 }
250 addSpace(&ZoneTmpHigh, (void*)s, (void*)e);
251 }
252
253 // Populate other regions
254 addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM);
255 addSpace(&ZoneFSeg, BiosTableSpace, &BiosTableSpace[CONFIG_MAX_BIOSTABLE]);
Kevin O'Connor5e019082012-05-20 21:11:43 -0400256 addSpace(&ZoneLow, _datalow_base + OPROM_HEADER_RESERVE, (void*)lowmemend());
257 RomBase = findLast(&ZoneLow);
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400258 if (highram) {
259 addSpace(&ZoneHigh, (void*)highram
260 , (void*)highram + CONFIG_MAX_HIGHTABLE);
261 add_e820(highram, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
262 }
263}
264
Kevin O'Connor533b6282011-07-16 13:13:12 -0400265// Update pointers after code relocation.
266void
267malloc_fixupreloc(void)
268{
269 ASSERT32FLAT();
270 if (!CONFIG_RELOCATE_INIT)
271 return;
272 dprintf(3, "malloc fixup reloc\n");
273
274 int i;
275 for (i=0; i<ARRAY_SIZE(Zones); i++) {
276 struct zone_s *zone = Zones[i];
Kevin O'Connor890d9852012-02-15 20:13:05 -0500277 if (zone->info)
278 zone->info->pprev = &zone->info;
Kevin O'Connor533b6282011-07-16 13:13:12 -0400279 }
Kevin O'Connor8b9137d2011-08-03 20:15:26 -0400280
281 // Add space free'd during relocation in f-segment to ZoneFSeg
282 extern u8 code32init_end[];
283 if ((u32)code32init_end > BUILD_BIOS_ADDR) {
284 memset((void*)BUILD_BIOS_ADDR, 0, (u32)code32init_end - BUILD_BIOS_ADDR);
285 addSpace(&ZoneFSeg, (void*)BUILD_BIOS_ADDR, code32init_end);
286 }
Kevin O'Connor533b6282011-07-16 13:13:12 -0400287}
288
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400289void
290malloc_finalize(void)
291{
Kevin O'Connor1313b782011-07-16 13:39:26 -0400292 ASSERT32FLAT();
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400293 dprintf(3, "malloc finalize\n");
294
Kevin O'Connor9c985172012-05-12 23:49:33 -0400295 // Place an optionrom signature around used low mem area.
296 struct allocinfo_s *info = findLast(&ZoneLow);
Kevin O'Connor5e019082012-05-20 21:11:43 -0400297 u32 base = rom_get_top();
298 struct rom_header *dummyrom = (void*)base;
299 dummyrom->signature = OPTION_ROM_SIGNATURE;
Kevin O'Connor33d51182012-05-23 23:58:11 -0400300 int size = (BUILD_BIOS_ADDR - base) / 512;
301 dummyrom->size = (size > 255) ? 255 : size;
Kevin O'Connor9c985172012-05-12 23:49:33 -0400302 memset((void*)RomEnd, 0, base-RomEnd);
303 dprintf(1, "Space available for UMB: %08x-%08x\n", RomEnd, base);
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400304
305 // Give back unused high ram.
Kevin O'Connor9c985172012-05-12 23:49:33 -0400306 info = findLast(&ZoneHigh);
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400307 if (info) {
308 u32 giveback = ALIGN_DOWN(info->allocend - info->dataend, PAGE_SIZE);
309 add_e820((u32)info->dataend, giveback, E820_RAM);
310 dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback);
311 }
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400312}
313
314
315/****************************************************************
Kevin O'Connor8f4409b2009-11-25 18:51:46 -0500316 * tracked memory allocations
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400317 ****************************************************************/
318
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400319// Allocate memory from the given zone and track it as a PMM allocation
Kevin O'Connorf9a774c2010-04-17 16:58:32 -0400320void * __malloc
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400321pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align)
322{
Kevin O'Connor1313b782011-07-16 13:39:26 -0400323 ASSERT32FLAT();
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400324 if (!size)
325 return NULL;
326
327 // Find and reserve space for bookkeeping.
328 struct allocdetail_s *detail = allocSpace(
329 &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
330 if (!detail) {
331 detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
332 , MALLOC_MIN_ALIGN, NULL);
333 if (!detail)
Kevin O'Connord948e2b2009-10-12 12:54:56 -0400334 return NULL;
335 }
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400336
337 // Find and reserve space for main allocation
Kevin O'Connor9c985172012-05-12 23:49:33 -0400338 void *data = allocSpace(zone, size, align, &detail->datainfo);
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400339 if (!data) {
340 freeSpace(&detail->detailinfo);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400341 return NULL;
342 }
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400343
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400344 dprintf(8, "pmm_malloc zone=%p handle=%x size=%d align=%x"
345 " ret=%p (detail=%p)\n"
346 , zone, handle, size, align
347 , data, detail);
Kevin O'Connor1313b782011-07-16 13:39:26 -0400348 detail->handle = handle;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400349
350 return data;
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400351}
352
353// Free a data block allocated with pmm_malloc
Kevin O'Connord948e2b2009-10-12 12:54:56 -0400354int
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400355pmm_free(void *data)
356{
Kevin O'Connor1313b782011-07-16 13:39:26 -0400357 ASSERT32FLAT();
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400358 struct allocinfo_s *info = findAlloc(data);
Kevin O'Connor1313b782011-07-16 13:39:26 -0400359 if (!info || data == (void*)info || data == info->dataend)
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400360 return -1;
361 struct allocdetail_s *detail = container_of(
362 info, struct allocdetail_s, datainfo);
363 dprintf(8, "pmm_free %p (detail=%p)\n", data, detail);
364 freeSpace(info);
365 freeSpace(&detail->detailinfo);
366 return 0;
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400367}
368
369// Find the amount of free space in a given zone.
370static u32
371pmm_getspace(struct zone_s *zone)
372{
Kevin O'Connorf416fe92009-09-24 20:51:55 -0400373 // XXX - doesn't account for ZoneLow being able to grow.
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400374 // XXX - results not reliable when CONFIG_THREAD_OPTIONROMS
375 u32 maxspace = 0;
376 struct allocinfo_s *info;
Kevin O'Connor1313b782011-07-16 13:39:26 -0400377 for (info = zone->info; info; info = info->next) {
378 u32 space = info->allocend - info->dataend;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400379 if (space > maxspace)
380 maxspace = space;
381 }
382
Kevin O'Connord948e2b2009-10-12 12:54:56 -0400383 if (zone != &ZoneTmpHigh && zone != &ZoneTmpLow)
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400384 return maxspace;
Kevin O'Connord948e2b2009-10-12 12:54:56 -0400385 // Account for space needed for PMM tracking.
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400386 u32 reserve = ALIGN(sizeof(struct allocdetail_s), MALLOC_MIN_ALIGN);
387 if (maxspace <= reserve)
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400388 return 0;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400389 return maxspace - reserve;
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400390}
391
392// Find the data block allocated with pmm_malloc with a given handle.
393static void *
394pmm_find(u32 handle)
395{
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400396 int i;
397 for (i=0; i<ARRAY_SIZE(Zones); i++) {
Kevin O'Connor1313b782011-07-16 13:39:26 -0400398 struct zone_s *zone = Zones[i];
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400399 struct allocinfo_s *info;
Kevin O'Connor1313b782011-07-16 13:39:26 -0400400 for (info = zone->info; info; info = info->next) {
401 if (info->data != (void*)info)
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400402 continue;
403 struct allocdetail_s *detail = container_of(
404 info, struct allocdetail_s, detailinfo);
Kevin O'Connor1313b782011-07-16 13:39:26 -0400405 if (detail->handle == handle)
406 return detail->datainfo.data;
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400407 }
Kevin O'Connor8f4409b2009-11-25 18:51:46 -0500408 }
Kevin O'Connor42a1d4c2010-06-06 11:10:24 -0400409 return NULL;
Kevin O'Connor8f4409b2009-11-25 18:51:46 -0500410}
411
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400412
413/****************************************************************
414 * pmm interface
415 ****************************************************************/
Kevin O'Connore54ee382009-07-26 19:33:13 -0400416
417struct pmmheader {
418 u32 signature;
419 u8 version;
420 u8 length;
421 u8 checksum;
422 u16 entry_offset;
423 u16 entry_seg;
424 u8 reserved[5];
425} PACKED;
426
427extern struct pmmheader PMMHEADER;
428
429#define PMM_SIGNATURE 0x4d4d5024 // $PMM
430
431#if CONFIG_PMM
432struct pmmheader PMMHEADER __aligned(16) VAR16EXPORT = {
433 .version = 0x01,
434 .length = sizeof(PMMHEADER),
435 .entry_seg = SEG_BIOS,
436};
437#endif
438
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400439#define PMM_FUNCTION_NOT_SUPPORTED 0xffffffff
Kevin O'Connore54ee382009-07-26 19:33:13 -0400440
441// PMM - allocate
442static u32
443handle_pmm00(u16 *args)
444{
445 u32 length = *(u32*)&args[1], handle = *(u32*)&args[3];
446 u16 flags = args[5];
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400447 dprintf(3, "pmm00: length=%x handle=%x flags=%x\n"
Kevin O'Connore54ee382009-07-26 19:33:13 -0400448 , length, handle, flags);
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400449 struct zone_s *lowzone = &ZoneTmpLow, *highzone = &ZoneTmpHigh;
450 if (flags & 8) {
451 // Permanent memory request.
452 lowzone = &ZoneLow;
453 highzone = &ZoneHigh;
454 }
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400455 if (!length) {
456 // Memory size request
457 switch (flags & 3) {
458 default:
459 case 0:
460 return 0;
461 case 1:
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400462 return pmm_getspace(lowzone);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400463 case 2:
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400464 return pmm_getspace(highzone);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400465 case 3: {
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400466 u32 spacelow = pmm_getspace(lowzone);
467 u32 spacehigh = pmm_getspace(highzone);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400468 if (spacelow > spacehigh)
469 return spacelow;
470 return spacehigh;
471 }
472 }
473 }
474 u32 size = length * 16;
475 if ((s32)size <= 0)
476 return 0;
477 u32 align = MALLOC_MIN_ALIGN;
478 if (flags & 4) {
479 align = 1<<__ffs(size);
480 if (align < MALLOC_MIN_ALIGN)
481 align = MALLOC_MIN_ALIGN;
482 }
483 switch (flags & 3) {
484 default:
485 case 0:
486 return 0;
487 case 1:
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400488 return (u32)pmm_malloc(lowzone, handle, size, align);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400489 case 2:
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400490 return (u32)pmm_malloc(highzone, handle, size, align);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400491 case 3: {
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400492 void *data = pmm_malloc(lowzone, handle, size, align);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400493 if (data)
494 return (u32)data;
Kevin O'Connor0e9fd612009-08-22 21:31:58 -0400495 return (u32)pmm_malloc(highzone, handle, size, align);
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400496 }
497 }
Kevin O'Connore54ee382009-07-26 19:33:13 -0400498}
499
500// PMM - find
501static u32
502handle_pmm01(u16 *args)
503{
504 u32 handle = *(u32*)&args[1];
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400505 dprintf(3, "pmm01: handle=%x\n", handle);
Kevin O'Connord948e2b2009-10-12 12:54:56 -0400506 if (handle == PMM_DEFAULT_HANDLE)
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400507 return 0;
508 return (u32)pmm_find(handle);
Kevin O'Connore54ee382009-07-26 19:33:13 -0400509}
510
511// PMM - deallocate
512static u32
513handle_pmm02(u16 *args)
514{
515 u32 buffer = *(u32*)&args[1];
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400516 dprintf(3, "pmm02: buffer=%x\n", buffer);
517 int ret = pmm_free((void*)buffer);
518 if (ret)
519 // Error
520 return 1;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400521 return 0;
522}
523
524static u32
525handle_pmmXX(u16 *args)
526{
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400527 return PMM_FUNCTION_NOT_SUPPORTED;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400528}
529
Kevin O'Connor533b6282011-07-16 13:13:12 -0400530u32 VISIBLE32INIT
Kevin O'Connore54ee382009-07-26 19:33:13 -0400531handle_pmm(u16 *args)
532{
Kevin O'Connor1313b782011-07-16 13:39:26 -0400533 ASSERT32FLAT();
Kevin O'Connore54ee382009-07-26 19:33:13 -0400534 if (! CONFIG_PMM)
Kevin O'Connor0bf92702009-08-01 11:45:37 -0400535 return PMM_FUNCTION_NOT_SUPPORTED;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400536
537 u16 arg1 = args[0];
538 dprintf(DEBUG_HDL_pmm, "pmm call arg1=%x\n", arg1);
539
Kevin O'Connor533b6282011-07-16 13:13:12 -0400540 int oldpreempt;
541 if (CONFIG_THREAD_OPTIONROMS) {
542 // Not a preemption event - don't wait in wait_preempt()
543 oldpreempt = CanPreempt;
544 CanPreempt = 0;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400545 }
Kevin O'Connor533b6282011-07-16 13:13:12 -0400546
547 u32 ret;
548 switch (arg1) {
549 case 0x00: ret = handle_pmm00(args); break;
550 case 0x01: ret = handle_pmm01(args); break;
551 case 0x02: ret = handle_pmm02(args); break;
552 default: ret = handle_pmmXX(args); break;
553 }
554
555 if (CONFIG_THREAD_OPTIONROMS)
556 CanPreempt = oldpreempt;
557
558 return ret;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400559}
560
561// romlayout.S
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500562extern void entry_pmm(void);
Kevin O'Connore54ee382009-07-26 19:33:13 -0400563
564void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500565pmm_setup(void)
Kevin O'Connore54ee382009-07-26 19:33:13 -0400566{
567 if (! CONFIG_PMM)
568 return;
569
570 dprintf(3, "init PMM\n");
571
572 PMMHEADER.signature = PMM_SIGNATURE;
573 PMMHEADER.entry_offset = (u32)entry_pmm - BUILD_BIOS_ADDR;
574 PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER));
575}
576
577void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500578pmm_finalize(void)
Kevin O'Connore54ee382009-07-26 19:33:13 -0400579{
580 if (! CONFIG_PMM)
581 return;
582
583 dprintf(3, "finalize PMM\n");
584
585 PMMHEADER.signature = 0;
586 PMMHEADER.entry_offset = 0;
Kevin O'Connore54ee382009-07-26 19:33:13 -0400587}