summaryrefslogtreecommitdiff
path: root/com32/lib/syslinux/load_linux.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2007-03-15 17:17:29 -0700
committerH. Peter Anvin <hpa@zytor.com>2007-03-15 17:17:29 -0700
commit5c55d7059b5078df7faad8b260cfc59abd1ab332 (patch)
tree96649d0df42c99a05bdd8deea400fc9eacb06a5a /com32/lib/syslinux/load_linux.c
parentc5e9d7a496936b9ea553be6fef4dff74596bbf11 (diff)
downloadsyslinux-5c55d7059b5078df7faad8b260cfc59abd1ab332.tar.gz
initramfs chain handling: add support for forcing the alignment.
cpio has annoying alignment constraints; make it possible to enforce them without adding padding to the end of last member (which breaks things which relies on gzip and need to know the final length.)
Diffstat (limited to 'com32/lib/syslinux/load_linux.c')
-rw-r--r--com32/lib/syslinux/load_linux.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index 620ad081..b8d5a732 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -93,8 +93,10 @@ static addr_t initramfs_size(struct initramfs *initramfs)
if (!initramfs)
return 0;
- for (ip = initramfs->next; ip->len; ip = ip->next)
+ for (ip = initramfs->next; ip->len; ip = ip->next) {
+ size = (size+ip->align-1) & ~(ip->align-1); /* Alignment */
size += ip->len;
+ }
return size;
}
@@ -106,18 +108,30 @@ static int map_initramfs(struct syslinux_movelist **fraglist,
addr_t addr)
{
struct initramfs *ip;
+ addr_t next_addr, len, pad;
for (ip = initramfs->next; ip->len; ip = ip->next) {
+ len = ip->len;
+ next_addr = addr+len;
+
+ /* If this isn't the last entry, extend the zero-pad region
+ to enforce the alignment of the next chunk. */
+ if (ip->next->len) {
+ pad = -next_addr & (ip->next->align-1);
+ len += pad;
+ next_addr += pad;
+ }
+
if (ip->data_len) {
- if (syslinux_add_movelist(fraglist, addr, (addr_t)ip->data, ip->len))
+ if (syslinux_add_movelist(fraglist, addr, (addr_t)ip->data, len))
return -1;
}
- if (ip->len > ip->data_len) {
+ if (len > ip->data_len) {
if (syslinux_add_memmap(mmap, addr+ip->data_len,
- ip->len-ip->data_len, SMT_ZERO))
+ len-ip->data_len, SMT_ZERO))
return -1;
}
- addr += ip->len;
+ addr = next_addr;
}
return 0;
@@ -253,13 +267,14 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
if (irf_size) {
addr_t best_addr = 0;
struct syslinux_memmap *ml;
+ const addr_t align_mask = INITRAMFS_MAX_ALIGN-1;
if (irf_size) {
for (ml = amap; ml->type != SMT_END; ml = ml->next) {
- addr_t adj_start = (ml->start+0xfff) & ~0xfff; /* Page-aligned */
+ addr_t adj_start = (ml->start+align_mask) & ~align_mask;
if (ml->type == SMT_FREE &&
ml->next->start - adj_start >= irf_size)
- best_addr = (ml->next->start - irf_size) & ~0xfff;
+ best_addr = (ml->next->start - irf_size) & ~align_mask;
}
if (!best_addr)