Use leftovers

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-04-21 09:27:57 +02:00
parent 91b58e6b74
commit 6d6f55c557
3 changed files with 237 additions and 96 deletions

View file

@ -66,8 +66,10 @@ struct grub_relocator_mmap_event
/* To track the regions already in heap. */ /* To track the regions already in heap. */
FIRMWARE_BLOCK_START = 6, FIRMWARE_BLOCK_START = 6,
FIRMWARE_BLOCK_END = FIRMWARE_BLOCK_START | 1, FIRMWARE_BLOCK_END = FIRMWARE_BLOCK_START | 1,
REG_LEFTOVER_START = 8,
REG_LEFTOVER_END = REG_LEFTOVER_START | 1,
#endif #endif
COLLISION_START = 8, COLLISION_START = 10,
COLLISION_END = COLLISION_START | 1 COLLISION_END = COLLISION_START | 1
} type; } type;
grub_addr_t pos; grub_addr_t pos;
@ -80,6 +82,9 @@ struct grub_relocator_mmap_event
grub_mm_region_t *regancestor; grub_mm_region_t *regancestor;
grub_mm_header_t head; grub_mm_header_t head;
}; };
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
struct grub_relocator_fw_leftover *leftover;
#endif
}; };
}; };

View file

@ -35,7 +35,7 @@ struct grub_relocator_subchunk
{ {
enum {CHUNK_TYPE_IN_REGION, CHUNK_TYPE_REGION_START, enum {CHUNK_TYPE_IN_REGION, CHUNK_TYPE_REGION_START,
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
CHUNK_TYPE_FIRMWARE CHUNK_TYPE_FIRMWARE, CHUNK_TYPE_LEFTOVER
#endif #endif
} type; } type;
grub_addr_t host_start; grub_addr_t host_start;
@ -334,6 +334,7 @@ free_subchunk (const struct grub_relocator_subchunk *subchu)
} }
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
case CHUNK_TYPE_FIRMWARE: case CHUNK_TYPE_FIRMWARE:
case CHUNK_TYPE_LEFTOVER:
{ {
grub_addr_t fstart, fend; grub_addr_t fstart, fend;
fstart = ALIGN_UP (subchu->start, fstart = ALIGN_UP (subchu->start,
@ -375,11 +376,12 @@ malloc_in_range (struct grub_relocator *rel,
{ {
grub_mm_region_t r, *ra, base_saved; grub_mm_region_t r, *ra, base_saved;
struct grub_relocator_mmap_event *events = NULL, *eventt = NULL, *t; struct grub_relocator_mmap_event *events = NULL, *eventt = NULL, *t;
unsigned maxevents = 2; /* 128 is just in case of additional malloc (shouldn't happen). */
unsigned maxevents = 2 + 128;
grub_mm_header_t p, pa; grub_mm_header_t p, pa;
unsigned *counter; unsigned *counter;
int nallocs = 0; int nallocs = 0;
unsigned i, j, N = 0; unsigned j, N = 0;
grub_addr_t target = 0; grub_addr_t target = 0;
grub_dprintf ("relocator", grub_dprintf ("relocator",
@ -422,6 +424,23 @@ malloc_in_range (struct grub_relocator *rel,
} }
maxevents += grub_relocator_firmware_get_max_events (); maxevents += grub_relocator_firmware_get_max_events ();
{
struct grub_relocator_fw_leftover *cur;
for (cur = leftovers; cur; cur = cur->next)
{
int l = 0;
unsigned i;
for (i = 0; i < GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; i++)
{
if (l != ((cur->freebytes[i / 8] >> (i % 8)) & 1))
maxevents++;
l = ((cur->freebytes[i / 8] >> (i % 8)) & 1);
}
if (l)
maxevents++;
}
}
#endif #endif
events = grub_malloc (maxevents * sizeof (events[0])); events = grub_malloc (maxevents * sizeof (events[0]));
@ -478,10 +497,35 @@ malloc_in_range (struct grub_relocator *rel,
N++; N++;
} }
} }
#endif
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
N += grub_relocator_firmware_fill_events (events + N); N += grub_relocator_firmware_fill_events (events + N);
{
struct grub_relocator_fw_leftover *cur;
for (cur = leftovers; cur; cur = cur->next)
{
unsigned i;
int l = 0;
for (i = 0; i < GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; i++)
{
if (l != ((cur->freebytes[i / 8] >> (i % 8)) & 1))
{
events[N].type = l ? REG_LEFTOVER_END : REG_LEFTOVER_START;
events[N].pos = cur->quantstart + i;
events[N].leftover = cur;
N++;
}
l = ((cur->freebytes[i / 8] >> (i % 8)) & 1);
}
if (l)
{
events[N].type = REG_LEFTOVER_END;
events[N].pos = cur->quantstart + i;
events[N].leftover = cur;
N++;
}
}
}
#endif #endif
/* No malloc from this point. */ /* No malloc from this point. */
@ -539,22 +583,25 @@ malloc_in_range (struct grub_relocator *rel,
eventt = events; eventt = events;
events = t; events = t;
} }
for (i = 0; i < (BITS_IN_BYTE * sizeof (grub_addr_t) / DIGITSORT_BITS); {
i++) unsigned i;
{ for (i = 0; i < (BITS_IN_BYTE * sizeof (grub_addr_t) / DIGITSORT_BITS);
memset (counter, 0, (1 + (1 << DIGITSORT_BITS)) * sizeof (counter[0])); i++)
for (j = 0; j < N; j++) {
counter[((events[j].pos >> (DIGITSORT_BITS * i)) memset (counter, 0, (1 + (1 << DIGITSORT_BITS)) * sizeof (counter[0]));
& DIGITSORT_MASK) + 1]++; for (j = 0; j < N; j++)
for (j = 0; j <= DIGITSORT_MASK; j++) counter[((events[j].pos >> (DIGITSORT_BITS * i))
counter[j+1] += counter[j]; & DIGITSORT_MASK) + 1]++;
for (j = 0; j < N; j++) for (j = 0; j <= DIGITSORT_MASK; j++)
eventt[counter[((events[j].pos >> (DIGITSORT_BITS * i)) counter[j+1] += counter[j];
& DIGITSORT_MASK)]++] = events[j]; for (j = 0; j < N; j++)
t = eventt; eventt[counter[((events[j].pos >> (DIGITSORT_BITS * i))
eventt = events; & DIGITSORT_MASK)]++] = events[j];
events = t; t = eventt;
} eventt = events;
events = t;
}
}
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
retry: retry:
@ -563,14 +610,15 @@ malloc_in_range (struct grub_relocator *rel,
/* Now events are nicely sorted. */ /* Now events are nicely sorted. */
{ {
int nstarted = 0, ncollisions = 0, nstartedfw = 0, nblockfw = 0; int nstarted = 0, ncollisions = 0, nstartedfw = 0, nblockfw = 0;
int nlefto = 0;
grub_addr_t starta = 0; grub_addr_t starta = 0;
int numstarted; int numstarted;
for (j = from_low_priv ? 0 : N - 1; from_low_priv ? j < N : (j + 1); for (j = from_low_priv ? 0 : N - 1; from_low_priv ? j < N : (j + 1);
from_low_priv ? j++ : j--) from_low_priv ? j++ : j--)
{ {
int isinsidebefore, isinsideafter; int isinsidebefore, isinsideafter;
isinsidebefore = (!ncollisions isinsidebefore = (!ncollisions && (nstarted || (((nlefto || nstartedfw)
&& (nstarted || (nstartedfw && !nblockfw))); && !nblockfw))));
switch (events[j].type) switch (events[j].type)
{ {
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
@ -589,6 +637,13 @@ malloc_in_range (struct grub_relocator *rel,
case FIRMWARE_BLOCK_END: case FIRMWARE_BLOCK_END:
nblockfw--; nblockfw--;
break; break;
case REG_LEFTOVER_START:
nlefto++;
break;
case REG_LEFTOVER_END:
nlefto--;
break;
#endif #endif
case COLLISION_START: case COLLISION_START:
@ -609,8 +664,8 @@ malloc_in_range (struct grub_relocator *rel,
nstarted--; nstarted--;
break; break;
} }
isinsideafter = (!ncollisions isinsideafter = (!ncollisions && (nstarted || ((nlefto || nstartedfw)
&& (nstarted || (nstartedfw && !nblockfw))); && !nblockfw)));
if (!isinsidebefore && isinsideafter) if (!isinsidebefore && isinsideafter)
{ {
starta = from_low_priv ? ALIGN_UP (events[j].pos, align) starta = from_low_priv ? ALIGN_UP (events[j].pos, align)
@ -647,7 +702,7 @@ malloc_in_range (struct grub_relocator *rel,
{ {
int inreg = 0, regbeg = 0, ncol = 0; int inreg = 0, regbeg = 0, ncol = 0;
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
int fwin = 0, fwb = 0; int fwin = 0, fwb = 0, fwlefto = 0;
#endif #endif
int last_start = 0; int last_start = 0;
for (j = 0; j < N; j++) for (j = 0; j < N; j++)
@ -662,6 +717,8 @@ malloc_in_range (struct grub_relocator *rel,
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
else if (fwin && !fwb) else if (fwin && !fwb)
typepre = CHUNK_TYPE_FIRMWARE; typepre = CHUNK_TYPE_FIRMWARE;
else if (fwlefto && !fwb)
typepre = CHUNK_TYPE_LEFTOVER;
#endif #endif
else else
typepre = -1; typepre = -1;
@ -722,6 +779,21 @@ malloc_in_range (struct grub_relocator *rel,
} }
break; break;
} }
case CHUNK_TYPE_LEFTOVER:
{
unsigned offstart = alloc_start
% GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT;
unsigned offend = alloc_end
% GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT;
struct grub_relocator_fw_leftover *lo
= events[last_start].leftover;
lo->freebytes[offstart / 8]
&= ((1 << (8 - (start % 8))) - 1);
grub_memset (lo->freebytes + (offstart + 7) / 8, 0,
offend / 8 - (offstart + 7) / 8);
lo->freebytes[offend / 8] &= ~((1 << (offend % 8)) - 1);
}
break;
#endif #endif
} }
nallocs++; nallocs++;
@ -757,6 +829,14 @@ malloc_in_range (struct grub_relocator *rel,
fwin--; fwin--;
break; break;
case REG_LEFTOVER_START:
fwlefto++;
break;
case REG_LEFTOVER_END:
fwlefto--;
break;
case FIRMWARE_BLOCK_START: case FIRMWARE_BLOCK_START:
fwb++; fwb++;
break; break;
@ -797,7 +877,7 @@ malloc_in_range (struct grub_relocator *rel,
int last_start = 0; int last_start = 0;
int inreg = 0, regbeg = 0, ncol = 0; int inreg = 0, regbeg = 0, ncol = 0;
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
int fwin = 0, fwb = 0; int fwin = 0, fwlefto = 0, fwb = 0;
#endif #endif
unsigned cural = 0; unsigned cural = 0;
int oom = 0; int oom = 0;
@ -818,6 +898,8 @@ malloc_in_range (struct grub_relocator *rel,
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
else if (fwin && !fwb) else if (fwin && !fwb)
typepre = CHUNK_TYPE_FIRMWARE; typepre = CHUNK_TYPE_FIRMWARE;
else if (fwlefto && !fwb)
typepre = CHUNK_TYPE_LEFTOVER;
#endif #endif
else else
typepre = -1; typepre = -1;
@ -863,74 +945,80 @@ malloc_in_range (struct grub_relocator *rel,
} }
#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
if (!oom && typepre == CHUNK_TYPE_FIRMWARE) if (!oom && typepre == CHUNK_TYPE_FIRMWARE)
{ {
grub_addr_t fstart, fend; grub_addr_t fstart, fend;
struct grub_relocator_fw_leftover *lo1 = NULL; struct grub_relocator_fw_leftover *lo1 = NULL;
struct grub_relocator_fw_leftover *lo2 = NULL; struct grub_relocator_fw_leftover *lo2 = NULL;
fstart fstart
= ALIGN_DOWN (alloc_start, = ALIGN_DOWN (alloc_start,
GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT);
fend
= ALIGN_UP (alloc_end,
GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT);
fend
= ALIGN_UP (alloc_end,
GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT);
if (fstart != alloc_start) if (fstart != alloc_start)
lo1 = grub_malloc (sizeof (*lo1)); lo1 = grub_malloc (sizeof (*lo1));
if (fend != alloc_end) if (fend != alloc_end)
lo2 = grub_malloc (sizeof (*lo2)); lo2 = grub_malloc (sizeof (*lo2));
if ((!lo1 && fstart != alloc_start) if ((!lo1 && fstart != alloc_start)
|| (!lo2 && fend != alloc_end)) || (!lo2 && fend != alloc_end))
{ {
struct grub_relocator_extra_block *ne; struct grub_relocator_extra_block *ne;
grub_free (lo1); grub_free (lo1);
grub_free (lo2); grub_free (lo2);
lo1 = NULL; lo1 = NULL;
lo2 = NULL; lo2 = NULL;
oom = 1; oom = 1;
grub_memcpy (&tofree, curschu, sizeof (tofree)); grub_memcpy (&tofree, curschu, sizeof (tofree));
ne = extra_blocks; ne = extra_blocks;
extra_blocks = extra_blocks->next; extra_blocks = extra_blocks->next;
grub_free (ne); grub_free (ne);
} }
if (lo1) if (lo1)
{ {
lo1->quantstart = fstart; lo1->quantstart = fstart;
grub_memset (lo1->freebytes, 0xff, grub_memset (lo1->freebytes, 0xff,
(alloc_start - fstart) / 8); (alloc_start - fstart) / 8);
lo1->freebytes[(alloc_start - fstart) / 8] lo1->freebytes[(alloc_start - fstart) / 8]
= (1 << ((alloc_start - fstart) % 8)) - 1; = (1 << ((alloc_start - fstart) % 8)) - 1;
grub_memset (lo1->freebytes grub_memset (lo1->freebytes
+ ((alloc_start - fstart) / 8) + 1, 0, + ((alloc_start - fstart) / 8) + 1, 0,
sizeof (lo1->freebytes) sizeof (lo1->freebytes)
- (alloc_start - fstart) / 8 - 1); - (alloc_start - fstart) / 8 - 1);
lo1->next = leftovers; lo1->next = leftovers;
lo1->prev = &leftovers; lo1->prev = &leftovers;
if (leftovers) if (leftovers)
leftovers->prev = &lo1->next; leftovers->prev = &lo1->next;
leftovers = lo1; leftovers = lo1;
} }
if (lo2) if (lo2)
{ {
lo2->quantstart lo2->quantstart
= fend - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; = fend - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT;
grub_memset (lo2->freebytes, 0, grub_memset (lo2->freebytes, 0,
(alloc_end - lo2->quantstart) / 8); (alloc_end - lo2->quantstart) / 8);
lo2->freebytes[(alloc_end - lo2->quantstart) / 8] lo2->freebytes[(alloc_end - lo2->quantstart) / 8]
= ~((1 << ((alloc_end - lo2->quantstart) % 8)) - 1); = ~((1 << ((alloc_end - lo2->quantstart) % 8)) - 1);
grub_memset (lo2->freebytes grub_memset (lo2->freebytes
+ ((alloc_end - lo2->quantstart) / 8) + ((alloc_end - lo2->quantstart) / 8)
+ 1, 0, sizeof (lo2->freebytes) + 1, 0, sizeof (lo2->freebytes)
- (alloc_end - lo2->quantstart) / 8 - 1); - (alloc_end - lo2->quantstart) / 8 - 1);
lo2->prev = &leftovers; lo2->prev = &leftovers;
if (leftovers) if (leftovers)
leftovers->prev = &lo2->next; leftovers->prev = &lo2->next;
lo2->next = leftovers; lo2->next = leftovers;
leftovers = lo2; leftovers = lo2;
} }
curschu->pre = lo1; curschu->pre = lo1;
curschu->post = lo2; curschu->post = lo2;
} }
if (typepre == CHUNK_TYPE_LEFTOVER)
{
curschu->pre = events[last_start].leftover;
curschu->post = events[last_start].leftover;
}
#endif #endif
if (!oom) if (!oom)
cural++; cural++;
@ -965,6 +1053,14 @@ malloc_in_range (struct grub_relocator *rel,
fwin--; fwin--;
break; break;
case REG_LEFTOVER_START:
fwlefto++;
break;
case REG_LEFTOVER_END:
fwlefto--;
break;
case FIRMWARE_BLOCK_START: case FIRMWARE_BLOCK_START:
fwb++; fwb++;
break; break;
@ -983,6 +1079,7 @@ malloc_in_range (struct grub_relocator *rel,
} }
if (oom) if (oom)
{ {
unsigned i;
for (i = 0; i < cural; i++) for (i = 0; i < cural; i++)
free_subchunk (&res->subchunks[i]); free_subchunk (&res->subchunks[i]);
grub_free (res->subchunks); grub_free (res->subchunks);

View file

@ -32,6 +32,8 @@ pkglib_DATA="@pkglib_DATA@"
coreboot_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/${target_cpu}-coreboot coreboot_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/${target_cpu}-coreboot
pc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/${target_cpu}-pc pc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/${target_cpu}-pc
efi32_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-efi
efi64_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/x86_64-efi
# Usage: usage # Usage: usage
# Print the usage. # Print the usage.
@ -128,13 +130,23 @@ if [ "${override_dir}" = "" ] ; then
if test -e "${pc_dir}" ; then if test -e "${pc_dir}" ; then
process_input_dir ${pc_dir} pc process_input_dir ${pc_dir} pc
fi fi
if test -e "${efi32_dir}" ; then
process_input_dir ${efi32_dir} efi32
fi
if test -e "${efi64_dir}" ; then
process_input_dir ${efi64_dir} efi64
fi
else else
process_input_dir ${override_dir} ${native_platform} process_input_dir ${override_dir} ${native_platform}
coreboot_dir= coreboot_dir=
pc_dir= pc_dir=
case "${native_platform}" in efi32_dir=
coreboot) coreboot_dir=${override_dir} ;; efi64_dir=
pc) pc_dir=${override_dir} ;; case "${target_cpu}-${native_platform}" in
i386-coreboot) coreboot_dir=${override_dir} ;;
i386-pc) pc_dir=${override_dir} ;;
i386-efi) efi32_dir=${override_dir} ;;
x86_64-efi) efi64_dir=${override_dir} ;;
esac esac
fi fi
@ -191,6 +203,33 @@ if test -e "${pc_dir}" ; then
--embedded-boot ${embed_img}" --embedded-boot ${embed_img}"
fi fi
if test -e "${efi64_dir}" || test -e "${efi32_dir}"; then
efi_dir=`mktemp -d "$MKTEMP_TEMPLATE"`
mkdir -p "${efi_dir}/efi/boot"
else
efi_dir=
fi
# build bootx64.efi
if test -e "${efi64_dir}" ; then
echo "Generates bootx64.efi"
grub-mkimage -d "${efi64_dir}" -o "${efi_dir}"/efi/boot/bootx64.efi --prefix=/boot/grub/x86_64-efi \
search iso9660 configfile sh
modules="$(cat "${efi64_dir}"/partmap.lst) ${modules}"
(for i in ${modules} ; do
echo "insmod $i"
done ; \
echo "source /boot/grub/grub.cfg") \
> "${iso9660_dir}"/boot/grub/x86_64-efi/grub.cfg
fi
if test x"${efi_dir}" != x; then
mformat -C -f 2880 -L 16 -i "${iso9660_dir}"/efi.img ::
mcopy -s -i "${iso9660_dir}"/efi.img ${efi_dir}/efi ::/
grub_mkisofs_arguments="${grub_mkisofs_arguments} --efi-boot efi.img"
fi
# build iso image # build iso image
grub-mkisofs ${grub_mkisofs_arguments} --protective-msdos-label -o ${output_image} -r ${iso9660_dir} ${source} grub-mkisofs ${grub_mkisofs_arguments} --protective-msdos-label -o ${output_image} -r ${iso9660_dir} ${source}
rm -rf ${iso9660_dir} rm -rf ${iso9660_dir}