First version of allocation from firmware
This commit is contained in:
parent
accbdc88a5
commit
3a5768645c
5 changed files with 440 additions and 147 deletions
|
@ -16,9 +16,16 @@ vga_text_mod_CFLAGS = $(COMMON_CFLAGS)
|
|||
vga_text_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
|
||||
pkglib_MODULES += relocator.mod
|
||||
ifeq ($(platform), ieee1275)
|
||||
relocator_mod_SOURCES = lib/relocator.c lib/i386/relocator32.S \
|
||||
lib/i386/relocator64.S lib/i386/relocator16.S \
|
||||
lib/$(target_cpu)/relocator_asm.S lib/i386/relocator.c \
|
||||
lib/ieee1275/relocator.c
|
||||
else
|
||||
relocator_mod_SOURCES = lib/relocator.c lib/i386/relocator32.S \
|
||||
lib/i386/relocator64.S lib/i386/relocator16.S \
|
||||
lib/$(target_cpu)/relocator_asm.S lib/i386/relocator.c
|
||||
endif
|
||||
relocator_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
relocator_mod_ASFLAGS = $(COMMON_ASFLAGS)
|
||||
relocator_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <grub/types.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm_private.h>
|
||||
|
||||
extern grub_size_t grub_relocator_align;
|
||||
extern grub_size_t grub_relocator_forward_size;
|
||||
|
@ -38,4 +39,49 @@ void grub_cpu_relocator_backward (void *rels, void *src, void *tgt,
|
|||
grub_size_t size);
|
||||
void grub_cpu_relocator_jumper (void *rels, grub_addr_t addr);
|
||||
|
||||
#ifdef GRUB_MACHINE_IEEE1275
|
||||
#define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 1
|
||||
#else
|
||||
#define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 0
|
||||
#endif
|
||||
|
||||
struct grub_relocator_mmap_event
|
||||
{
|
||||
enum {
|
||||
IN_REG_START = 0,
|
||||
IN_REG_END = 1,
|
||||
REG_BEG_START = 2,
|
||||
REG_BEG_END = REG_BEG_START | 1,
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
REG_FIRMWARE_START = 4,
|
||||
REG_FIRMWARE_END = REG_FIRMWARE_START | 1,
|
||||
/* To track the regions already in heap. */
|
||||
FIRMWARE_BLOCK_START = 6,
|
||||
FIRMWARE_BLOCK_END = FIRMWARE_BLOCK_START | 1,
|
||||
#endif
|
||||
COLLISION_START = 8,
|
||||
COLLISION_END = COLLISION_START | 1
|
||||
} type;
|
||||
grub_addr_t pos;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
grub_mm_region_t reg;
|
||||
grub_mm_header_t hancestor;
|
||||
grub_mm_region_t *regancestor;
|
||||
grub_mm_header_t head;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -253,6 +253,7 @@ grub_relocator64_boot (struct grub_relocator *rel,
|
|||
return err;
|
||||
|
||||
asm volatile ("cli");
|
||||
grub_printf ("%x\n", relst);
|
||||
((void (*) (void)) relst) ();
|
||||
|
||||
/* Not reached. */
|
||||
|
|
83
lib/ieee1275/relocator.c
Normal file
83
lib/ieee1275/relocator.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/relocator.h>
|
||||
#include <grub/relocator_private.h>
|
||||
#include <grub/memory.h>
|
||||
#include <grub/ieee1275/ieee1275.h>
|
||||
|
||||
unsigned
|
||||
grub_relocator_firmware_get_max_events (void)
|
||||
{
|
||||
int counter = 0;
|
||||
auto int NESTED_FUNC_ATTR count (grub_uint64_t addr __attribute__ ((unused)),
|
||||
grub_uint64_t len __attribute__ ((unused)),
|
||||
grub_uint32_t type __attribute__ ((unused)));
|
||||
int NESTED_FUNC_ATTR count (grub_uint64_t addr __attribute__ ((unused)),
|
||||
grub_uint64_t len __attribute__ ((unused)),
|
||||
grub_uint32_t type __attribute__ ((unused)))
|
||||
{
|
||||
counter++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET))
|
||||
return 0;
|
||||
grub_machine_mmap_iterate (count);
|
||||
return 2 * counter;
|
||||
}
|
||||
|
||||
unsigned
|
||||
grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events)
|
||||
{
|
||||
int counter = 0;
|
||||
auto int NESTED_FUNC_ATTR fill (grub_uint64_t addr, grub_uint64_t len,
|
||||
grub_uint32_t type);
|
||||
int NESTED_FUNC_ATTR fill (grub_uint64_t addr, grub_uint64_t len,
|
||||
grub_uint32_t type)
|
||||
{
|
||||
if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
|
||||
return 0;
|
||||
|
||||
events[counter].type = REG_FIRMWARE_START;
|
||||
events[counter].pos = addr;
|
||||
counter++;
|
||||
events[counter].type = REG_FIRMWARE_END;
|
||||
events[counter].pos = addr + len;
|
||||
counter++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET))
|
||||
return 0;
|
||||
grub_machine_mmap_iterate (fill);
|
||||
return counter;
|
||||
}
|
||||
|
||||
int
|
||||
grub_relocator_firmware_alloc_region (grub_addr_t start, grub_size_t size)
|
||||
{
|
||||
return (grub_claimmap (start, size) >= 0);
|
||||
}
|
||||
|
||||
void
|
||||
grub_relocator_firmware_free_region (grub_addr_t start, grub_size_t size)
|
||||
{
|
||||
grub_ieee1275_release (start, size);
|
||||
}
|
450
lib/relocator.c
450
lib/relocator.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -23,7 +23,6 @@
|
|||
#include <grub/cache.h>
|
||||
|
||||
/* FIXME: check memory map. */
|
||||
/* FIXME: try to request memory from firmware. */
|
||||
|
||||
struct grub_relocator
|
||||
{
|
||||
|
@ -36,7 +35,11 @@ struct grub_relocator
|
|||
|
||||
struct grub_relocator_subchunk
|
||||
{
|
||||
enum {CHUNK_TYPE_IN_REGION, CHUNK_TYPE_REGION_START} type;
|
||||
enum {CHUNK_TYPE_IN_REGION, CHUNK_TYPE_REGION_START,
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
CHUNK_TYPE_FIRMWARE
|
||||
#endif
|
||||
} type;
|
||||
grub_addr_t host_start;
|
||||
grub_addr_t start;
|
||||
grub_size_t size;
|
||||
|
@ -52,6 +55,15 @@ struct grub_relocator_chunk
|
|||
unsigned nsubchunks;
|
||||
};
|
||||
|
||||
struct grub_relocator_extra_block
|
||||
{
|
||||
struct grub_relocator_extra_block *next;
|
||||
grub_addr_t start;
|
||||
grub_addr_t end;
|
||||
};
|
||||
|
||||
struct grub_relocator_extra_block *extra_blocks;
|
||||
|
||||
struct grub_relocator *
|
||||
grub_relocator_new (void)
|
||||
{
|
||||
|
@ -70,29 +82,6 @@ grub_relocator_new (void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct event
|
||||
{
|
||||
enum {
|
||||
IN_REG_START = 0,
|
||||
IN_REG_END = 1,
|
||||
REG_BEG_START = 2,
|
||||
REG_BEG_END = REG_BEG_START | 1,
|
||||
COLLISION_START = 4,
|
||||
COLLISION_END = COLLISION_START | 1
|
||||
} type;
|
||||
grub_addr_t pos;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
grub_mm_region_t reg;
|
||||
grub_mm_header_t hancestor;
|
||||
grub_mm_region_t *regancestor;
|
||||
grub_mm_header_t head;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#define DIGITSORT_BITS 8
|
||||
#define DIGITSORT_MASK ((1 << DIGITSORT_BITS) - 1)
|
||||
#define BITS_IN_BYTE 8
|
||||
|
@ -221,7 +210,7 @@ malloc_in_range (struct grub_relocator *rel,
|
|||
int from_low_priv, int collisioncheck)
|
||||
{
|
||||
grub_mm_region_t r, *ra, base_saved;
|
||||
struct event *events = NULL, *eventt = NULL, *t;
|
||||
struct grub_relocator_mmap_event *events = NULL, *eventt = NULL, *t;
|
||||
unsigned maxevents = 2;
|
||||
grub_mm_header_t p, pa;
|
||||
unsigned *counter;
|
||||
|
@ -254,7 +243,7 @@ malloc_in_range (struct grub_relocator *rel,
|
|||
p = p->next;
|
||||
}
|
||||
while (p != r->first);
|
||||
maxevents += 2;
|
||||
maxevents += 4;
|
||||
}
|
||||
if (collisioncheck && rel)
|
||||
{
|
||||
|
@ -263,6 +252,16 @@ malloc_in_range (struct grub_relocator *rel,
|
|||
maxevents += 2;
|
||||
}
|
||||
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
{
|
||||
struct grub_relocator_extra_block *cur;
|
||||
for (cur = extra_blocks; cur; cur = cur->next)
|
||||
maxevents += 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
maxevents += grub_relocator_firmware_get_max_events ();
|
||||
|
||||
events = grub_malloc (maxevents * sizeof (events[0]));
|
||||
eventt = grub_malloc (maxevents * sizeof (events[0]));
|
||||
counter = grub_malloc ((DIGITSORT_MASK + 2) * sizeof (counter[0]));
|
||||
|
@ -290,6 +289,35 @@ malloc_in_range (struct grub_relocator *rel,
|
|||
}
|
||||
}
|
||||
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
for (r = grub_mm_base; r; r = r->next)
|
||||
{
|
||||
grub_dprintf ("relocator", "Blocking at 0x%x-0x%x\n",
|
||||
(grub_addr_t) r - r->pre_size,
|
||||
(grub_addr_t) (r + 1) + r->size);
|
||||
events[N].type = FIRMWARE_BLOCK_START;
|
||||
events[N].pos = (grub_addr_t) r - r->pre_size;
|
||||
N++;
|
||||
events[N].type = FIRMWARE_BLOCK_END;
|
||||
events[N].pos = (grub_addr_t) (r + 1) + r->size;
|
||||
N++;
|
||||
}
|
||||
{
|
||||
struct grub_relocator_extra_block *cur;
|
||||
for (cur = extra_blocks; cur; cur = cur->next)
|
||||
{
|
||||
grub_dprintf ("relocator", "Blocking at 0x%x-0x%x\n",
|
||||
cur->start, cur->end);
|
||||
events[N].type = FIRMWARE_BLOCK_START;
|
||||
events[N].pos = cur->start;
|
||||
N++;
|
||||
events[N].type = FIRMWARE_BLOCK_END;
|
||||
events[N].pos = cur->end;
|
||||
N++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No malloc from this point. */
|
||||
base_saved = grub_mm_base;
|
||||
grub_mm_base = NULL;
|
||||
|
@ -344,6 +372,8 @@ malloc_in_range (struct grub_relocator *rel,
|
|||
}
|
||||
}
|
||||
|
||||
N += grub_relocator_firmware_fill_events (events + N);
|
||||
|
||||
/* Put ending events after starting events. */
|
||||
{
|
||||
int st = 0, e = N / 2;
|
||||
|
@ -373,104 +403,86 @@ malloc_in_range (struct grub_relocator *rel,
|
|||
events = t;
|
||||
}
|
||||
|
||||
grub_dprintf ("relocator", "scanline events:\n");
|
||||
for (j = 0; j < N; j++)
|
||||
grub_dprintf ("relocator", "event %x, type %d\n", events[j].pos,
|
||||
events[j].type);
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
retry:
|
||||
#endif
|
||||
|
||||
/* Now events are nicely sorted. */
|
||||
if (from_low_priv)
|
||||
{
|
||||
int nstarted = 0, ncollisions = 0;
|
||||
grub_addr_t starta = 0;
|
||||
int numstarted;
|
||||
for (j = 0; j < N; j++)
|
||||
{
|
||||
switch (events[j].type)
|
||||
{
|
||||
case COLLISION_END:
|
||||
ncollisions--;
|
||||
case IN_REG_START:
|
||||
case REG_BEG_START:
|
||||
if ((events[j].type == COLLISION_END ? nstarted != 0
|
||||
: nstarted == 0)
|
||||
&& ncollisions == 0)
|
||||
{
|
||||
starta = ALIGN_UP (events[j].pos, align);
|
||||
numstarted = j;
|
||||
}
|
||||
if (events[j].type != COLLISION_END)
|
||||
nstarted++;
|
||||
break;
|
||||
{
|
||||
int nstarted = 0, ncollisions = 0, nstartedfw = 0, nblockfw = 0;
|
||||
grub_addr_t starta = 0;
|
||||
int numstarted;
|
||||
for (j = from_low_priv ? 0 : N - 1; from_low_priv ? j < N : (j + 1);
|
||||
from_low_priv ? j++ : j--)
|
||||
{
|
||||
int isinsidebefore, isinsideafter;
|
||||
isinsidebefore = (!ncollisions
|
||||
&& (nstarted || (nstartedfw && !nblockfw)));
|
||||
switch (events[j].type)
|
||||
{
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
case REG_FIRMWARE_START:
|
||||
nstartedfw++;
|
||||
break;
|
||||
|
||||
case IN_REG_END:
|
||||
case REG_BEG_END:
|
||||
nstarted--;
|
||||
case COLLISION_START:
|
||||
if (((events[j].type == COLLISION_START)
|
||||
? nstarted != 0 : nstarted == 0)
|
||||
&& ncollisions == 0)
|
||||
{
|
||||
target = starta;
|
||||
if (target < start)
|
||||
target = start;
|
||||
grub_dprintf ("relocator", "%x, %x, %x\n", target, start,
|
||||
events[j].pos);
|
||||
if (target + size <= end && target + size <= events[j].pos)
|
||||
/* Found an usable address. */
|
||||
goto found;
|
||||
}
|
||||
if (events[j].type == COLLISION_START)
|
||||
ncollisions++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int nstarted = 0, ncollisions = 0;
|
||||
grub_addr_t enda = 0;
|
||||
int numend;
|
||||
for (j = N - 1; j != (unsigned) -1; j--)
|
||||
{
|
||||
switch (events[j].type)
|
||||
{
|
||||
case COLLISION_START:
|
||||
ncollisions--;
|
||||
case IN_REG_END:
|
||||
case REG_BEG_END:
|
||||
if ((events[j].type == COLLISION_END ? nstarted != 0
|
||||
: nstarted == 0)
|
||||
&& ncollisions == 0)
|
||||
{
|
||||
enda = ALIGN_DOWN (events[j].pos - size, align) + size;
|
||||
numend = j;
|
||||
}
|
||||
nstarted++;
|
||||
break;
|
||||
case REG_FIRMWARE_END:
|
||||
nstartedfw--;
|
||||
break;
|
||||
|
||||
case IN_REG_START:
|
||||
case REG_BEG_START:
|
||||
nstarted--;
|
||||
case COLLISION_END:
|
||||
if ((events[j].type == COLLISION_START ? nstarted != 0
|
||||
: nstarted == 0)
|
||||
&& ncollisions == 0)
|
||||
{
|
||||
target = enda - size;
|
||||
if (target > end - size)
|
||||
target = end - size;
|
||||
grub_dprintf ("relocator", "%x, %x, %x\n", target, start,
|
||||
events[j].pos);
|
||||
if (target >= start && target >= events[j].pos)
|
||||
goto found;
|
||||
}
|
||||
if (events[j].type == COLLISION_START)
|
||||
ncollisions++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
case FIRMWARE_BLOCK_START:
|
||||
nblockfw++;
|
||||
break;
|
||||
|
||||
case FIRMWARE_BLOCK_END:
|
||||
nblockfw--;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case COLLISION_START:
|
||||
ncollisions++;
|
||||
break;
|
||||
|
||||
case COLLISION_END:
|
||||
ncollisions--;
|
||||
break;
|
||||
|
||||
case IN_REG_START:
|
||||
case REG_BEG_START:
|
||||
nstarted++;
|
||||
break;
|
||||
|
||||
case IN_REG_END:
|
||||
case REG_BEG_END:
|
||||
nstarted--;
|
||||
break;
|
||||
}
|
||||
isinsideafter = (!ncollisions
|
||||
&& (nstarted || (nstartedfw && !nblockfw)));
|
||||
if (!isinsidebefore && isinsideafter)
|
||||
{
|
||||
starta = from_low_priv ? ALIGN_UP (events[j].pos, align)
|
||||
: ALIGN_DOWN (events[j].pos - size, align) + size;
|
||||
numstarted = j;
|
||||
}
|
||||
if (isinsidebefore && !isinsideafter && from_low_priv)
|
||||
{
|
||||
target = starta;
|
||||
if (target < start)
|
||||
target = start;
|
||||
if (target + size <= end && target + size <= events[j].pos)
|
||||
/* Found an usable address. */
|
||||
goto found;
|
||||
}
|
||||
if (isinsidebefore && !isinsideafter && !from_low_priv)
|
||||
{
|
||||
target = starta - size;
|
||||
if (target > end - size)
|
||||
target = end - size;
|
||||
if (target >= start && target >= events[j].pos)
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grub_mm_base = base_saved;
|
||||
grub_free (events);
|
||||
|
@ -480,9 +492,24 @@ malloc_in_range (struct grub_relocator *rel,
|
|||
|
||||
found:
|
||||
{
|
||||
int inreg = 0, regbeg = 0, fwin = 0, fwb = 0, ncol = 0;
|
||||
int last_start = 0;
|
||||
for (j = 0; j < N; j++)
|
||||
{
|
||||
int typepre;
|
||||
if (ncol)
|
||||
typepre = -1;
|
||||
else if (regbeg)
|
||||
typepre = CHUNK_TYPE_REGION_START;
|
||||
else if (inreg)
|
||||
typepre = CHUNK_TYPE_IN_REGION;
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
else if (fwin && !fwb)
|
||||
typepre = CHUNK_TYPE_FIRMWARE;
|
||||
#endif
|
||||
else
|
||||
typepre = -1;
|
||||
|
||||
if (j != 0 && events[j - 1].pos != events[j].pos)
|
||||
{
|
||||
grub_addr_t alloc_start, alloc_end;
|
||||
|
@ -490,28 +517,84 @@ malloc_in_range (struct grub_relocator *rel,
|
|||
alloc_end = min (events[j].pos, target + size);
|
||||
if (alloc_end > alloc_start)
|
||||
{
|
||||
grub_dprintf ("relocator", "%d\n", last_start);
|
||||
|
||||
if (events[last_start].type == REG_BEG_START
|
||||
|| events[last_start].type == IN_REG_START)
|
||||
switch (typepre)
|
||||
{
|
||||
if (events[last_start].type == REG_BEG_START &&
|
||||
(grub_addr_t) (events[last_start].reg + 1) > target)
|
||||
allocate_regstart (alloc_start, alloc_end - alloc_start,
|
||||
events[last_start].reg,
|
||||
events[last_start].regancestor,
|
||||
events[last_start].hancestor);
|
||||
else
|
||||
allocate_inreg (alloc_start, alloc_end - alloc_start,
|
||||
events[last_start].head,
|
||||
events[last_start].hancestor,
|
||||
events[last_start].reg);
|
||||
case CHUNK_TYPE_REGION_START:
|
||||
allocate_regstart (alloc_start, alloc_end - alloc_start,
|
||||
events[last_start].reg,
|
||||
events[last_start].regancestor,
|
||||
events[last_start].hancestor);
|
||||
break;
|
||||
case CHUNK_TYPE_IN_REGION:
|
||||
allocate_inreg (alloc_start, alloc_end - alloc_start,
|
||||
events[last_start].head,
|
||||
events[last_start].hancestor,
|
||||
events[last_start].reg);
|
||||
break;
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
case CHUNK_TYPE_FIRMWARE:
|
||||
/* The failure here can be very expensive. */
|
||||
if (!grub_relocator_firmware_alloc_region (alloc_start,
|
||||
alloc_end - alloc_start))
|
||||
{
|
||||
grub_dprintf ("relocator",
|
||||
"firmware allocation 0x%x-0x%x failed.\n",
|
||||
alloc_start, alloc_end);
|
||||
if (from_low_priv)
|
||||
start = alloc_end;
|
||||
else
|
||||
end = alloc_start;
|
||||
goto retry;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
nallocs++;
|
||||
}
|
||||
}
|
||||
if (is_start (events[j].type))
|
||||
last_start = j;
|
||||
|
||||
switch (events[j].type)
|
||||
{
|
||||
case REG_BEG_START:
|
||||
case IN_REG_START:
|
||||
if (events[j].type == REG_BEG_START &&
|
||||
(grub_addr_t) (events[j].reg + 1) > target)
|
||||
regbeg++;
|
||||
else
|
||||
inreg++;
|
||||
last_start = j;
|
||||
break;
|
||||
|
||||
case REG_BEG_END:
|
||||
case IN_REG_END:
|
||||
inreg = regbeg = 0;
|
||||
break;
|
||||
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
case REG_FIRMWARE_START:
|
||||
fwin++;
|
||||
break;
|
||||
|
||||
case REG_FIRMWARE_END:
|
||||
fwin--;
|
||||
break;
|
||||
|
||||
case FIRMWARE_BLOCK_START:
|
||||
fwb++;
|
||||
break;
|
||||
|
||||
case FIRMWARE_BLOCK_END:
|
||||
fwb--;
|
||||
break;
|
||||
#endif
|
||||
case COLLISION_START:
|
||||
ncol++;
|
||||
break;
|
||||
case COLLISION_END:
|
||||
ncol--;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -538,9 +621,24 @@ malloc_in_range (struct grub_relocator *rel,
|
|||
|
||||
{
|
||||
int last_start = 0;
|
||||
int inreg = 0, regbeg = 0, fwin = 0, fwb = 0, ncol = 0;
|
||||
int cural = 0;
|
||||
for (j = 0; j < N; j++)
|
||||
{
|
||||
int typepre;
|
||||
if (ncol)
|
||||
typepre = -1;
|
||||
else if (regbeg)
|
||||
typepre = CHUNK_TYPE_REGION_START;
|
||||
else if (inreg)
|
||||
typepre = CHUNK_TYPE_IN_REGION;
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
else if (fwin && !fwb)
|
||||
typepre = CHUNK_TYPE_FIRMWARE;
|
||||
#endif
|
||||
else
|
||||
typepre = -1;
|
||||
|
||||
if (j != 0 && events[j - 1].pos != events[j].pos)
|
||||
{
|
||||
grub_addr_t alloc_start, alloc_end;
|
||||
|
@ -548,23 +646,76 @@ malloc_in_range (struct grub_relocator *rel,
|
|||
alloc_end = min (events[j].pos, target + size);
|
||||
if (alloc_end > alloc_start)
|
||||
{
|
||||
res->subchunks[cural].start = alloc_start;
|
||||
res->subchunks[cural].size = alloc_end - alloc_start;
|
||||
if (res->subchunks[last_start].type == IN_REG_START)
|
||||
res->subchunks[cural].type = CHUNK_TYPE_IN_REGION;
|
||||
else if (res->subchunks[last_start].type == REG_BEG_START)
|
||||
grub_dprintf ("relocator", "subchunk 0x%x-0x%x, %d\n",
|
||||
alloc_start, alloc_end, typepre);
|
||||
res->subchunks[cural].type = typepre;
|
||||
if (typepre == CHUNK_TYPE_REGION_START)
|
||||
{
|
||||
res->subchunks[cural].type = CHUNK_TYPE_REGION_START;
|
||||
res->subchunks[cural].host_start
|
||||
= (grub_addr_t) events[last_start].reg;
|
||||
}
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
if (typepre == CHUNK_TYPE_REGION_START
|
||||
|| typepre == CHUNK_TYPE_FIRMWARE)
|
||||
{
|
||||
/* FIXME: react on out of memory. */
|
||||
struct grub_relocator_extra_block *ne;
|
||||
ne = grub_malloc (sizeof (*ne));
|
||||
ne->start = alloc_start;
|
||||
ne->end = alloc_end;
|
||||
ne->next = extra_blocks;
|
||||
extra_blocks = ne;
|
||||
}
|
||||
#endif
|
||||
cural++;
|
||||
}
|
||||
}
|
||||
if (is_start (events[j].type))
|
||||
last_start = j;
|
||||
|
||||
switch (events[j].type)
|
||||
{
|
||||
case REG_BEG_START:
|
||||
case IN_REG_START:
|
||||
if (events[j].type == REG_BEG_START &&
|
||||
(grub_addr_t) (events[j].reg + 1) > target)
|
||||
regbeg++;
|
||||
else
|
||||
inreg++;
|
||||
last_start = j;
|
||||
break;
|
||||
|
||||
case REG_BEG_END:
|
||||
case IN_REG_END:
|
||||
inreg = regbeg = 0;
|
||||
break;
|
||||
|
||||
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
|
||||
case REG_FIRMWARE_START:
|
||||
fwin++;
|
||||
break;
|
||||
|
||||
case REG_FIRMWARE_END:
|
||||
fwin--;
|
||||
break;
|
||||
|
||||
case FIRMWARE_BLOCK_START:
|
||||
fwb++;
|
||||
break;
|
||||
|
||||
case FIRMWARE_BLOCK_END:
|
||||
fwb--;
|
||||
break;
|
||||
#endif
|
||||
case COLLISION_START:
|
||||
ncol++;
|
||||
break;
|
||||
case COLLISION_END:
|
||||
ncol--;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
res->src = target;
|
||||
res->size = size;
|
||||
grub_dprintf ("relocator", "allocated: %x %x\n", target, size);
|
||||
|
@ -801,6 +952,7 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src,
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* FIXME: remove extra blocks. */
|
||||
void
|
||||
grub_relocator_unload (struct grub_relocator *rel)
|
||||
{
|
||||
|
@ -856,6 +1008,10 @@ grub_relocator_unload (struct grub_relocator *rel)
|
|||
grub_free (h + 1);
|
||||
break;
|
||||
}
|
||||
case CHUNK_TYPE_FIRMWARE:
|
||||
grub_relocator_firmware_free_region (chunk->subchunks[i].start,
|
||||
chunk->subchunks[i].size);
|
||||
break;
|
||||
}
|
||||
next = chunk->next;
|
||||
grub_free (chunk->subchunks);
|
||||
|
|
Loading…
Reference in a new issue