Stefan Reinauer | 38cd29e | 2009-08-11 21:28:25 +0000 | [diff] [blame] | 1 | /**************************************************************************** |
| 2 | * YABEL BIOS Emulator |
| 3 | * |
| 4 | * This program and the accompanying materials |
| 5 | * are made available under the terms of the BSD License |
| 6 | * which accompanies this distribution, and is available at |
| 7 | * http://www.opensource.org/licenses/bsd-license.php |
| 8 | * |
| 9 | * Copyright (c) 2008 Pattrick Hueper <phueper@hueper.net> |
| 10 | ****************************************************************************/ |
| 11 | |
| 12 | #include <x86emu/x86emu.h> |
Stefan Reinauer | 38cd29e | 2009-08-11 21:28:25 +0000 | [diff] [blame] | 13 | #include "../x86emu/prim_ops.h" |
Stefan Reinauer | 38cd29e | 2009-08-11 21:28:25 +0000 | [diff] [blame] | 14 | #include <string.h> |
| 15 | |
| 16 | #include "biosemu.h" |
| 17 | #include "pmm.h" |
| 18 | #include "debug.h" |
| 19 | #include "device.h" |
| 20 | |
| 21 | /* this struct is used to remember which PMM spaces |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 22 | * have been assigned. MAX_PMM_AREAS defines how many |
| 23 | * PMM areas we can assign. |
Stefan Reinauer | 38cd29e | 2009-08-11 21:28:25 +0000 | [diff] [blame] | 24 | * All areas are assigned in PMM_CONV_SEGMENT |
| 25 | */ |
| 26 | typedef struct { |
| 27 | u32 handle; /* handle that is returned to PMM caller */ |
| 28 | u32 offset; /* in PMM_CONV_SEGMENT */ |
| 29 | u32 length; /* length of this area */ |
| 30 | } pmm_allocation_t; |
| 31 | |
| 32 | #define MAX_PMM_AREAS 10 |
| 33 | |
| 34 | /* array to store the above structs */ |
| 35 | static pmm_allocation_t pmm_allocation_array[MAX_PMM_AREAS]; |
| 36 | |
| 37 | /* index into pmm_allocation_array */ |
| 38 | static u32 curr_pmm_allocation_index = 0; |
| 39 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 40 | /* This function is used to setup the PMM struct in virtual memory |
Stefan Reinauer | 38cd29e | 2009-08-11 21:28:25 +0000 | [diff] [blame] | 41 | * at a certain offset, the length of the PMM struct is returned */ |
| 42 | u8 pmm_setup(u16 segment, u16 offset) |
| 43 | { |
| 44 | /* setup the PMM structure */ |
| 45 | pmm_information_t *pis = |
| 46 | (pmm_information_t *) (M.mem_base + (((u32) segment) << 4) + |
| 47 | offset); |
| 48 | memset(pis, 0, sizeof(pmm_information_t)); |
| 49 | /* set signature to $PMM */ |
| 50 | pis->signature[0] = '$'; |
| 51 | pis->signature[1] = 'P'; |
| 52 | pis->signature[2] = 'M'; |
| 53 | pis->signature[3] = 'M'; |
| 54 | /* revision as specified */ |
| 55 | pis->struct_rev = 0x01; |
| 56 | /* internal length, excluding code */ |
| 57 | pis->length = ((void *)&(pis->code) - (void *)&(pis->signature)); |
| 58 | /* the code to be executed, pointed to by entry_point_offset */ |
| 59 | pis->code[0] = 0xCD; /* INT */ |
| 60 | pis->code[1] = PMM_INT_NUM; /* my selfdefined PMM INT number */ |
| 61 | pis->code[2] = 0xCB; /* RETF */ |
| 62 | /* set the entry_point_offset, it should point to pis->code, segment is the segment of |
| 63 | * this struct. Since pis->length is the length of the struct excluding code, offset+pis->length |
| 64 | * points to the code... it's that simple ;-) |
| 65 | */ |
| 66 | out32le(&(pis->entry_point_offset), |
| 67 | (u32) segment << 16 | (u32) (offset + pis->length)); |
| 68 | /* checksum calculation */ |
| 69 | u8 i; |
| 70 | u8 checksum = 0; |
| 71 | for (i = 0; i < pis->length; i++) { |
| 72 | checksum += *(((u8 *) pis) + i); |
| 73 | } |
| 74 | pis->checksum = ((u8) 0) - checksum; |
| 75 | CHECK_DBG(DEBUG_PMM) { |
| 76 | DEBUG_PRINTF_PMM("PMM Structure:\n"); |
| 77 | dump((void *)pis, sizeof(pmm_information_t)); |
| 78 | } |
| 79 | return sizeof(pmm_information_t); |
| 80 | } |
| 81 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 82 | /* handle the selfdefined interrupt, this is executed, when the PMM Entry Point |
Stefan Reinauer | 38cd29e | 2009-08-11 21:28:25 +0000 | [diff] [blame] | 83 | * is executed, it must handle all PMM requests |
| 84 | */ |
| 85 | void pmm_handleInt() |
| 86 | { |
| 87 | u32 rval = 0; |
| 88 | u16 function, flags; |
| 89 | u32 handle, length; |
| 90 | u32 i, j; |
| 91 | u32 buffer; |
| 92 | /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
| 93 | * according to the PMM Spec "the flags and all registers, except DX and AX |
| 94 | * are preserved across calls to PMM" |
| 95 | * so we save M.x86 and in :exit label we restore it, however, this means that no |
| 96 | * returns must be used in this function, any exit must use goto exit! |
| 97 | * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
| 98 | */ |
| 99 | X86EMU_regs backup_regs = M.x86; |
| 100 | pop_long(); /* pop the return address, this is already saved in INT handler, we don't need |
| 101 | to remember this. */ |
| 102 | function = pop_word(); |
| 103 | switch (function) { |
| 104 | case 0: |
| 105 | /* function pmmAllocate */ |
| 106 | length = pop_long(); |
| 107 | length *= 16; /* length is passed in "paragraphs" of 16 bytes each */ |
| 108 | handle = pop_long(); |
| 109 | flags = pop_word(); |
| 110 | DEBUG_PRINTF_PMM |
| 111 | ("%s: pmmAllocate: Length: %x, Handle: %x, Flags: %x\n", |
| 112 | __func__, length, handle, flags); |
| 113 | if ((flags & 0x1) != 0) { |
| 114 | /* request to allocate in conventional memory */ |
| 115 | if (curr_pmm_allocation_index >= MAX_PMM_AREAS) { |
| 116 | printf |
| 117 | ("%s: pmmAllocate: Maximum Number of allocatable areas reached (%d), cannot allocate more memory!\n", |
| 118 | __func__, MAX_PMM_AREAS); |
| 119 | rval = 0; |
| 120 | goto exit; |
| 121 | } |
| 122 | /* some ROMs seem to be confused by offset 0, so lets start at 0x100 */ |
| 123 | u32 next_offset = 0x100; |
| 124 | pmm_allocation_t *pmm_alloc = |
| 125 | &(pmm_allocation_array[curr_pmm_allocation_index]); |
| 126 | if (curr_pmm_allocation_index != 0) { |
| 127 | /* we have already allocated... get the new next_offset |
| 128 | * from the previous pmm_allocation_t */ |
| 129 | next_offset = |
| 130 | pmm_allocation_array |
| 131 | [curr_pmm_allocation_index - 1].offset + |
| 132 | pmm_allocation_array |
| 133 | [curr_pmm_allocation_index - 1].length; |
| 134 | } |
| 135 | DEBUG_PRINTF_PMM("%s: next_offset: 0x%x\n", |
| 136 | __func__, next_offset); |
| 137 | if (length == 0) { |
| 138 | /* largest possible block size requested, we have on segment |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 139 | * to allocate, so largest possible is segment size (0xFFFF) |
Stefan Reinauer | 38cd29e | 2009-08-11 21:28:25 +0000 | [diff] [blame] | 140 | * minus next_offset |
| 141 | */ |
| 142 | rval = 0xFFFF - next_offset; |
| 143 | goto exit; |
| 144 | } |
| 145 | u32 align = 0; |
| 146 | if (((flags & 0x4) != 0) && (length > 0)) { |
| 147 | /* align to least significant bit set in length param */ |
| 148 | u8 lsb = 0; |
| 149 | while (((length >> lsb) & 0x1) == 0) { |
| 150 | lsb++; |
| 151 | } |
| 152 | align = 1 << lsb; |
| 153 | } |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 154 | /* always align at least to paragraph (16byte) boundary |
Stefan Reinauer | 38cd29e | 2009-08-11 21:28:25 +0000 | [diff] [blame] | 155 | * hm... since the length is always in paragraphs, we cannot |
| 156 | * align outside of paragraphs anyway... so this check might |
| 157 | * be unnecessary...*/ |
| 158 | if (align < 0x10) { |
| 159 | align = 0x10; |
| 160 | } |
| 161 | DEBUG_PRINTF_PMM("%s: align: 0x%x\n", __func__, |
| 162 | align); |
| 163 | if ((next_offset & (align - 1)) != 0) { |
| 164 | /* not yet aligned... align! */ |
| 165 | next_offset += align; |
| 166 | next_offset &= ~(align - 1); |
| 167 | } |
| 168 | if ((next_offset + length) > 0xFFFF) { |
| 169 | rval = 0; |
| 170 | printf |
| 171 | ("%s: pmmAllocate: Not enough memory available for allocation!\n", |
| 172 | __func__); |
| 173 | goto exit; |
| 174 | } |
| 175 | curr_pmm_allocation_index++; |
| 176 | /* remember the values in pmm_allocation_array */ |
| 177 | pmm_alloc->handle = handle; |
| 178 | pmm_alloc->offset = next_offset; |
| 179 | pmm_alloc->length = length; |
| 180 | /* return the 32bit "physical" address, i.e. combination of segment and offset */ |
| 181 | rval = ((u32) (PMM_CONV_SEGMENT << 16)) | next_offset; |
| 182 | DEBUG_PRINTF_PMM |
| 183 | ("%s: pmmAllocate: allocated memory at %x\n", |
| 184 | __func__, rval); |
| 185 | } else { |
| 186 | rval = 0; |
| 187 | printf |
| 188 | ("%s: pmmAllocate: allocation in extended memory not supported!\n", |
| 189 | __func__); |
| 190 | } |
| 191 | goto exit; |
| 192 | case 1: |
| 193 | /* function pmmFind */ |
| 194 | handle = pop_long(); /* the handle to lookup */ |
| 195 | DEBUG_PRINTF_PMM("%s: pmmFind: Handle: %x\n", __func__, |
| 196 | handle); |
| 197 | i = 0; |
| 198 | for (i = 0; i < curr_pmm_allocation_index; i++) { |
| 199 | if (pmm_allocation_array[i].handle == handle) { |
| 200 | DEBUG_PRINTF_PMM |
| 201 | ("%s: pmmFind: found allocated memory at %x\n", |
| 202 | __func__, rval); |
| 203 | /* return the 32bit "physical" address, i.e. combination of segment and offset */ |
| 204 | rval = |
| 205 | ((u32) (PMM_CONV_SEGMENT << 16)) | |
| 206 | pmm_allocation_array[i].offset; |
| 207 | } |
| 208 | } |
| 209 | if (rval == 0) { |
| 210 | DEBUG_PRINTF_PMM |
| 211 | ("%s: pmmFind: handle (%x) not found!\n", |
| 212 | __func__, handle); |
| 213 | } |
| 214 | goto exit; |
| 215 | case 2: |
| 216 | /* function pmmDeallocate */ |
| 217 | buffer = pop_long(); |
| 218 | /* since argument is the address of the PMM block (including the segment, |
| 219 | * we need to remove the segment to get the offset |
| 220 | */ |
| 221 | buffer = buffer ^ ((u32) PMM_CONV_SEGMENT << 16); |
| 222 | DEBUG_PRINTF_PMM("%s: pmmDeallocate: PMM segment offset: %x\n", |
| 223 | __func__, buffer); |
| 224 | i = 0; |
Martin Roth | 63373ed | 2013-07-08 16:24:19 -0600 | [diff] [blame] | 225 | /* rval = 0 means we deallocated the buffer, so set it to 1 in case we don't find it and |
Stefan Reinauer | 38cd29e | 2009-08-11 21:28:25 +0000 | [diff] [blame] | 226 | * thus cannot deallocate |
| 227 | */ |
| 228 | rval = 1; |
| 229 | for (i = 0; i < curr_pmm_allocation_index; i++) { |
| 230 | DEBUG_PRINTF_PMM("%d: %x\n", i, |
| 231 | pmm_allocation_array[i].handle); |
| 232 | if (pmm_allocation_array[i].offset == buffer) { |
| 233 | /* we found the requested buffer, rval = 0 */ |
| 234 | rval = 0; |
| 235 | DEBUG_PRINTF_PMM |
| 236 | ("%s: pmmDeallocate: found allocated memory at index: %d\n", |
| 237 | __func__, i); |
| 238 | /* copy the remaining elements in pmm_allocation_array one position up */ |
| 239 | j = i; |
| 240 | for (; j < curr_pmm_allocation_index; j++) { |
| 241 | pmm_allocation_array[j] = |
| 242 | pmm_allocation_array[j + 1]; |
| 243 | } |
| 244 | /* move curr_pmm_allocation_index one up, too */ |
| 245 | curr_pmm_allocation_index--; |
| 246 | /* finally clean last element */ |
| 247 | pmm_allocation_array[curr_pmm_allocation_index]. |
| 248 | handle = 0; |
| 249 | pmm_allocation_array[curr_pmm_allocation_index]. |
| 250 | offset = 0; |
| 251 | pmm_allocation_array[curr_pmm_allocation_index]. |
| 252 | length = 0; |
| 253 | break; |
| 254 | } |
| 255 | } |
| 256 | if (rval != 0) { |
| 257 | DEBUG_PRINTF_PMM |
| 258 | ("%s: pmmDeallocate: offset (%x) not found, cannot deallocate!\n", |
| 259 | __func__, buffer); |
| 260 | } |
| 261 | goto exit; |
| 262 | default: |
| 263 | /* invalid/unimplemented function */ |
| 264 | printf("%s: invalid PMM function (0x%04x) called!\n", |
| 265 | __func__, function); |
| 266 | /* PMM spec says if function is invalid, return 0xFFFFFFFF */ |
| 267 | rval = 0xFFFFFFFF; |
| 268 | goto exit; |
| 269 | } |
Patrick Georgi | c5fc7db | 2012-03-07 15:55:47 +0100 | [diff] [blame] | 270 | exit: |
Stefan Reinauer | 38cd29e | 2009-08-11 21:28:25 +0000 | [diff] [blame] | 271 | /* exit handler of this function, restore registers, put return value in DX:AX */ |
| 272 | M.x86 = backup_regs; |
| 273 | M.x86.R_DX = (u16) ((rval >> 16) & 0xFFFF); |
| 274 | M.x86.R_AX = (u16) (rval & 0xFFFF); |
| 275 | CHECK_DBG(DEBUG_PMM) { |
| 276 | DEBUG_PRINTF_PMM("%s: dump of pmm_allocation_array:\n", |
| 277 | __func__); |
| 278 | for (i = 0; i < MAX_PMM_AREAS; i++) { |
| 279 | DEBUG_PRINTF_PMM |
| 280 | ("%d:\n\thandle: %x\n\toffset: %x\n\tlength: %x\n", |
| 281 | i, pmm_allocation_array[i].handle, |
| 282 | pmm_allocation_array[i].offset, |
| 283 | pmm_allocation_array[i].length); |
| 284 | } |
| 285 | } |
| 286 | return; |
| 287 | } |
| 288 | |
| 289 | /* This function tests the pmm_handleInt() function above. */ |
| 290 | void pmm_test(void) |
| 291 | { |
| 292 | u32 handle, length, addr; |
| 293 | u16 function, flags; |
| 294 | /*-------------------- Test simple allocation/find/deallocation ----------------------------- */ |
| 295 | function = 0; /* pmmAllocate */ |
| 296 | handle = 0xdeadbeef; |
| 297 | length = 16; /* in 16byte paragraphs, so we allocate 256 bytes... */ |
| 298 | flags = 0x1; /* conventional memory, unaligned */ |
| 299 | /* setup stack for call to pmm_handleInt() */ |
| 300 | push_word(flags); |
| 301 | push_long(handle); |
| 302 | push_long(length); |
| 303 | push_word(function); |
| 304 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 305 | pmm_handleInt(); |
| 306 | addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX; |
| 307 | DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __func__, |
| 308 | M.x86.R_DX, M.x86.R_AX); |
| 309 | function = 1; /* pmmFind */ |
| 310 | push_long(handle); |
| 311 | push_word(function); |
| 312 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 313 | pmm_handleInt(); |
| 314 | DEBUG_PRINTF_PMM("%s: found memory at: %04x:%04x (expected: %08x)\n", |
| 315 | __func__, M.x86.R_DX, M.x86.R_AX, addr); |
| 316 | function = 2; /* pmmDeallocate */ |
| 317 | push_long(addr); |
| 318 | push_word(function); |
| 319 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 320 | pmm_handleInt(); |
| 321 | DEBUG_PRINTF_PMM |
| 322 | ("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n", |
| 323 | __func__, M.x86.R_DX, M.x86.R_AX); |
| 324 | /*-------------------- Test aligned allocation/deallocation ----------------------------- */ |
| 325 | function = 0; /* pmmAllocate */ |
| 326 | handle = 0xdeadbeef; |
| 327 | length = 257; /* in 16byte paragraphs, so we allocate 4KB + 16 bytes... */ |
| 328 | flags = 0x1; /* conventional memory, unaligned */ |
| 329 | /* setup stack for call to pmm_handleInt() */ |
| 330 | push_word(flags); |
| 331 | push_long(handle); |
| 332 | push_long(length); |
| 333 | push_word(function); |
| 334 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 335 | pmm_handleInt(); |
| 336 | addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX; |
| 337 | DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __func__, |
| 338 | M.x86.R_DX, M.x86.R_AX); |
| 339 | function = 0; /* pmmAllocate */ |
| 340 | handle = 0xf00d4b0b; |
| 341 | length = 128; /* in 16byte paragraphs, so we allocate 2KB... */ |
| 342 | flags = 0x5; /* conventional memory, aligned */ |
| 343 | /* setup stack for call to pmm_handleInt() */ |
| 344 | push_word(flags); |
| 345 | push_long(handle); |
| 346 | push_long(length); |
| 347 | push_word(function); |
| 348 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 349 | pmm_handleInt(); |
| 350 | /* the address should be aligned to 0x800, so probably it is at offset 0x1800... */ |
| 351 | addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX; |
| 352 | DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __func__, |
| 353 | M.x86.R_DX, M.x86.R_AX); |
| 354 | function = 1; /* pmmFind */ |
| 355 | push_long(handle); |
| 356 | push_word(function); |
| 357 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 358 | pmm_handleInt(); |
| 359 | addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX; |
| 360 | function = 2; /* pmmDeallocate */ |
| 361 | push_long(addr); |
| 362 | push_word(function); |
| 363 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 364 | pmm_handleInt(); |
| 365 | DEBUG_PRINTF_PMM |
| 366 | ("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n", |
| 367 | __func__, M.x86.R_DX, M.x86.R_AX); |
| 368 | handle = 0xdeadbeef; |
| 369 | function = 1; /* pmmFind */ |
| 370 | push_long(handle); |
| 371 | push_word(function); |
| 372 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 373 | pmm_handleInt(); |
| 374 | addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX; |
| 375 | function = 2; /* pmmDeallocate */ |
| 376 | push_long(addr); |
| 377 | push_word(function); |
| 378 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 379 | pmm_handleInt(); |
| 380 | DEBUG_PRINTF_PMM |
| 381 | ("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n", |
| 382 | __func__, M.x86.R_DX, M.x86.R_AX); |
| 383 | /*-------------------- Test out of memory allocation ----------------------------- */ |
| 384 | function = 0; /* pmmAllocate */ |
| 385 | handle = 0xdeadbeef; |
| 386 | length = 0; /* length zero means, give me the largest possible block */ |
| 387 | flags = 0x1; /* conventional memory, unaligned */ |
| 388 | /* setup stack for call to pmm_handleInt() */ |
| 389 | push_word(flags); |
| 390 | push_long(handle); |
| 391 | push_long(length); |
| 392 | push_word(function); |
| 393 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 394 | pmm_handleInt(); |
| 395 | length = ((u32) M.x86.R_DX << 16) | M.x86.R_AX; |
| 396 | length /= 16; /* length in paragraphs */ |
| 397 | DEBUG_PRINTF_PMM("%s: largest possible length: %08x\n", __func__, |
| 398 | length); |
| 399 | function = 0; /* pmmAllocate */ |
| 400 | flags = 0x1; /* conventional memory, aligned */ |
| 401 | /* setup stack for call to pmm_handleInt() */ |
| 402 | push_word(flags); |
| 403 | push_long(handle); |
| 404 | push_long(length); |
| 405 | push_word(function); |
| 406 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 407 | pmm_handleInt(); |
| 408 | addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX; |
| 409 | DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __func__, |
| 410 | M.x86.R_DX, M.x86.R_AX); |
| 411 | function = 0; /* pmmAllocate */ |
| 412 | length = 1; |
| 413 | handle = 0xf00d4b0b; |
| 414 | flags = 0x1; /* conventional memory, aligned */ |
| 415 | /* setup stack for call to pmm_handleInt() */ |
| 416 | push_word(flags); |
| 417 | push_long(handle); |
| 418 | push_long(length); |
| 419 | push_word(function); |
| 420 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 421 | pmm_handleInt(); |
| 422 | /* this should fail, so 0x0 should be returned */ |
| 423 | addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX; |
| 424 | DEBUG_PRINTF_PMM |
| 425 | ("%s: allocated memory at: %04x:%04x expected: 0000:0000\n", |
| 426 | __func__, M.x86.R_DX, M.x86.R_AX); |
| 427 | handle = 0xdeadbeef; |
| 428 | function = 1; /* pmmFind */ |
| 429 | push_long(handle); |
| 430 | push_word(function); |
| 431 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 432 | pmm_handleInt(); |
| 433 | addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX; |
| 434 | function = 2; /* pmmDeallocate */ |
| 435 | push_long(addr); |
| 436 | push_word(function); |
| 437 | push_long(0); /* This is the return address for the ABI, unused in this implementation */ |
| 438 | pmm_handleInt(); |
| 439 | DEBUG_PRINTF_PMM |
| 440 | ("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n", |
| 441 | __func__, M.x86.R_DX, M.x86.R_AX); |
| 442 | } |