First part of virtual addr support in relocator

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-04-21 15:25:49 +02:00
parent ba2f141cb5
commit 368c17f85d
4 changed files with 110 additions and 75 deletions

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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;