2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009, 2010 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/relocator.h>
20 #include <grub/relocator_private.h>
21 #include <grub/mm_private.h>
22 #include <grub/misc.h>
23 #include <grub/cache.h>
24 #include <grub/memory.h>
26 #include <grub/i18n.h>
28 GRUB_MOD_LICENSE ("GPLv3+");
32 struct grub_relocator_chunk
*chunks
;
33 grub_phys_addr_t postchunks
;
34 grub_phys_addr_t highestaddr
;
35 grub_phys_addr_t highestnonpostaddr
;
36 grub_size_t relocators_size
;
39 struct grub_relocator_subchunk
41 enum {CHUNK_TYPE_IN_REGION
, CHUNK_TYPE_REGION_START
,
42 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
43 CHUNK_TYPE_FIRMWARE
, CHUNK_TYPE_LEFTOVER
47 grub_phys_addr_t start
;
50 struct grub_relocator_extra_block
*extra
;
51 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
52 struct grub_relocator_fw_leftover
*pre
, *post
;
56 struct grub_relocator_chunk
58 struct grub_relocator_chunk
*next
;
61 grub_phys_addr_t target
;
63 struct grub_relocator_subchunk
*subchunks
;
67 struct grub_relocator_extra_block
69 struct grub_relocator_extra_block
*next
;
70 struct grub_relocator_extra_block
**prev
;
71 grub_phys_addr_t start
;
75 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
76 struct grub_relocator_fw_leftover
78 struct grub_relocator_fw_leftover
*next
;
79 struct grub_relocator_fw_leftover
**prev
;
80 grub_phys_addr_t quantstart
;
81 grub_uint8_t freebytes
[GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
/ 8];
84 static struct grub_relocator_fw_leftover
*leftovers
;
87 static struct grub_relocator_extra_block
*extra_blocks
;
90 get_virtual_current_address (grub_relocator_chunk_t in
)
96 get_physical_target_address (grub_relocator_chunk_t in
)
101 struct grub_relocator
*
102 grub_relocator_new (void)
104 struct grub_relocator
*ret
;
106 grub_cpu_relocator_init ();
108 ret
= grub_zalloc (sizeof (struct grub_relocator
));
112 ret
->postchunks
= ~(grub_phys_addr_t
) 0;
113 ret
->relocators_size
= grub_relocator_jumper_size
;
114 grub_dprintf ("relocator", "relocators_size=%lu\n",
115 (unsigned long) ret
->relocators_size
);
119 #define DIGITSORT_BITS 8
120 #define DIGITSORT_MASK ((1 << DIGITSORT_BITS) - 1)
121 #define BITS_IN_BYTE 8
123 #define max(a, b) (((a) > (b)) ? (a) : (b))
124 #define min(a, b) (((a) < (b)) ? (a) : (b))
129 return !(type
& 1) && (type
!= COLLISION_START
);
133 allocate_regstart (grub_phys_addr_t addr
, grub_size_t size
, grub_mm_region_t rb
,
134 grub_mm_region_t
*regancestor
, grub_mm_header_t hancestor
)
136 grub_addr_t newreg_start
, newreg_raw_start
137 = (grub_addr_t
) rb
+ (addr
- grub_vtop (rb
)) + size
;
138 grub_addr_t newreg_size
, newreg_presize
;
139 grub_mm_header_t new_header
;
140 grub_mm_header_t hb
= (grub_mm_header_t
) (rb
+ 1);
142 #ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF
143 grub_dprintf ("relocator", "ra = %p, rb = %p\n", regancestor
, rb
);
145 newreg_start
= ALIGN_UP (newreg_raw_start
, GRUB_MM_ALIGN
);
146 newreg_presize
= newreg_start
- newreg_raw_start
;
147 newreg_size
= rb
->size
- (newreg_start
- (grub_addr_t
) rb
);
148 if ((hb
->size
<< GRUB_MM_ALIGN_LOG2
) >= newreg_start
151 grub_mm_header_t newhnext
= hb
->next
;
152 grub_size_t newhsize
= ((hb
->size
<< GRUB_MM_ALIGN_LOG2
)
154 - (grub_addr_t
) rb
)) >> GRUB_MM_ALIGN_LOG2
;
155 new_header
= (void *) (newreg_start
+ sizeof (*rb
));
157 newhnext
= new_header
;
158 new_header
->next
= newhnext
;
159 new_header
->size
= newhsize
;
160 new_header
->magic
= GRUB_MM_FREE_MAGIC
;
164 new_header
= hb
->next
;
165 if (new_header
== hb
)
166 new_header
= (void *) (newreg_start
+ sizeof (*rb
));
169 struct grub_mm_header
*newregfirst
= rb
->first
;
170 struct grub_mm_region
*newregnext
= rb
->next
;
171 struct grub_mm_region
*newreg
= (void *) newreg_start
;
172 hancestor
->next
= new_header
;
173 if (newregfirst
== hb
)
174 newregfirst
= new_header
;
175 newreg
->first
= newregfirst
;
176 newreg
->next
= newregnext
;
177 newreg
->pre_size
= newreg_presize
;
178 newreg
->size
= newreg_size
;
179 *regancestor
= newreg
;
181 grub_mm_header_t h
= newreg
->first
, hp
= NULL
;
184 if ((void *) h
< (void *) (newreg
+ 1))
185 grub_fatal ("Failed to adjust memory region: %p, %p, %p, %p, %p",
186 newreg
, newreg
->first
, h
, hp
, hb
);
187 #ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF
188 if ((void *) h
== (void *) (newreg
+ 1))
189 grub_dprintf ("relocator",
190 "Free start memory region: %p, %p, %p, %p, %p",
191 newreg
, newreg
->first
, h
, hp
, hb
);
196 while (h
!= newreg
->first
);
202 allocate_inreg (grub_phys_addr_t paddr
, grub_size_t size
,
203 grub_mm_header_t hb
, grub_mm_header_t hbp
,
206 struct grub_mm_header
*foll
= NULL
;
207 grub_addr_t vaddr
= (grub_addr_t
) hb
+ (paddr
- grub_vtop (hb
));
209 #ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF
210 grub_dprintf ("relocator", "inreg paddr = 0x%lx, size = %lu,"
211 " hb = %p, hbp = %p, rb = %p, vaddr = 0x%lx\n",
212 (unsigned long) paddr
, (unsigned long) size
, hb
, hbp
,
213 rb
, (unsigned long) vaddr
);
216 if (ALIGN_UP (vaddr
+ size
, GRUB_MM_ALIGN
) + GRUB_MM_ALIGN
217 <= (grub_addr_t
) (hb
+ hb
->size
))
219 foll
= (void *) ALIGN_UP (vaddr
+ size
, GRUB_MM_ALIGN
);
220 foll
->magic
= GRUB_MM_FREE_MAGIC
;
221 foll
->size
= hb
+ hb
->size
- foll
;
222 #ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF
223 grub_dprintf ("relocator", "foll = %p, foll->size = %lu\n", foll
,
224 (unsigned long) foll
->size
);
228 if (vaddr
- (grub_addr_t
) hb
>= sizeof (*hb
))
230 hb
->size
= ((vaddr
- (grub_addr_t
) hb
) >> GRUB_MM_ALIGN_LOG2
);
245 foll
->next
= hb
->next
;
257 rb
->first
= (void *) (rb
+ 1);
262 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
264 check_leftover (struct grub_relocator_fw_leftover
*lo
)
267 for (i
= 0; i
< sizeof (lo
->freebytes
); i
++)
268 if (lo
->freebytes
[i
] != 0xff)
270 grub_relocator_firmware_free_region (lo
->quantstart
,
271 GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
);
272 *lo
->prev
= lo
->next
;
274 lo
->next
->prev
= lo
->prev
;
279 free_subchunk (const struct grub_relocator_subchunk
*subchu
)
281 switch (subchu
->type
)
283 case CHUNK_TYPE_REGION_START
:
285 grub_mm_region_t r1
, r2
, *rp
;
287 grub_size_t pre_size
;
289 r2
= (grub_mm_region_t
) ALIGN_UP ((grub_addr_t
) subchu
->reg
290 + (grub_vtop (subchu
->reg
)
291 - subchu
->start
) + subchu
->size
,
293 for (rp
= &grub_mm_base
; *rp
&& *rp
!= r2
; rp
= &((*rp
)->next
));
294 pre_size
= subchu
->pre_size
;
298 grub_mm_header_t h2
, *hp
;
299 r1
->first
= r2
->first
;
301 r1
->pre_size
= pre_size
;
302 r1
->size
= r2
->size
+ (r2
- r1
) * sizeof (*r2
);
304 h
= (grub_mm_header_t
) (r1
+ 1);
306 h
->magic
= GRUB_MM_FREE_MAGIC
;
307 h
->size
= (r2
- r1
- 1);
308 for (hp
= &r2
->first
, h2
= *hp
; h2
->next
!= r2
->first
;
309 hp
= &(h2
->next
), h2
= *hp
)
310 if (h2
== (grub_mm_header_t
) (r2
+ 1))
312 if (h2
== (grub_mm_header_t
) (r2
+ 1))
314 h
->size
= h2
->size
+ (h2
- h
);
317 if (hp
== &r2
->first
)
319 for (h2
= r2
->first
; h2
->next
!= r2
->first
; h2
= h2
->next
);
330 r1
->pre_size
= pre_size
;
331 r1
->size
= (r2
- r1
) * sizeof (*r2
);
332 /* Find where to insert this region.
333 Put a smaller one before bigger ones,
334 to prevent fragmentation. */
335 for (rp
= &grub_mm_base
; *rp
; rp
= &((*rp
)->next
))
336 if ((*rp
)->size
> r1
->size
)
340 h
= (grub_mm_header_t
) (r1
+ 1);
343 h
->magic
= GRUB_MM_FREE_MAGIC
;
344 h
->size
= (r2
- r1
- 1);
346 for (r2
= grub_mm_base
; r2
; r2
= r2
->next
)
347 if ((grub_addr_t
) r2
+ r2
->size
== (grub_addr_t
) r1
)
351 grub_mm_header_t hl2
, hl
, g
;
352 g
= (grub_mm_header_t
) ((grub_addr_t
) r2
+ r2
->size
);
353 g
->size
= (grub_mm_header_t
) r1
- g
;
354 r2
->size
+= r1
->size
;
355 for (hl
= r2
->first
; hl
->next
!= r2
->first
; hl
= hl
->next
);
356 for (hl2
= r1
->first
; hl2
->next
!= r1
->first
; hl2
= hl2
->next
);
357 hl2
->next
= r2
->first
;
358 r2
->first
= r1
->first
;
359 hl
->next
= r2
->first
;
365 case CHUNK_TYPE_IN_REGION
:
367 grub_mm_header_t h
= (grub_mm_header_t
) ALIGN_DOWN ((grub_addr_t
) subchu
->start
,
370 = ((subchu
->start
+ subchu
->size
+ GRUB_MM_ALIGN
- 1) / GRUB_MM_ALIGN
)
371 - (subchu
->start
/ GRUB_MM_ALIGN
) - 1;
373 h
->magic
= GRUB_MM_ALLOC_MAGIC
;
377 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
378 case CHUNK_TYPE_FIRMWARE
:
379 case CHUNK_TYPE_LEFTOVER
:
381 grub_addr_t fstart
, fend
;
382 fstart
= ALIGN_UP (subchu
->start
,
383 GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
);
384 fend
= ALIGN_DOWN (subchu
->start
+ subchu
->size
,
385 GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
);
387 grub_relocator_firmware_free_region (fstart
, fend
- fstart
);
388 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
391 int off
= subchu
->start
- fstart
392 - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
;
393 grub_memset (subchu
->pre
->freebytes
+ off
/ 8 + 1,
394 0xff, sizeof (subchu
->pre
->freebytes
) - off
/ 8 - 1);
395 subchu
->pre
->freebytes
[off
/ 8] |= ~((1 << (off
% 8)) - 1);
396 check_leftover (subchu
->pre
);
400 int off
= subchu
->start
+ subchu
->size
- fend
;
401 grub_memset (subchu
->pre
->freebytes
,
402 0xff, sizeof (subchu
->pre
->freebytes
) - off
/ 8);
403 subchu
->pre
->freebytes
[off
/ 8] |= ((1 << (8 - (off
% 8))) - 1);
404 check_leftover (subchu
->post
);
407 *subchu
->extra
->prev
= subchu
->extra
->next
;
408 grub_free (subchu
->extra
);
416 malloc_in_range (struct grub_relocator
*rel
,
417 grub_addr_t start
, grub_addr_t end
, grub_addr_t align
,
418 grub_size_t size
, struct grub_relocator_chunk
*res
,
419 int from_low_priv
, int collisioncheck
)
421 grub_mm_region_t r
, *ra
, base_saved
;
422 struct grub_relocator_mmap_event
*events
= NULL
, *eventt
= NULL
, *t
;
423 /* 128 is just in case of additional malloc (shouldn't happen). */
424 unsigned maxevents
= 2 + 128;
425 grub_mm_header_t p
, pa
;
429 grub_addr_t target
= 0;
431 grub_dprintf ("relocator",
432 "trying to allocate in 0x%lx-0x%lx aligned 0x%lx size 0x%lx\n",
433 (unsigned long) start
, (unsigned long) end
,
434 (unsigned long) align
, (unsigned long) size
);
436 start
= ALIGN_UP (start
, align
);
437 end
= ALIGN_DOWN (end
- size
, align
) + size
;
439 if (end
< start
+ size
)
442 /* We have to avoid any allocations when filling scanline events.
445 for (r
= grub_mm_base
; r
; r
= r
->next
)
450 if ((grub_addr_t
) p
< (grub_addr_t
) (r
+ 1)
451 || (grub_addr_t
) p
>= (grub_addr_t
) (r
+ 1) + r
->size
)
452 grub_fatal ("%d: out of range pointer: %p\n", __LINE__
, p
);
456 while (p
!= r
->first
);
460 if (collisioncheck
&& rel
)
462 struct grub_relocator_chunk
*chunk
;
463 for (chunk
= rel
->chunks
; chunk
; chunk
= chunk
->next
)
467 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
469 struct grub_relocator_extra_block
*cur
;
470 for (cur
= extra_blocks
; cur
; cur
= cur
->next
)
473 for (r
= grub_mm_base
; r
; r
= r
->next
)
476 maxevents
+= grub_relocator_firmware_get_max_events ();
479 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
481 struct grub_relocator_fw_leftover
*cur
;
482 for (cur
= leftovers
; cur
; cur
= cur
->next
)
486 for (i
= 0; i
< GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
; i
++)
488 if (l
!= ((cur
->freebytes
[i
/ 8] >> (i
% 8)) & 1))
490 l
= ((cur
->freebytes
[i
/ 8] >> (i
% 8)) & 1);
498 eventt
= grub_malloc (maxevents
* sizeof (events
[0]));
499 counter
= grub_malloc ((DIGITSORT_MASK
+ 2) * sizeof (counter
[0]));
500 events
= grub_malloc (maxevents
* sizeof (events
[0]));
501 if (!events
|| !eventt
|| !counter
)
503 grub_dprintf ("relocator", "events or counter allocation failed %d\n",
511 if (collisioncheck
&& rel
)
513 struct grub_relocator_chunk
*chunk
;
514 for (chunk
= rel
->chunks
; chunk
; chunk
= chunk
->next
)
516 events
[N
].type
= COLLISION_START
;
517 events
[N
].pos
= chunk
->target
;
519 events
[N
].type
= COLLISION_END
;
520 events
[N
].pos
= chunk
->target
+ chunk
->size
;
525 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
526 for (r
= grub_mm_base
; r
; r
= r
->next
)
528 #ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF
529 grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n",
530 (unsigned long) r
- r
->pre_size
,
531 (unsigned long) (r
+ 1) + r
->size
);
533 events
[N
].type
= FIRMWARE_BLOCK_START
;
534 events
[N
].pos
= (grub_addr_t
) r
- r
->pre_size
;
536 events
[N
].type
= FIRMWARE_BLOCK_END
;
537 events
[N
].pos
= (grub_addr_t
) (r
+ 1) + r
->size
;
541 struct grub_relocator_extra_block
*cur
;
542 for (cur
= extra_blocks
; cur
; cur
= cur
->next
)
544 #ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF
545 grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n",
546 (unsigned long) cur
->start
, (unsigned long) cur
->end
);
548 events
[N
].type
= FIRMWARE_BLOCK_START
;
549 events
[N
].pos
= cur
->start
;
551 events
[N
].type
= FIRMWARE_BLOCK_END
;
552 events
[N
].pos
= cur
->end
;
557 N
+= grub_relocator_firmware_fill_events (events
+ N
);
559 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
561 struct grub_relocator_fw_leftover
*cur
;
562 for (cur
= leftovers
; cur
; cur
= cur
->next
)
566 for (i
= 0; i
< GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
; i
++)
568 if (l
!= ((cur
->freebytes
[i
/ 8] >> (i
% 8)) & 1))
570 events
[N
].type
= l
? REG_LEFTOVER_END
: REG_LEFTOVER_START
;
571 events
[N
].pos
= cur
->quantstart
+ i
;
572 events
[N
].leftover
= cur
;
575 l
= ((cur
->freebytes
[i
/ 8] >> (i
% 8)) & 1);
579 events
[N
].type
= REG_LEFTOVER_END
;
580 events
[N
].pos
= cur
->quantstart
+ i
;
581 events
[N
].leftover
= cur
;
589 /* No malloc from this point. */
590 base_saved
= grub_mm_base
;
593 for (ra
= &base_saved
, r
= *ra
; r
; ra
= &(r
->next
), r
= *ra
)
597 if (p
->magic
== GRUB_MM_ALLOC_MAGIC
)
601 if (p
->magic
!= GRUB_MM_FREE_MAGIC
)
602 grub_fatal (__FILE__
":%d free magic broken at %p (0x%x)\n",
603 __LINE__
, p
, p
->magic
);
604 if (p
== (grub_mm_header_t
) (r
+ 1))
606 events
[N
].type
= REG_BEG_START
;
607 events
[N
].pos
= grub_vtop (r
) - r
->pre_size
;
609 events
[N
].regancestor
= ra
;
611 events
[N
].hancestor
= pa
;
613 events
[N
].type
= REG_BEG_END
;
614 events
[N
].pos
= grub_vtop (p
+ p
->size
) - sizeof (*r
)
615 - sizeof (struct grub_mm_header
);
620 events
[N
].type
= IN_REG_START
;
621 events
[N
].pos
= grub_vtop (p
);
623 events
[N
].hancestor
= pa
;
626 events
[N
].type
= IN_REG_END
;
627 events
[N
].pos
= grub_vtop (p
+ p
->size
);
633 while (pa
!= r
->first
);
636 /* Put ending events after starting events. */
638 int st
= 0, e
= N
/ 2;
639 for (j
= 0; j
< N
; j
++)
640 if (is_start (events
[j
].type
) || events
[j
].type
== COLLISION_START
)
641 eventt
[st
++] = events
[j
];
643 eventt
[e
++] = events
[j
];
651 for (i
= 0; i
< (BITS_IN_BYTE
* sizeof (grub_addr_t
) / DIGITSORT_BITS
);
654 memset (counter
, 0, (1 + (1 << DIGITSORT_BITS
)) * sizeof (counter
[0]));
655 for (j
= 0; j
< N
; j
++)
656 counter
[((events
[j
].pos
>> (DIGITSORT_BITS
* i
))
657 & DIGITSORT_MASK
) + 1]++;
658 for (j
= 0; j
<= DIGITSORT_MASK
; j
++)
659 counter
[j
+1] += counter
[j
];
660 for (j
= 0; j
< N
; j
++)
661 eventt
[counter
[((events
[j
].pos
>> (DIGITSORT_BITS
* i
))
662 & DIGITSORT_MASK
)]++] = events
[j
];
669 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
673 /* Now events are nicely sorted. */
675 int nstarted
= 0, ncollisions
= 0, nstartedfw
= 0, nblockfw
= 0;
676 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
679 const int nlefto
= 0;
681 grub_addr_t starta
= 0;
682 for (j
= from_low_priv
? 0 : N
- 1; from_low_priv
? j
< N
: (j
+ 1);
683 from_low_priv
? j
++ : j
--)
685 int isinsidebefore
, isinsideafter
;
686 isinsidebefore
= (!ncollisions
&& (nstarted
|| (((nlefto
|| nstartedfw
)
688 switch (events
[j
].type
)
690 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
691 case REG_FIRMWARE_START
:
695 case REG_FIRMWARE_END
:
699 case FIRMWARE_BLOCK_START
:
703 case FIRMWARE_BLOCK_END
:
708 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
709 case REG_LEFTOVER_START
:
713 case REG_LEFTOVER_END
:
718 case COLLISION_START
:
736 isinsideafter
= (!ncollisions
&& (nstarted
|| ((nlefto
|| nstartedfw
)
738 if (!isinsidebefore
&& isinsideafter
)
739 starta
= from_low_priv
? ALIGN_UP (events
[j
].pos
, align
)
740 : ALIGN_DOWN (events
[j
].pos
- size
, align
) + size
;
741 if (isinsidebefore
&& !isinsideafter
&& from_low_priv
)
746 if (target
+ size
<= end
&& target
+ size
<= events
[j
].pos
)
747 /* Found an usable address. */
750 if (isinsidebefore
&& !isinsideafter
&& !from_low_priv
)
752 target
= starta
- size
;
753 if (target
> end
- size
)
755 if (target
>= start
&& target
>= events
[j
].pos
)
761 grub_mm_base
= base_saved
;
769 int inreg
= 0, regbeg
= 0, ncol
= 0;
770 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
771 int fwin
= 0, fwb
= 0, fwlefto
= 0;
773 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
777 for (j
= 0; j
< N
; j
++)
783 typepre
= CHUNK_TYPE_REGION_START
;
785 typepre
= CHUNK_TYPE_IN_REGION
;
786 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
787 else if (fwin
&& !fwb
)
788 typepre
= CHUNK_TYPE_FIRMWARE
;
789 else if (fwlefto
&& !fwb
)
790 typepre
= CHUNK_TYPE_LEFTOVER
;
795 if (j
!= 0 && events
[j
- 1].pos
!= events
[j
].pos
)
797 grub_addr_t alloc_start
, alloc_end
;
798 alloc_start
= max (events
[j
- 1].pos
, target
);
799 alloc_end
= min (events
[j
].pos
, target
+ size
);
800 if (alloc_end
> alloc_start
)
804 case CHUNK_TYPE_REGION_START
:
805 allocate_regstart (alloc_start
, alloc_end
- alloc_start
,
806 events
[last_start
].reg
,
807 events
[last_start
].regancestor
,
808 events
[last_start
].hancestor
);
809 /* TODO: maintain a reverse lookup tree for hancestor. */
812 for (k
= 0; k
< N
; k
++)
813 if (events
[k
].hancestor
== events
[last_start
].head
)
814 events
[k
].hancestor
= events
[last_start
].hancestor
;
817 case CHUNK_TYPE_IN_REGION
:
818 allocate_inreg (alloc_start
, alloc_end
- alloc_start
,
819 events
[last_start
].head
,
820 events
[last_start
].hancestor
,
821 events
[last_start
].reg
);
824 for (k
= 0; k
< N
; k
++)
825 if (events
[k
].hancestor
== events
[last_start
].head
)
826 events
[k
].hancestor
= events
[last_start
].hancestor
;
829 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
830 case CHUNK_TYPE_FIRMWARE
:
832 grub_addr_t fstart
, fend
;
834 = ALIGN_DOWN (alloc_start
,
835 GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
);
837 = ALIGN_UP (alloc_end
,
838 GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
);
839 #ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF
840 grub_dprintf ("relocator", "requesting %lx-%lx\n",
841 (unsigned long) fstart
,
842 (unsigned long) fend
);
844 /* The failure here can be very expensive. */
845 if (!grub_relocator_firmware_alloc_region (fstart
,
858 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
859 case CHUNK_TYPE_LEFTOVER
:
861 unsigned offstart
= alloc_start
862 % GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
;
863 unsigned offend
= alloc_end
864 % GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
;
865 struct grub_relocator_fw_leftover
*lo
866 = events
[last_lo
].leftover
;
867 lo
->freebytes
[offstart
/ 8]
868 &= ((1 << (8 - (start
% 8))) - 1);
869 grub_memset (lo
->freebytes
+ (offstart
+ 7) / 8, 0,
870 offend
/ 8 - (offstart
+ 7) / 8);
871 lo
->freebytes
[offend
/ 8] &= ~((1 << (offend
% 8)) - 1);
880 switch (events
[j
].type
)
884 if (events
[j
].type
== REG_BEG_START
&&
885 (grub_addr_t
) (events
[j
].reg
+ 1) > target
)
900 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
901 case REG_FIRMWARE_START
:
905 case REG_FIRMWARE_END
:
909 case FIRMWARE_BLOCK_START
:
913 case FIRMWARE_BLOCK_END
:
918 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
919 case REG_LEFTOVER_START
:
924 case REG_LEFTOVER_END
:
928 case COLLISION_START
:
939 /* Malloc is available again. */
940 grub_mm_base
= base_saved
;
947 int inreg
= 0, regbeg
= 0, ncol
= 0;
948 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
949 int fwin
= 0, fwlefto
= 0, fwb
= 0;
953 res
->subchunks
= grub_malloc (sizeof (res
->subchunks
[0]) * nallocs
);
956 res
->nsubchunks
= nallocs
;
958 for (j
= 0; j
< N
; j
++)
964 typepre
= CHUNK_TYPE_REGION_START
;
966 typepre
= CHUNK_TYPE_IN_REGION
;
967 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
968 else if (fwin
&& !fwb
)
969 typepre
= CHUNK_TYPE_FIRMWARE
;
970 else if (fwlefto
&& !fwb
)
971 typepre
= CHUNK_TYPE_LEFTOVER
;
976 if (j
!= 0 && events
[j
- 1].pos
!= events
[j
].pos
)
978 grub_addr_t alloc_start
, alloc_end
;
979 struct grub_relocator_subchunk tofree
;
980 struct grub_relocator_subchunk
*curschu
= &tofree
;
982 curschu
= &res
->subchunks
[cural
];
983 alloc_start
= max (events
[j
- 1].pos
, target
);
984 alloc_end
= min (events
[j
].pos
, target
+ size
);
985 if (alloc_end
> alloc_start
)
987 grub_dprintf ("relocator", "subchunk 0x%lx-0x%lx, %d\n",
988 (unsigned long) alloc_start
,
989 (unsigned long) alloc_end
, typepre
);
990 curschu
->type
= typepre
;
991 curschu
->start
= alloc_start
;
992 curschu
->size
= alloc_end
- alloc_start
;
993 if (typepre
== CHUNK_TYPE_REGION_START
994 || typepre
== CHUNK_TYPE_IN_REGION
)
996 curschu
->reg
= events
[last_start
].reg
;
997 curschu
->pre_size
= alloc_start
- events
[j
- 1].pos
;
999 if (!oom
&& (typepre
== CHUNK_TYPE_REGION_START
1000 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
1001 || typepre
== CHUNK_TYPE_FIRMWARE
1005 struct grub_relocator_extra_block
*ne
;
1006 ne
= grub_malloc (sizeof (*ne
));
1010 grub_memcpy (&tofree
, curschu
, sizeof (tofree
));
1014 ne
->start
= alloc_start
;
1015 ne
->end
= alloc_end
;
1016 ne
->next
= extra_blocks
;
1017 ne
->prev
= &extra_blocks
;
1019 extra_blocks
->prev
= &(ne
->next
);
1021 curschu
->extra
= ne
;
1025 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
1026 if (!oom
&& typepre
== CHUNK_TYPE_FIRMWARE
)
1028 grub_addr_t fstart
, fend
;
1031 = ALIGN_DOWN (alloc_start
,
1032 GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
);
1034 = ALIGN_UP (alloc_end
,
1035 GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
);
1038 struct grub_relocator_fw_leftover
*lo1
= NULL
;
1039 struct grub_relocator_fw_leftover
*lo2
= NULL
;
1040 if (fstart
!= alloc_start
)
1041 lo1
= grub_malloc (sizeof (*lo1
));
1042 if (fend
!= alloc_end
)
1043 lo2
= grub_malloc (sizeof (*lo2
));
1044 if ((!lo1
&& fstart
!= alloc_start
)
1045 || (!lo2
&& fend
!= alloc_end
))
1047 struct grub_relocator_extra_block
*ne
;
1053 grub_memcpy (&tofree
, curschu
, sizeof (tofree
));
1055 extra_blocks
= extra_blocks
->next
;
1060 lo1
->quantstart
= fstart
;
1061 grub_memset (lo1
->freebytes
, 0xff,
1062 (alloc_start
- fstart
) / 8);
1063 lo1
->freebytes
[(alloc_start
- fstart
) / 8]
1064 = (1 << ((alloc_start
- fstart
) % 8)) - 1;
1065 grub_memset (lo1
->freebytes
1066 + ((alloc_start
- fstart
) / 8) + 1, 0,
1067 sizeof (lo1
->freebytes
)
1068 - (alloc_start
- fstart
) / 8 - 1);
1069 lo1
->next
= leftovers
;
1070 lo1
->prev
= &leftovers
;
1072 leftovers
->prev
= &lo1
->next
;
1078 = fend
- GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT
;
1079 grub_memset (lo2
->freebytes
, 0,
1080 (alloc_end
- lo2
->quantstart
) / 8);
1081 lo2
->freebytes
[(alloc_end
- lo2
->quantstart
) / 8]
1082 = ~((1 << ((alloc_end
- lo2
->quantstart
) % 8)) - 1);
1083 grub_memset (lo2
->freebytes
1084 + ((alloc_end
- lo2
->quantstart
) / 8)
1085 + 1, 0, sizeof (lo2
->freebytes
)
1086 - (alloc_end
- lo2
->quantstart
) / 8 - 1);
1087 lo2
->prev
= &leftovers
;
1089 leftovers
->prev
= &lo2
->next
;
1090 lo2
->next
= leftovers
;
1094 curschu
->post
= lo2
;
1098 if (typepre
== CHUNK_TYPE_LEFTOVER
)
1100 curschu
->pre
= events
[last_start
].leftover
;
1101 curschu
->post
= events
[last_start
].leftover
;
1108 free_subchunk (&tofree
);
1112 switch (events
[j
].type
)
1116 if (events
[j
].type
== REG_BEG_START
&&
1117 (grub_addr_t
) (events
[j
].reg
+ 1) > target
)
1129 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
1130 case REG_FIRMWARE_START
:
1134 case REG_FIRMWARE_END
:
1138 case FIRMWARE_BLOCK_START
:
1142 case FIRMWARE_BLOCK_END
:
1147 #if GRUB_RELOCATOR_HAVE_LEFTOVERS
1148 case REG_LEFTOVER_START
:
1152 case REG_LEFTOVER_END
:
1156 case COLLISION_START
:
1167 for (i
= 0; i
< cural
; i
++)
1168 free_subchunk (&res
->subchunks
[i
]);
1169 grub_free (res
->subchunks
);
1170 grub_dprintf ("relocator", "allocation failed with out-of-memory\n");
1182 grub_dprintf ("relocator", "allocated: 0x%lx+0x%lx\n", (unsigned long) target
,
1183 (unsigned long) size
);
1189 adjust_limits (struct grub_relocator
*rel
,
1190 grub_phys_addr_t
*min_addr
, grub_phys_addr_t
*max_addr
,
1191 grub_phys_addr_t in_min
, grub_phys_addr_t in_max
)
1193 struct grub_relocator_chunk
*chunk
;
1196 *max_addr
= rel
->postchunks
;
1198 /* Keep chunks in memory in the same order as they'll be after relocation. */
1199 for (chunk
= rel
->chunks
; chunk
; chunk
= chunk
->next
)
1201 if (chunk
->target
> in_max
&& chunk
->src
< *max_addr
1202 && chunk
->src
< rel
->postchunks
)
1203 *max_addr
= chunk
->src
;
1204 if (chunk
->target
+ chunk
->size
<= in_min
1205 && chunk
->src
+ chunk
->size
> *min_addr
1206 && chunk
->src
< rel
->postchunks
)
1207 *min_addr
= chunk
->src
+ chunk
->size
;
1212 grub_relocator_alloc_chunk_addr (struct grub_relocator
*rel
,
1213 grub_relocator_chunk_t
*out
,
1214 grub_phys_addr_t target
, grub_size_t size
)
1216 struct grub_relocator_chunk
*chunk
;
1217 grub_phys_addr_t min_addr
= 0, max_addr
;
1220 return grub_error (GRUB_ERR_BUG
, "address is out of range");
1222 adjust_limits (rel
, &min_addr
, &max_addr
, target
, target
);
1224 for (chunk
= rel
->chunks
; chunk
; chunk
= chunk
->next
)
1225 if ((chunk
->target
<= target
&& target
< chunk
->target
+ chunk
->size
)
1226 || (target
<= chunk
->target
&& chunk
->target
< target
+ size
))
1227 return grub_error (GRUB_ERR_BUG
, "overlap detected");
1229 chunk
= grub_malloc (sizeof (struct grub_relocator_chunk
));
1233 grub_dprintf ("relocator",
1234 "min_addr = 0x%llx, max_addr = 0x%llx, target = 0x%llx\n",
1235 (unsigned long long) min_addr
, (unsigned long long) max_addr
,
1236 (unsigned long long) target
);
1240 /* A trick to improve Linux allocation. */
1241 #if defined (__i386__) || defined (__x86_64__)
1242 if (target
< 0x100000)
1243 if (malloc_in_range (rel
, rel
->highestnonpostaddr
, ~(grub_addr_t
)0, 1,
1246 if (rel
->postchunks
> chunk
->src
)
1247 rel
->postchunks
= chunk
->src
;
1251 if (malloc_in_range (rel
, target
, max_addr
, 1, size
, chunk
, 1, 0))
1254 if (malloc_in_range (rel
, min_addr
, target
, 1, size
, chunk
, 0, 0))
1257 if (malloc_in_range (rel
, rel
->highestnonpostaddr
, ~(grub_addr_t
)0, 1,
1260 if (rel
->postchunks
> chunk
->src
)
1261 rel
->postchunks
= chunk
->src
;
1265 grub_dprintf ("relocator", "not allocated\n");
1267 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, N_("out of memory"));
1271 grub_dprintf ("relocator", "allocated 0x%llx/0x%llx\n",
1272 (unsigned long long) chunk
->src
, (unsigned long long) target
);
1274 if (rel
->highestaddr
< target
+ size
)
1275 rel
->highestaddr
= target
+ size
;
1277 if (rel
->highestaddr
< chunk
->src
+ size
)
1278 rel
->highestaddr
= chunk
->src
+ size
;
1280 if (chunk
->src
< rel
->postchunks
)
1282 if (rel
->highestnonpostaddr
< target
+ size
)
1283 rel
->highestnonpostaddr
= target
+ size
;
1285 if (rel
->highestnonpostaddr
< chunk
->src
+ size
)
1286 rel
->highestnonpostaddr
= chunk
->src
+ size
;
1289 grub_dprintf ("relocator", "relocators_size=%ld\n",
1290 (unsigned long) rel
->relocators_size
);
1292 if (chunk
->src
< target
)
1293 rel
->relocators_size
+= grub_relocator_backward_size
;
1294 if (chunk
->src
> target
)
1295 rel
->relocators_size
+= grub_relocator_forward_size
;
1297 grub_dprintf ("relocator", "relocators_size=%ld\n",
1298 (unsigned long) rel
->relocators_size
);
1300 chunk
->target
= target
;
1302 chunk
->next
= rel
->chunks
;
1303 rel
->chunks
= chunk
;
1304 grub_dprintf ("relocator", "cur = %p, next = %p\n", rel
->chunks
,
1307 chunk
->srcv
= grub_map_memory (chunk
->src
, chunk
->size
);
1309 #ifdef DEBUG_RELOCATOR
1310 grub_memset (chunk
->srcv
, 0xfa, chunk
->size
);
1313 return GRUB_ERR_NONE
;
1317 grub_relocator_alloc_chunk_align (struct grub_relocator
*rel
,
1318 grub_relocator_chunk_t
*out
,
1319 grub_phys_addr_t min_addr
,
1320 grub_phys_addr_t max_addr
,
1321 grub_size_t size
, grub_size_t align
,
1323 int avoid_efi_boot_services
)
1325 grub_addr_t min_addr2
= 0, max_addr2
;
1326 struct grub_relocator_chunk
*chunk
;
1328 if (max_addr
> ~size
)
1331 #ifdef GRUB_MACHINE_PCBIOS
1332 if (min_addr
< 0x1000)
1336 grub_dprintf ("relocator", "chunks = %p\n", rel
->chunks
);
1338 chunk
= grub_malloc (sizeof (struct grub_relocator_chunk
));
1342 if (malloc_in_range (rel
, min_addr
, max_addr
, align
,
1344 preference
!= GRUB_RELOCATOR_PREFERENCE_HIGH
, 1))
1346 grub_dprintf ("relocator", "allocated 0x%llx/0x%llx\n",
1347 (unsigned long long) chunk
->src
,
1348 (unsigned long long) chunk
->src
);
1349 grub_dprintf ("relocator", "chunks = %p\n", rel
->chunks
);
1350 chunk
->target
= chunk
->src
;
1352 chunk
->next
= rel
->chunks
;
1353 rel
->chunks
= chunk
;
1354 chunk
->srcv
= grub_map_memory (chunk
->src
, chunk
->size
);
1356 return GRUB_ERR_NONE
;
1359 adjust_limits (rel
, &min_addr2
, &max_addr2
, min_addr
, max_addr
);
1360 grub_dprintf ("relocator", "Adjusted limits from %lx-%lx to %lx-%lx\n",
1361 (unsigned long) min_addr
, (unsigned long) max_addr
,
1362 (unsigned long) min_addr2
, (unsigned long) max_addr2
);
1366 if (malloc_in_range (rel
, min_addr2
, max_addr2
, align
,
1370 if (malloc_in_range (rel
, rel
->highestnonpostaddr
, ~(grub_addr_t
)0, 1,
1373 if (rel
->postchunks
> chunk
->src
)
1374 rel
->postchunks
= chunk
->src
;
1378 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, N_("out of memory"));
1384 auto int NESTED_FUNC_ATTR
hook (grub_uint64_t
, grub_uint64_t
,
1385 grub_memory_type_t
);
1386 int NESTED_FUNC_ATTR
hook (grub_uint64_t addr
, grub_uint64_t sz
,
1387 grub_memory_type_t type
)
1389 grub_uint64_t candidate
;
1390 if (type
!= GRUB_MEMORY_AVAILABLE
)
1392 candidate
= ALIGN_UP (addr
, align
);
1393 if (candidate
< min_addr
)
1394 candidate
= ALIGN_UP (min_addr
, align
);
1395 if (candidate
+ size
> addr
+ sz
1396 || candidate
> ALIGN_DOWN (max_addr
, align
))
1398 if (preference
== GRUB_RELOCATOR_PREFERENCE_HIGH
)
1399 candidate
= ALIGN_DOWN (min (addr
+ sz
- size
, max_addr
), align
);
1400 if (!found
|| (preference
== GRUB_RELOCATOR_PREFERENCE_HIGH
1401 && candidate
> chunk
->target
))
1402 chunk
->target
= candidate
;
1403 if (!found
|| (preference
== GRUB_RELOCATOR_PREFERENCE_LOW
1404 && candidate
< chunk
->target
))
1405 chunk
->target
= candidate
;
1410 #ifdef GRUB_MACHINE_EFI
1411 grub_efi_mmap_iterate (hook
, avoid_efi_boot_services
);
1412 #elif defined (__powerpc__)
1413 (void) avoid_efi_boot_services
;
1414 grub_machine_mmap_iterate (hook
);
1416 (void) avoid_efi_boot_services
;
1417 grub_mmap_iterate (hook
);
1420 return grub_error (GRUB_ERR_BAD_OS
, "couldn't find suitable memory target");
1424 struct grub_relocator_chunk
*chunk2
;
1425 for (chunk2
= rel
->chunks
; chunk2
; chunk2
= chunk2
->next
)
1426 if ((chunk2
->target
<= chunk
->target
1427 && chunk
->target
< chunk2
->target
+ chunk2
->size
)
1428 || (chunk
->target
<= chunk2
->target
&& chunk2
->target
1429 < chunk
->target
+ size
))
1431 if (preference
== GRUB_RELOCATOR_PREFERENCE_HIGH
)
1432 chunk
->target
= ALIGN_DOWN (chunk2
->target
, align
);
1434 chunk
->target
= ALIGN_UP (chunk2
->target
+ chunk2
->size
, align
);
1441 grub_dprintf ("relocator", "relocators_size=%ld\n",
1442 (unsigned long) rel
->relocators_size
);
1444 if (chunk
->src
< chunk
->target
)
1445 rel
->relocators_size
+= grub_relocator_backward_size
;
1446 if (chunk
->src
> chunk
->target
)
1447 rel
->relocators_size
+= grub_relocator_forward_size
;
1449 grub_dprintf ("relocator", "relocators_size=%ld\n",
1450 (unsigned long) rel
->relocators_size
);
1453 chunk
->next
= rel
->chunks
;
1454 rel
->chunks
= chunk
;
1455 grub_dprintf ("relocator", "cur = %p, next = %p\n", rel
->chunks
,
1457 chunk
->srcv
= grub_map_memory (chunk
->src
, chunk
->size
);
1459 #ifdef DEBUG_RELOCATOR
1460 grub_memset (chunk
->srcv
, 0xfa, chunk
->size
);
1463 return GRUB_ERR_NONE
;
1467 grub_relocator_unload (struct grub_relocator
*rel
)
1469 struct grub_relocator_chunk
*chunk
, *next
;
1472 for (chunk
= rel
->chunks
; chunk
; chunk
= next
)
1475 for (i
= 0; i
< chunk
->nsubchunks
; i
++)
1476 free_subchunk (&chunk
->subchunks
[i
]);
1477 grub_unmap_memory (chunk
->srcv
, chunk
->size
);
1479 grub_free (chunk
->subchunks
);
1486 grub_relocator_prepare_relocs (struct grub_relocator
*rel
, grub_addr_t addr
,
1487 void **relstart
, grub_size_t
*relsize
)
1490 grub_uint8_t
*rels0
;
1491 struct grub_relocator_chunk
*sorted
;
1492 grub_size_t nchunks
= 0;
1494 struct grub_relocator_chunk movers_chunk
;
1496 grub_dprintf ("relocator", "Preparing relocs (size=%ld)\n",
1497 (unsigned long) rel
->relocators_size
);
1499 if (!malloc_in_range (rel
, 0, ~(grub_addr_t
)0 - rel
->relocators_size
+ 1,
1500 grub_relocator_align
,
1501 rel
->relocators_size
, &movers_chunk
, 1, 1))
1502 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, N_("out of memory"));
1503 movers_chunk
.srcv
= rels
= rels0
1504 = grub_map_memory (movers_chunk
.src
, movers_chunk
.size
);
1507 *relsize
= rel
->relocators_size
;
1509 grub_dprintf ("relocator", "Relocs allocated at %p\n", movers_chunk
.srcv
);
1513 grub_size_t count
[257];
1514 struct grub_relocator_chunk
*from
, *to
, *tmp
;
1516 grub_memset (count
, 0, sizeof (count
));
1519 struct grub_relocator_chunk
*chunk
;
1520 for (chunk
= rel
->chunks
; chunk
; chunk
= chunk
->next
)
1522 grub_dprintf ("relocator", "chunk %p->%p, 0x%lx\n",
1523 (void *) chunk
->src
, (void *) chunk
->target
,
1524 (unsigned long) chunk
->size
);
1526 count
[(chunk
->src
& 0xff) + 1]++;
1529 from
= grub_malloc (nchunks
* sizeof (sorted
[0]));
1530 to
= grub_malloc (nchunks
* sizeof (sorted
[0]));
1538 for (j
= 0; j
< 256; j
++)
1539 count
[j
+1] += count
[j
];
1542 struct grub_relocator_chunk
*chunk
;
1543 for (chunk
= rel
->chunks
; chunk
; chunk
= chunk
->next
)
1544 from
[count
[chunk
->src
& 0xff]++] = *chunk
;
1547 for (i
= 1; i
< GRUB_CPU_SIZEOF_VOID_P
; i
++)
1549 grub_memset (count
, 0, sizeof (count
));
1550 for (j
= 0; j
< nchunks
; j
++)
1551 count
[((from
[j
].src
>> (8 * i
)) & 0xff) + 1]++;
1552 for (j
= 0; j
< 256; j
++)
1553 count
[j
+1] += count
[j
];
1554 for (j
= 0; j
< nchunks
; j
++)
1555 to
[count
[(from
[j
].src
>> (8 * i
)) & 0xff]++] = from
[j
];
1564 for (j
= 0; j
< nchunks
; j
++)
1566 grub_dprintf ("relocator", "sorted chunk %p->%p, 0x%lx\n",
1567 (void *) sorted
[j
].src
, (void *) sorted
[j
].target
,
1568 (unsigned long) sorted
[j
].size
);
1569 if (sorted
[j
].src
< sorted
[j
].target
)
1571 grub_cpu_relocator_backward ((void *) rels
,
1573 grub_map_memory (sorted
[j
].target
,
1576 rels
+= grub_relocator_backward_size
;
1578 if (sorted
[j
].src
> sorted
[j
].target
)
1580 grub_cpu_relocator_forward ((void *) rels
,
1582 grub_map_memory (sorted
[j
].target
,
1585 rels
+= grub_relocator_forward_size
;
1587 if (sorted
[j
].src
== sorted
[j
].target
)
1588 grub_arch_sync_caches (sorted
[j
].srcv
, sorted
[j
].size
);
1590 grub_cpu_relocator_jumper ((void *) rels
, (grub_addr_t
) addr
);
1593 return GRUB_ERR_NONE
;
1597 grub_mm_check_real (char *file
, int line
)
1600 grub_mm_header_t p
, pa
;
1602 for (r
= grub_mm_base
; r
; r
= r
->next
)
1606 if (p
->magic
== GRUB_MM_ALLOC_MAGIC
)
1610 if ((grub_addr_t
) p
< (grub_addr_t
) (r
+ 1)
1611 || (grub_addr_t
) p
>= (grub_addr_t
) (r
+ 1) + r
->size
)
1612 grub_fatal ("%s:%d: out of range pointer: %p\n", file
, line
, p
);
1613 if (p
->magic
!= GRUB_MM_FREE_MAGIC
)
1614 grub_fatal ("%s:%d free magic broken at %p (0x%x)\n", file
,
1619 while (pa
!= r
->first
);