diff --git a/include/grub/i386/memory.h b/include/grub/i386/memory.h index fe2f6e4e1..4f9a3c916 100644 --- a/include/grub/i386/memory.h +++ b/include/grub/i386/memory.h @@ -28,4 +28,28 @@ #define GRUB_MEMORY_CPU_AMD64_MSR 0xc0000080 #define GRUB_MEMORY_CPU_AMD64_MSR_ON 0x00000100 +#ifndef ASM_FILE + +typedef grub_addr_t grub_phys_addr_t; + +static inline grub_phys_addr_t +grub_vtop (void *a) +{ + return (grub_phys_addr_t) a; +} + +static inline void * +grub_map_memory (grub_phys_addr_t a, grub_size_t size __attribute__ ((unused))) +{ + return (void *) a; +} + +static inline void +grub_unmap_memory (void *a __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} + +#endif + #endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/include/grub/relocator_private.h b/include/grub/relocator_private.h index a859ec9fd..d12a0f05a 100644 --- a/include/grub/relocator_private.h +++ b/include/grub/relocator_private.h @@ -31,8 +31,9 @@ extern grub_size_t grub_relocator_jumper_size; void grub_cpu_relocator_init (void); grub_err_t -grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr, - grub_addr_t *relstart, grub_size_t *relsize); +grub_relocator_prepare_relocs (struct grub_relocator *rel, + void *addr, + void **relstart, grub_size_t *relsize); void grub_cpu_relocator_forward (void *rels, void *src, void *tgt, grub_size_t size); void grub_cpu_relocator_backward (void *rels, void *src, void *tgt, @@ -72,7 +73,7 @@ struct grub_relocator_mmap_event COLLISION_START = 10, COLLISION_END = COLLISION_START | 1 } type; - grub_addr_t pos; + grub_phys_addr_t pos; union { struct @@ -91,10 +92,12 @@ struct grub_relocator_mmap_event /* Return 0 on failure, 1 on success. The failure here can be very time-expensive, so please make sure fill events is accurate. */ #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS -int grub_relocator_firmware_alloc_region (grub_addr_t start, grub_size_t size); +int grub_relocator_firmware_alloc_region (grub_phys_addr_t start, + grub_size_t size); unsigned grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events); unsigned grub_relocator_firmware_get_max_events (void); -void grub_relocator_firmware_free_region (grub_addr_t start, grub_size_t size); +void grub_relocator_firmware_free_region (grub_phys_addr_t start, + grub_size_t size); #endif #endif diff --git a/lib/i386/relocator.c b/lib/i386/relocator.c index 5985fac7a..5dd4cde75 100644 --- a/lib/i386/relocator.c +++ b/lib/i386/relocator.c @@ -84,6 +84,12 @@ grub_size_t grub_relocator_jumper_size = 12; grub_size_t grub_relocator_jumper_size = 7; #endif +static inline void * +ptov (grub_addr_t a) +{ + return (void *) a; +} + void grub_cpu_relocator_init (void) { @@ -148,10 +154,10 @@ grub_err_t grub_relocator32_boot (struct grub_relocator *rel, struct grub_relocator32_state state) { - grub_addr_t target; + grub_phys_addr_t target; void *src; grub_err_t err; - grub_addr_t relst; + void *relst; err = grub_relocator_alloc_chunk_align (rel, &src, &target, 0, (0xffffffff - RELOCATOR_SIZEOF (32)) @@ -170,7 +176,7 @@ grub_relocator32_boot (struct grub_relocator *rel, grub_memmove (src, &grub_relocator32_start, RELOCATOR_SIZEOF (32)); - err = grub_relocator_prepare_relocs (rel, target, &relst, NULL); + err = grub_relocator_prepare_relocs (rel, ptov (target), &relst, NULL); if (err) return err; @@ -185,10 +191,10 @@ grub_err_t grub_relocator16_boot (struct grub_relocator *rel, struct grub_relocator16_state state) { - grub_addr_t target; + grub_phys_addr_t target; void *src; grub_err_t err; - grub_addr_t relst; + void *relst; err = grub_relocator_alloc_chunk_align (rel, &src, &target, 0, 0xa0000 - RELOCATOR_SIZEOF (16), @@ -212,7 +218,7 @@ grub_relocator16_boot (struct grub_relocator *rel, grub_memmove (src, &grub_relocator16_start, RELOCATOR_SIZEOF (16)); - err = grub_relocator_prepare_relocs (rel, target, &relst, NULL); + err = grub_relocator_prepare_relocs (rel, ptov (target), &relst, NULL); if (err) return err; @@ -228,10 +234,10 @@ grub_relocator64_boot (struct grub_relocator *rel, struct grub_relocator64_state state, grub_addr_t min_addr, grub_addr_t max_addr) { - grub_addr_t target; + grub_phys_addr_t target; void *src; grub_err_t err; - grub_addr_t relst; + void *relst; err = grub_relocator_alloc_chunk_align (rel, &src, &target, min_addr, max_addr - RELOCATOR_SIZEOF (64), @@ -251,7 +257,7 @@ grub_relocator64_boot (struct grub_relocator *rel, grub_memmove (src, &grub_relocator64_start, RELOCATOR_SIZEOF (64)); - err = grub_relocator_prepare_relocs (rel, target, &relst, NULL); + err = grub_relocator_prepare_relocs (rel, ptov (target), &relst, NULL); if (err) return err; diff --git a/lib/relocator.c b/lib/relocator.c index 127b80533..b559d12ea 100644 --- a/lib/relocator.c +++ b/lib/relocator.c @@ -26,9 +26,9 @@ struct grub_relocator { struct grub_relocator_chunk *chunks; - grub_addr_t postchunks; - grub_addr_t highestaddr; - grub_addr_t highestnonpostaddr; + grub_phys_addr_t postchunks; + grub_phys_addr_t highestaddr; + grub_phys_addr_t highestnonpostaddr; grub_size_t relocators_size; }; @@ -39,9 +39,11 @@ struct grub_relocator_subchunk CHUNK_TYPE_FIRMWARE, CHUNK_TYPE_LEFTOVER #endif } type; - grub_addr_t host_start; - grub_addr_t start; + grub_mm_region_t reg; + grub_mm_header_t head; + grub_phys_addr_t start; grub_size_t size; + grub_size_t pre_size; struct grub_relocator_extra_block *extra; struct grub_relocator_fw_leftover *pre, *post; }; @@ -49,8 +51,9 @@ struct grub_relocator_subchunk struct grub_relocator_chunk { struct grub_relocator_chunk *next; - grub_addr_t src; - grub_addr_t target; + grub_phys_addr_t src; + void *srcv; + grub_phys_addr_t target; grub_size_t size; struct grub_relocator_subchunk *subchunks; unsigned nsubchunks; @@ -60,8 +63,8 @@ struct grub_relocator_extra_block { struct grub_relocator_extra_block *next; struct grub_relocator_extra_block **prev; - grub_addr_t start; - grub_addr_t end; + grub_phys_addr_t start; + grub_phys_addr_t end; }; #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS @@ -69,7 +72,7 @@ struct grub_relocator_fw_leftover { struct grub_relocator_fw_leftover *next; struct grub_relocator_fw_leftover **prev; - grub_addr_t quantstart; + grub_phys_addr_t quantstart; grub_uint8_t freebytes[GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT / 8]; }; @@ -89,7 +92,7 @@ grub_relocator_new (void) if (!ret) return NULL; - ret->postchunks = ~(grub_addr_t) 0; + ret->postchunks = ~(grub_phys_addr_t) 0; ret->relocators_size = grub_relocator_jumper_size; grub_dprintf ("relocator", "relocators_size=%lu\n", (unsigned long) ret->relocators_size); @@ -110,10 +113,11 @@ is_start (int type) } static void -allocate_regstart (grub_addr_t addr, grub_size_t size, grub_mm_region_t rb, +allocate_regstart (grub_phys_addr_t addr, grub_size_t size, grub_mm_region_t rb, grub_mm_region_t *regancestor, grub_mm_header_t hancestor) { - grub_addr_t newreg_start, newreg_raw_start = addr + size; + grub_addr_t newreg_start, newreg_raw_start + = (grub_addr_t) rb + (addr - grub_vtop (rb)) + size; grub_addr_t newreg_size, newreg_presize; grub_mm_header_t new_header; grub_mm_header_t hb = (grub_mm_header_t) (rb + 1); @@ -176,23 +180,24 @@ allocate_regstart (grub_addr_t addr, grub_size_t size, grub_mm_region_t rb, } static void -allocate_inreg (grub_addr_t addr, grub_size_t size, +allocate_inreg (grub_phys_addr_t paddr, grub_size_t size, grub_mm_header_t hb, grub_mm_header_t hbp, grub_mm_region_t rb) { struct grub_mm_header *foll = NULL; + grub_addr_t vaddr = (grub_addr_t) hb + (paddr - grub_vtop (hb)); - if (ALIGN_UP (addr + size, GRUB_MM_ALIGN) + GRUB_MM_ALIGN + if (ALIGN_UP (vaddr + size, GRUB_MM_ALIGN) + GRUB_MM_ALIGN <= (grub_addr_t) (hb + hb->size)) { - foll = (void *) ALIGN_UP (addr + size, GRUB_MM_ALIGN); + foll = (void *) ALIGN_UP (vaddr + size, GRUB_MM_ALIGN); foll->magic = GRUB_MM_FREE_MAGIC; foll->size = hb->size - (foll - hb); } - if (addr - (grub_addr_t) hb >= sizeof (*hb)) + if (vaddr - (grub_addr_t) hb >= sizeof (*hb)) { - hb->size = ((addr - (grub_addr_t) hb) >> GRUB_MM_ALIGN_LOG2); + hb->size = ((vaddr - (grub_addr_t) hb) >> GRUB_MM_ALIGN_LOG2); if (foll) { foll->next = hb; @@ -250,12 +255,13 @@ free_subchunk (const struct grub_relocator_subchunk *subchu) grub_mm_region_t r1, r2, *rp; grub_mm_header_t h; grub_size_t pre_size; - r1 = (grub_mm_region_t) ALIGN_UP (subchu->host_start, GRUB_MM_ALIGN); - r2 = (grub_mm_region_t) ALIGN_UP (subchu->start + subchu->size, + r1 = subchu->reg; + r2 = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) subchu->reg + + (grub_vtop (subchu->reg) + - subchu->start) + subchu->size, GRUB_MM_ALIGN); for (rp = &grub_mm_base; *rp && *rp != r2; rp = &((*rp)->next)); - pre_size = ALIGN_UP (subchu->host_start, GRUB_MM_ALIGN) - - subchu->host_start; + pre_size = subchu->pre_size; if (*rp) { @@ -328,7 +334,7 @@ free_subchunk (const struct grub_relocator_subchunk *subchu) } case CHUNK_TYPE_IN_REGION: { - grub_mm_header_t h = (grub_mm_header_t) ALIGN_DOWN (subchu->start, + grub_mm_header_t h = (grub_mm_header_t) ALIGN_DOWN ((grub_addr_t) subchu->head, GRUB_MM_ALIGN); h->size = ((subchu->start + subchu->size + GRUB_MM_ALIGN - 1) / GRUB_MM_ALIGN) @@ -549,26 +555,26 @@ malloc_in_range (struct grub_relocator *rel, { pre_added = 1; events[N].type = REG_BEG_START; - events[N].pos = (grub_addr_t) r - r->pre_size; + events[N].pos = grub_vtop (r) - r->pre_size; events[N].reg = r; events[N].regancestor = ra; events[N].head = p; events[N].hancestor = pa; N++; events[N].type = REG_BEG_END; - events[N].pos = (grub_addr_t) (p + p->size) - sizeof (*r); + events[N].pos = grub_vtop (p + p->size) - sizeof (*r); N++; } else { events[N].type = IN_REG_START; - events[N].pos = (grub_addr_t) p; + events[N].pos = grub_vtop (p); events[N].head = p; events[N].hancestor = pa; events[N].reg = r; N++; events[N].type = IN_REG_END; - events[N].pos = (grub_addr_t) (p + p->size); + events[N].pos = grub_vtop (p + p->size); N++; } pa = p; @@ -862,20 +868,6 @@ malloc_in_range (struct grub_relocator *rel, } } - grub_memset ((void *) target, 0, size); - grub_dprintf ("relocator", "baseptr = %p\n", &base_saved); - for (r = base_saved; r; r = r->next) - { - p = r->first; - do - { - if (!p) - grub_fatal ("null in the ring %p\n", r); - p = p->next; - } - while (p != r->first); - } - /* Malloc is available again. */ grub_mm_base = base_saved; @@ -927,7 +919,13 @@ malloc_in_range (struct grub_relocator *rel, curschu->type = typepre; curschu->start = alloc_start; curschu->size = alloc_end - alloc_start; - if (typepre == CHUNK_TYPE_REGION_START) + if (typepre == CHUNK_TYPE_REGION_START + || typepre == CHUNK_TYPE_IN_REGION) + { + curschu->reg = events[last_start].reg; + curschu->head = events[last_start].head; + curschu->pre_size = alloc_start - events[j - 1].pos; + } if (!oom && (typepre == CHUNK_TYPE_REGION_START #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS || typepre == CHUNK_TYPE_FIRMWARE @@ -1106,8 +1104,8 @@ malloc_in_range (struct grub_relocator *rel, static void adjust_limits (struct grub_relocator *rel, - grub_addr_t *min_addr, grub_addr_t *max_addr, - grub_addr_t in_min, grub_addr_t in_max) + grub_phys_addr_t *min_addr, grub_phys_addr_t *max_addr, + grub_phys_addr_t in_min, grub_phys_addr_t in_max) { struct grub_relocator_chunk *chunk; @@ -1129,10 +1127,10 @@ adjust_limits (struct grub_relocator *rel, grub_err_t grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, void **src, - grub_addr_t target, grub_size_t size) + grub_phys_addr_t target, grub_size_t size) { struct grub_relocator_chunk *chunk; - grub_addr_t min_addr = 0, max_addr; + grub_phys_addr_t min_addr = 0, max_addr; if (target > ~size) return grub_error (GRUB_ERR_OUT_OF_RANGE, "address is out of range"); @@ -1223,14 +1221,15 @@ grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, void **src, grub_dprintf ("relocator", "cur = %p, next = %p\n", rel->chunks, rel->chunks->next); - *src = (void *) chunk->src; + *src = chunk->srcv = grub_map_memory (chunk->src, chunk->size); return GRUB_ERR_NONE; } grub_err_t grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src, - grub_addr_t *target, - grub_addr_t min_addr, grub_addr_t max_addr, + grub_phys_addr_t *target, + grub_phys_addr_t min_addr, + grub_phys_addr_t max_addr, grub_size_t size, grub_size_t align, int preference) { @@ -1354,7 +1353,7 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src, rel->chunks = chunk; grub_dprintf ("relocator", "cur = %p, next = %p\n", rel->chunks, rel->chunks->next); - *src = (void *) chunk->src; + *src = chunk->srcv = grub_map_memory (chunk->src, chunk->size); *target = chunk->target; return GRUB_ERR_NONE; } @@ -1370,6 +1369,7 @@ grub_relocator_unload (struct grub_relocator *rel) unsigned i; for (i = 0; i < chunk->nsubchunks; i++) free_subchunk (&chunk->subchunks[i]); + grub_unmap_memory (chunk->srcv, chunk->size); next = chunk->next; grub_free (chunk->subchunks); grub_free (chunk); @@ -1378,11 +1378,11 @@ grub_relocator_unload (struct grub_relocator *rel) } grub_err_t -grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr, - grub_addr_t *relstart, grub_size_t *relsize) +grub_relocator_prepare_relocs (struct grub_relocator *rel, void *addr, + void **relstart, grub_size_t *relsize) { - grub_addr_t rels; - grub_addr_t rels0; + grub_uint8_t *rels; + grub_uint8_t *rels0; struct grub_relocator_chunk *sorted; grub_size_t nchunks = 0; unsigned j; @@ -1395,7 +1395,7 @@ grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr, grub_relocator_align, rel->relocators_size, &movers_chunk, 1, 1)) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); - rels = rels0 = movers_chunk.src; + rels = rels0 = movers_chunk.srcv; if (relsize) *relsize = rel->relocators_size; @@ -1463,23 +1463,25 @@ grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr, if (sorted[j].src < sorted[j].target) { grub_cpu_relocator_backward ((void *) rels, - (void *) sorted[j].src, - (void *) sorted[j].target, + sorted[j].srcv, + grub_map_memory (sorted[j].target, + sorted[j].size), sorted[j].size); rels += grub_relocator_backward_size; } if (sorted[j].src > sorted[j].target) { grub_cpu_relocator_forward ((void *) rels, - (void *) sorted[j].src, - (void *) sorted[j].target, + sorted[j].srcv, + grub_map_memory (sorted[j].target, + sorted[j].size), sorted[j].size); rels += grub_relocator_forward_size; } if (sorted[j].src == sorted[j].target) - grub_arch_sync_caches ((void *) sorted[j].src, sorted[j].size); + grub_arch_sync_caches (sorted[j].srcv, sorted[j].size); } - grub_cpu_relocator_jumper ((void *) rels, addr); + grub_cpu_relocator_jumper ((void *) rels, (grub_addr_t) addr); *relstart = rels0; grub_free (sorted); return GRUB_ERR_NONE;