From 4f0de6881cef5f8396333ab6c12c6e571b0f8d26 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 24 Sep 2010 14:05:47 +0200 Subject: [PATCH 1/7] C part of Reed-Solomon --- Makefile.util.def | 1 + grub-core/kern/i386/pc/startup.S | 2 + grub-core/partmap/gpt.c | 14 +- grub-core/partmap/msdos.c | 16 +- include/grub/offsets.h | 9 +- include/grub/partition.h | 5 +- include/grub/reed_solomon.h | 30 ++ util/grub-setup.c | 34 ++- util/reed_solomon.c | 465 +++++++++++++++++++++++++++++++ 9 files changed, 553 insertions(+), 23 deletions(-) create mode 100644 include/grub/reed_solomon.h create mode 100644 util/reed_solomon.c diff --git a/Makefile.util.def b/Makefile.util.def index 21314e04a..5d091f7f5 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -244,6 +244,7 @@ program = { common = util/grub-setup.c; common = util/raid.c; common = util/lvm.c; + common = util/reed_solomon.c; sparc64_ieee1275 = util/ieee1275/ofpath.c; diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S index 46e6b1fac..01825396c 100644 --- a/grub-core/kern/i386/pc/startup.S +++ b/grub-core/kern/i386/pc/startup.S @@ -100,6 +100,8 @@ VARIABLE(grub_install_dos_part) .long 0xFFFFFFFF VARIABLE(grub_install_bsd_part) .long 0xFFFFFFFF +reed_solomon_redundancy: + .long 0 #ifdef APPLE_CC bss_start: diff --git a/grub-core/partmap/gpt.c b/grub-core/partmap/gpt.c index c9393d932..7f2c36143 100644 --- a/grub-core/partmap/gpt.c +++ b/grub-core/partmap/gpt.c @@ -124,9 +124,9 @@ gpt_partition_map_iterate (grub_disk_t disk, #ifdef GRUB_UTIL static grub_err_t -gpt_partition_map_embed (struct grub_disk *disk, unsigned int nsectors, +gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, grub_embed_type_t embed_type, - grub_disk_addr_t *sectors) + grub_disk_addr_t **sectors) { grub_disk_addr_t start = 0, len = 0; unsigned i; @@ -168,13 +168,17 @@ gpt_partition_map_embed (struct grub_disk *disk, unsigned int nsectors, "This GPT partition label has no BIOS Boot Partition;" " embedding won't be possible!"); - if (len < nsectors) + if (len < *nsectors) return grub_error (GRUB_ERR_OUT_OF_RANGE, "Your BIOS Boot Partition is too small;" " embedding won't be possible!"); - for (i = 0; i < nsectors; i++) - sectors[i] = start + i; + *nsectors = len; + *sectors = grub_malloc (*nsectors * sizeof (**sectors)); + if (!*sectors) + return grub_errno; + for (i = 0; i < *nsectors; i++) + (*sectors)[i] = start + i; return GRUB_ERR_NONE; } diff --git a/grub-core/partmap/msdos.c b/grub-core/partmap/msdos.c index 921e2554e..f99e27a6e 100644 --- a/grub-core/partmap/msdos.c +++ b/grub-core/partmap/msdos.c @@ -145,9 +145,9 @@ grub_partition_msdos_iterate (grub_disk_t disk, #ifdef GRUB_UTIL static grub_err_t -pc_partition_map_embed (struct grub_disk *disk, unsigned int nsectors, +pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, grub_embed_type_t embed_type, - grub_disk_addr_t *sectors) + grub_disk_addr_t **sectors) { grub_disk_addr_t end = ~0ULL; struct grub_msdos_partition_mbr mbr; @@ -232,11 +232,15 @@ pc_partition_map_embed (struct grub_disk *disk, unsigned int nsectors, break; } - if (end >= nsectors + 1) + if (end >= *nsectors + 1) { int i; - for (i = 0; i < nsectors; i++) - sectors[i] = 1 + i; + *nsectors = end - 1; + *sectors = grub_malloc (*nsectors * sizeof (**sectors)); + if (!*sectors) + return grub_errno; + for (i = 0; i < *nsectors; i++) + (*sectors)[i] = 1 + i; return GRUB_ERR_NONE; } @@ -245,7 +249,7 @@ pc_partition_map_embed (struct grub_disk *disk, unsigned int nsectors, "This msdos-style partition label has no " "post-MBR gap; embedding won't be possible!"); - if (nsectors > 62) + if (*nsectors > 62) return grub_error (GRUB_ERR_OUT_OF_RANGE, "Your core.img is unusually large. " "It won't fit in the embedding area."); diff --git a/include/grub/offsets.h b/include/grub/offsets.h index 359b32244..d1cf8720f 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -34,11 +34,16 @@ /* The offset of GRUB_INSTALL_BSD_PART. */ #define GRUB_KERNEL_I386_PC_INSTALL_BSD_PART 0x18 +/* Offset of reed_solomon_redundancy. */ +#define GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY 0x1c + /* The offset of multiboot signature. */ -#define GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE 0x1c +#define GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE 0x20 /* The size of the first region which won't be compressed. */ -#define GRUB_KERNEL_I386_PC_RAW_SIZE 0x5D8 +#define GRUB_KERNEL_I386_PC_RAW_SIZE 0x5E0 + +#define GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART 0x300 /* The offset of GRUB_PREFIX. */ #define GRUB_KERNEL_I386_PC_PREFIX GRUB_KERNEL_I386_PC_RAW_SIZE diff --git a/include/grub/partition.h b/include/grub/partition.h index 7ccb7cffd..e7e00ef7f 100644 --- a/include/grub/partition.h +++ b/include/grub/partition.h @@ -48,8 +48,9 @@ struct grub_partition_map const grub_partition_t partition)); #ifdef GRUB_UTIL /* Determine sectors available for embedding. */ - grub_err_t (*embed) (struct grub_disk *disk, unsigned int nsectors, - grub_embed_type_t embed_type, grub_disk_addr_t *sectors); + grub_err_t (*embed) (struct grub_disk *disk, unsigned int *nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors); #endif }; typedef struct grub_partition_map *grub_partition_map_t; diff --git a/include/grub/reed_solomon.h b/include/grub/reed_solomon.h new file mode 100644 index 000000000..596dff246 --- /dev/null +++ b/include/grub/reed_solomon.h @@ -0,0 +1,30 @@ +/* + * 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 . + */ + +#ifndef GRUB_REED_SOLOMON_HEADER +#define GRUB_REED_SOLOMON_HEADER 1 + +void +grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, + grub_size_t redundancy); + +void +grub_reed_solomon_recover (void *buffer, grub_size_t data_size, + grub_size_t redundancy); + +#endif diff --git a/util/grub-setup.c b/util/grub-setup.c index 0c5470830..1518bb0a8 100644 --- a/util/grub-setup.c +++ b/util/grub-setup.c @@ -48,6 +48,7 @@ #include #include #include "progname.h" +#include #define _GNU_SOURCE 1 #include @@ -336,9 +337,10 @@ setup (const char *dir, grub_partition_t container = dest_dev->disk->partition; int multiple_partmaps = 0; grub_err_t err; - grub_disk_addr_t sectors[core_sectors]; + grub_disk_addr_t *sectors; int i; grub_fs_t fs; + unsigned int nsec; /* Unlike root_dev, with dest_dev we're interested in the partition map even if dest_dev itself is a whole disk. */ @@ -419,8 +421,11 @@ setup (const char *dir, goto unable_to_embed; } - err = dest_partmap->embed (dest_dev->disk, core_sectors, - GRUB_EMBED_PCBIOS, sectors); + nsec = core_sectors; + err = dest_partmap->embed (dest_dev->disk, &nsec, + GRUB_EMBED_PCBIOS, §ors); + if (nsec > 2 * core_sectors) + nsec = 2 * core_sectors; if (err) { @@ -439,6 +444,20 @@ setup (const char *dir, write_rootdev (core_img, root_dev, boot_img, first_sector); + core_img = realloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE); + first_block = (struct grub_boot_blocklist *) (core_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*block)); + + *(grub_uint32_t *) (core_img + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY) + = grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size); + + grub_reed_solomon_add_redundancy (core_img + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + GRUB_DISK_SECTOR_SIZE, + core_size - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART - GRUB_DISK_SECTOR_SIZE, + nsec * GRUB_DISK_SECTOR_SIZE + - core_size); + /* Make sure that the second blocklist is a terminator. */ block = first_block - 1; block->start = 0; @@ -446,14 +465,13 @@ setup (const char *dir, block->segment = 0; /* Write the core image onto the disk. */ - for (i = 0; i < core_sectors; i++) + for (i = 0; i < nsec; i++) grub_disk_write (dest_dev->disk, sectors[i], 0, - (core_size - i * GRUB_DISK_SECTOR_SIZE - < GRUB_DISK_SECTOR_SIZE) ? core_size - - i * GRUB_DISK_SECTOR_SIZE - : GRUB_DISK_SECTOR_SIZE, + GRUB_DISK_SECTOR_SIZE, core_img + i * GRUB_DISK_SECTOR_SIZE); + grub_free (sectors); + goto finish; } #endif diff --git a/util/reed_solomon.c b/util/reed_solomon.c new file mode 100644 index 000000000..c20d023e7 --- /dev/null +++ b/util/reed_solomon.c @@ -0,0 +1,465 @@ +/* + * 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 . + */ + +#ifdef TEST +#include +#include +#include +typedef unsigned int grub_size_t; +typedef unsigned char grub_uint8_t; +typedef unsigned short grub_uint16_t; +#define xmalloc malloc +#define grub_memset memset +#define grub_memcpy memcpy +#else +#include +#include +#include +#include +#endif + +#define GF_SIZE 8 +typedef grub_uint8_t gf_single_t; +typedef grub_uint16_t gf_double_t; +const gf_single_t gf_polynomial = 0x1d; + +#define SECTOR_SIZE 512 +#define MAX_BLOCK_SIZE (200 * SECTOR_SIZE) + +static gf_single_t +gf_reduce (gf_double_t a) +{ + int i; + for (i = GF_SIZE - 1; i >= 0; i--) + if (a & (1ULL << (i + GF_SIZE))) + a ^= (((gf_double_t) gf_polynomial) << i); + return a & ((1ULL << GF_SIZE) - 1); +} + +static gf_single_t +gf_mul (gf_single_t a, gf_single_t b) +{ + gf_double_t res = 0; + int i; + for (i = 0; i < GF_SIZE; i++) + if (b & (1 << i)) + res ^= ((gf_double_t) a) << i; + return gf_reduce (res); +} + +static int +bin_log2 (gf_double_t a) +{ + int i = 0; + while (a) + { + a >>= 1; + i++; + } + return i - 1; +} + +static gf_single_t +gf_invert (gf_single_t a) +{ + /* We start with: */ + /* 1 * a + 0 * p = a */ + /* 0 * a + 1 * p = p */ + gf_double_t x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1; + gf_double_t z2 = gf_polynomial | (1ULL << GF_SIZE), t; + /* invariant: z1 < z2*/ + while (z1 != 0) + { + int k; + k = bin_log2 (z2) - bin_log2 (z1); + x2 ^= (x1 << k); + y2 ^= (y1 << k); + z2 ^= (z1 << k); + + if (z1 >= z2) + { + t = x2; + x2 = x1; + x1 = t; + t = y2; + y2 = y1; + y1 = t; + t = z2; + z2 = z1; + z1 = t; + } + } + + return gf_reduce (x2); +} + +static gf_single_t +pol_evaluate (gf_single_t *pol, grub_size_t degree, gf_single_t x) +{ + int i; + gf_single_t xn = 1, s = 0; + for (i = degree; i >= 0; i--) + { + s ^= gf_mul (pol[i], xn); + xn = gf_mul (x, xn); + } + return s; +} + +static void +rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) +{ + gf_single_t *rs_polynomial, a = 1; + int i, j; + gf_single_t *m; + m = xmalloc ((s + rs) * sizeof (gf_single_t)); + grub_memcpy (m, data, s * sizeof (gf_single_t)); + grub_memset (m + s, 0, rs * sizeof (gf_single_t)); + rs_polynomial = xmalloc ((rs + 1) * sizeof (gf_single_t)); + grub_memset (rs_polynomial, 0, (rs + 1) * sizeof (gf_single_t)); + rs_polynomial[rs] = 1; + /* Multiply with X - a^r */ + for (j = 0; j < rs; j++) + { + if (a & (1 << (GF_SIZE - 1))) + { + a <<= 1; + a ^= gf_polynomial; + } + else + a <<= 1; + for (i = 0; i < rs; i++) + rs_polynomial[i] = rs_polynomial[i + 1] ^ gf_mul (a, rs_polynomial[i]); + rs_polynomial[rs] = gf_mul (a, rs_polynomial[rs]); + } + for (j = 0; j < s; j++) + if (m[j]) + { + gf_single_t f = m[j]; + for (i = 0; i <= rs; i++) + m[i+j] ^= gf_mul (rs_polynomial[i], f); + } + free (rs_polynomial); + grub_memcpy (data + s, m + s, rs * sizeof (gf_single_t)); + free (m); + +} + +static void +syndroms (gf_single_t *m, grub_size_t s, grub_size_t rs, + gf_single_t *sy) +{ + gf_single_t xn = 1; + int i; + for (i = 0; i < rs; i++) + { + if (xn & (1 << (GF_SIZE - 1))) + { + xn <<= 1; + xn ^= gf_polynomial; + } + else + xn <<= 1; + sy[i] = pol_evaluate (m, s + rs - 1, xn); + } +} + +static void +rs_recover (gf_single_t *m, grub_size_t s, grub_size_t rs) +{ + grub_size_t rs2 = rs / 2; + gf_single_t *sigma; + gf_single_t *errpot; + int *errpos; + gf_single_t *sy; + int errnum = 0; + int i, j; + + sigma = xmalloc (rs2 * sizeof (gf_single_t)); + errpot = xmalloc (rs2 * sizeof (gf_single_t)); + errpos = xmalloc (rs2 * sizeof (int)); + sy = xmalloc (rs * sizeof (gf_single_t)); + + syndroms (m, s, rs, sy); + + { + gf_single_t *eq; + int *chosen; + + eq = xmalloc (rs2 * (rs2 + 1) * sizeof (gf_single_t)); + chosen = xmalloc (rs2 * sizeof (int)); + + for (i = 0; i < rs; i++) + if (sy[i] != 0) + break; + + /* No error detected. */ + if (i == rs) + return; + + for (i = 0; i < rs2; i++) + for (j = 0; j < rs2 + 1; j++) + eq[i * (rs2 + 1) + j] = sy[i+j]; + + grub_memset (sigma, 0, rs2 * sizeof (gf_single_t)); + grub_memset (chosen, -1, rs2 * sizeof (int)); + + for (i = 0 ; i < rs2; i++) + { + int nzidx; + int k; + gf_single_t r; + for (nzidx = 0; nzidx < rs2 && (eq[i * (rs2 + 1) + nzidx] == 0); + nzidx++); + if (nzidx == rs2) + { + break; + } + chosen[i] = nzidx; + r = gf_invert (eq[i * (rs2 + 1) + nzidx]); + for (j = 0; j < rs2 + 1; j++) + eq[i * (rs2 + 1) + j] = gf_mul (eq[i * (rs2 + 1) + j], r); + for (j = i + 1; j < rs2; j++) + { + gf_single_t rr = eq[j * (rs2 + 1) + nzidx]; + for (k = 0; k < rs2 + 1; k++) + eq[j * (rs2 + 1) + k] ^= gf_mul (eq[i * (rs2 + 1) + k], rr);; + } + } + for (i = rs2 - 1; i >= 0; i--) + { + gf_single_t s = 0; + if (chosen[i] == -1) + continue; + for (j = 0; j < rs2; j++) + s ^= gf_mul (eq[i * (rs2 + 1) + j], sigma[j]); + s ^= eq[i * (rs2 + 1) + rs2]; + sigma[chosen[i]] = s; + } + + free (chosen); + free (eq); + } + + { + gf_single_t xn = 1, xx = gf_invert (2), yn = 1; + int lp = 0; + for (i = 0; i < rs + s; i++) + { + gf_single_t ev = (gf_mul (pol_evaluate (sigma, rs2 - 1, xn), xn) ^ 1); + if (ev == 0) + { + errpot[errnum] = yn; + errpos[errnum++] = s + rs - i - 1; + } + yn = gf_mul (yn, 2); + xn = gf_mul (xn, xx); + } + } + { + gf_single_t *eq; + int *chosen; + gf_single_t *errvals; + + eq = xmalloc (rs * (errnum + 1) * sizeof (gf_single_t)); + chosen = xmalloc (rs * sizeof (int)); + errvals = xmalloc (errnum * sizeof (int)); + + grub_memset (chosen, -1, rs * sizeof (int)); + grub_memset (errvals, 0, errnum * sizeof (gf_single_t)); + + for (j = 0; j < errnum; j++) + eq[j] = errpot[j]; + eq[errnum] = sy[0]; + for (i = 1; i < rs; i++) + { + for (j = 0; j < errnum; j++) + eq[(errnum + 1) * i + j] = gf_mul (errpot[j], + eq[(errnum + 1) * (i - 1) + j]); + eq[(errnum + 1) * i + errnum] = sy[i]; + } + for (i = 0 ; i < rs; i++) + { + int nzidx; + int k; + gf_single_t r; + for (nzidx = 0; nzidx < errnum && (eq[i * (errnum + 1) + nzidx] == 0); + nzidx++); + if (nzidx == errnum) + continue; + chosen[i] = nzidx; + r = gf_invert (eq[i * (errnum + 1) + nzidx]); + for (j = 0; j < errnum + 1; j++) + eq[i * (errnum + 1) + j] = gf_mul (eq[i * (errnum + 1) + j], r); + for (j = i + 1; j < rs; j++) + { + gf_single_t rr = eq[j * (errnum + 1) + nzidx]; + for (k = 0; k < errnum + 1; k++) + eq[j * (errnum + 1) + k] ^= gf_mul (eq[i * (errnum + 1) + k], rr); + } + } + for (i = rs - 1; i >= 0; i--) + { + gf_single_t s = 0; + if (chosen[i] == -1) + continue; + for (j = 0; j < errnum; j++) + s ^= gf_mul (eq[i * (errnum + 1) + j], errvals[j]); + s ^= eq[i * (errnum + 1) + errnum]; + errvals[chosen[i]] = s; + } + for (i = 0; i < errnum; i++) + m[errpos[i]] ^= errvals[i]; + } + free (sy); +} + +static void +decode_block (gf_single_t *ptr, grub_size_t s, + gf_single_t *rptr, grub_size_t rs) +{ + grub_size_t ss; + int i, j, k; + for (i = 0; i < SECTOR_SIZE; i++) + { + grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; + grub_size_t rr = (rs + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; + gf_single_t m[ds + rr]; + + for (j = 0; j < ds; j++) + m[j] = ptr[SECTOR_SIZE * j + i]; + for (j = 0; j < rr; j++) + m[j + ds] = rptr[SECTOR_SIZE * j + i]; + + rs_recover (m, ds, rr); + + for (j = 0; j < ds; j++) + ptr[SECTOR_SIZE * j + i] = m[j]; + } +} + +static void +encode_block (gf_single_t *ptr, grub_size_t s, + gf_single_t *rptr, grub_size_t rs) +{ + grub_size_t ss; + int i, j; + for (i = 0; i < SECTOR_SIZE; i++) + { + grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; + grub_size_t rr = (rs + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; + gf_single_t m[ds + rr]; + for (j = 0; j < ds; j++) + m[j] = ptr[SECTOR_SIZE * j + i]; + rs_encode (m, ds, rr); + for (j = 0; j < rr; j++) + rptr[SECTOR_SIZE * j + i] = m[j + ds]; + } +} + +void +grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, + grub_size_t redundancy) +{ + grub_size_t s = data_size; + grub_size_t rs = redundancy; + gf_single_t *ptr = buffer; + gf_single_t *rptr = ptr + s; + + while (s > 0) + { + grub_size_t tt; + grub_size_t cs, crs; + cs = s; + crs = rs; + tt = cs + crs; + if (tt > MAX_BLOCK_SIZE) + { + cs = (cs * MAX_BLOCK_SIZE) / tt; + crs = (crs * MAX_BLOCK_SIZE) / tt; + } + encode_block (ptr, cs, rptr, crs); + ptr += cs; + rptr += crs; + s -= cs; + rs -= crs; + } +} + +void +grub_reed_solomon_recover (void *ptr, grub_size_t s, grub_size_t rs) +{ + gf_single_t *rptr = ptr + s; + while (s > 0) + { + grub_size_t tt; + grub_size_t cs, crs; + cs = s; + crs = rs; + tt = cs + crs; + if (tt > MAX_BLOCK_SIZE) + { + cs = cs * MAX_BLOCK_SIZE / tt; + crs = crs * MAX_BLOCK_SIZE / tt; + } + decode_block (ptr, cs, rptr, crs); + ptr += cs; + rptr += crs; + s -= cs; + rs -= crs; + } +} + +#ifdef TEST +int +main (int argc, char **argv) +{ + FILE *in, *out; + grub_size_t s, rs; + char *buf; + in = fopen ("tst.bin", "rb"); + if (!in) + return 1; + fseek (in, 0, SEEK_END); + s = ftell (in); + fseek (in, 0, SEEK_SET); + rs = 1024 * ((s + MAX_BLOCK_SIZE - 1) / (MAX_BLOCK_SIZE - 1024)); + buf = xmalloc (s + rs + SECTOR_SIZE); + fread (buf, 1, s, in); + + grub_reed_solomon_add_redundancy (buf, s, rs); + + out = fopen ("tst_rs.bin", "wb"); + fwrite (buf, 1, s + rs, out); + fclose (out); + + grub_memset (buf + 512 * 15, 0, 512); + + out = fopen ("tst_dam.bin", "wb"); + fwrite (buf, 1, s + rs, out); + fclose (out); + + grub_reed_solomon_recover (buf, s, rs); + + out = fopen ("tst_rec.bin", "wb"); + fwrite (buf, 1, s, out); + fclose (out); + + return 0; +} +#endif From 419cbeb06d2733095b4cf9dad8b088f2338e1420 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 25 Sep 2010 19:33:05 +0200 Subject: [PATCH 2/7] hook Reed-Solomon into startup.S --- Makefile.util.def | 2 +- grub-core/Makefile.am | 4 + grub-core/kern/i386/pc/startup.S | 16 ++ {util => grub-core/lib}/reed_solomon.c | 327 ++++++++++++++----------- include/grub/offsets.h | 4 +- 5 files changed, 209 insertions(+), 144 deletions(-) rename {util => grub-core/lib}/reed_solomon.c (63%) diff --git a/Makefile.util.def b/Makefile.util.def index 5d091f7f5..bf66d45bc 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -244,7 +244,7 @@ program = { common = util/grub-setup.c; common = util/raid.c; common = util/lvm.c; - common = util/reed_solomon.c; + common = grub-core/lib/reed_solomon.c; sparc64_ieee1275 = util/ieee1275/ofpath.c; diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index addc83417..307467f44 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -48,6 +48,10 @@ CLEANFILES += grub_script.tab.c grub_script.tab.h grub_script.yy.h: script/yylex.l $(LEX) -o grub_script.yy.c --header-file=grub_script.yy.h $< grub_script.yy.c: grub_script.yy.h + +rs_decoder.S: $(srcdir)/lib/reed_solomon.c + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -I$(top_builddir) -S -DSTANDALONE -o $@ $< + CLEANFILES += grub_script.yy.c grub_script.yy.h include $(srcdir)/Makefile.core.am diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S index 01825396c..283fc4f49 100644 --- a/grub-core/kern/i386/pc/startup.S +++ b/grub-core/kern/i386/pc/startup.S @@ -206,6 +206,22 @@ LOCAL (codestart): incl %eax call grub_gate_a20 + movl EXT_C(grub_kernel_image_size), %eax + addl EXT_C(grub_total_module_size), %eax + movl reed_solomon_redundancy, %ecx + leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %edx + testl %eax, %eax + jz post_reed_solomon + call EXT_C (grub_reed_solomon_recover) + jmp post_reed_solomon + +#include "/home/phcoder/compile/grub-core/rs_decoder.S" + + .text + + . = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART +post_reed_solomon: + #ifdef ENABLE_LZMA movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi movl $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi diff --git a/util/reed_solomon.c b/grub-core/lib/reed_solomon.c similarity index 63% rename from util/reed_solomon.c rename to grub-core/lib/reed_solomon.c index c20d023e7..290eb9482 100644 --- a/util/reed_solomon.c +++ b/grub-core/lib/reed_solomon.c @@ -18,25 +18,48 @@ #ifdef TEST #include +#define xmalloc malloc +#define grub_memset memset +#define grub_memcpy memcpy +#endif + +#ifndef STANDALONE +#ifdef TEST #include #include typedef unsigned int grub_size_t; typedef unsigned char grub_uint8_t; typedef unsigned short grub_uint16_t; -#define xmalloc malloc -#define grub_memset memset -#define grub_memcpy memcpy #else #include #include #include #include #endif +#endif + +#ifdef STANDALONE +#ifdef TEST +typedef unsigned int grub_size_t; +typedef unsigned char grub_uint8_t; +typedef unsigned short grub_uint16_t; +#else +#include +#endif +void +grub_reed_solomon_recover (void *ptr_, grub_size_t s, grub_size_t rs); +#endif #define GF_SIZE 8 typedef grub_uint8_t gf_single_t; typedef grub_uint16_t gf_double_t; -const gf_single_t gf_polynomial = 0x1d; +#define GF_POLYNOMIAL 0x1d +#define GF_INVERT2 0x8e +#ifdef STANDALONE +static char *scratch __attribute__ ((section(".text"))) = (void *) 0x100000; +#else +static char *scratch; +#endif #define SECTOR_SIZE 512 #define MAX_BLOCK_SIZE (200 * SECTOR_SIZE) @@ -47,7 +70,7 @@ gf_reduce (gf_double_t a) int i; for (i = GF_SIZE - 1; i >= 0; i--) if (a & (1ULL << (i + GF_SIZE))) - a ^= (((gf_double_t) gf_polynomial) << i); + a ^= (((gf_double_t) GF_POLYNOMIAL) << i); return a & ((1ULL << GF_SIZE) - 1); } @@ -62,50 +85,19 @@ gf_mul (gf_single_t a, gf_single_t b) return gf_reduce (res); } -static int -bin_log2 (gf_double_t a) +static grub_uint8_t gf_invert[256]; + +static void +init_inverts (void) { - int i = 0; - while (a) + gf_single_t a = 1, ai = 1; + do { - a >>= 1; - i++; + a = gf_mul (a, 2); + ai = gf_mul (ai, GF_INVERT2); + gf_invert[a] = ai; } - return i - 1; -} - -static gf_single_t -gf_invert (gf_single_t a) -{ - /* We start with: */ - /* 1 * a + 0 * p = a */ - /* 0 * a + 1 * p = p */ - gf_double_t x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1; - gf_double_t z2 = gf_polynomial | (1ULL << GF_SIZE), t; - /* invariant: z1 < z2*/ - while (z1 != 0) - { - int k; - k = bin_log2 (z2) - bin_log2 (z1); - x2 ^= (x1 << k); - y2 ^= (y1 << k); - z2 ^= (z1 << k); - - if (z1 >= z2) - { - t = x2; - x2 = x1; - x1 = t; - t = y2; - y2 = y1; - y1 = t; - t = z2; - z2 = z1; - z1 = t; - } - } - - return gf_reduce (x2); + while (a != 1); } static gf_single_t @@ -121,6 +113,7 @@ pol_evaluate (gf_single_t *pol, grub_size_t degree, gf_single_t x) return s; } +#if !defined (STANDALONE) || defined (TEST) static void rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) { @@ -139,7 +132,7 @@ rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) if (a & (1 << (GF_SIZE - 1))) { a <<= 1; - a ^= gf_polynomial; + a ^= GF_POLYNOMIAL; } else a <<= 1; @@ -157,21 +150,21 @@ rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) free (rs_polynomial); grub_memcpy (data + s, m + s, rs * sizeof (gf_single_t)); free (m); - } +#endif static void syndroms (gf_single_t *m, grub_size_t s, grub_size_t rs, gf_single_t *sy) { gf_single_t xn = 1; - int i; + unsigned i; for (i = 0; i < rs; i++) { if (xn & (1 << (GF_SIZE - 1))) { xn <<= 1; - xn ^= gf_polynomial; + xn ^= GF_POLYNOMIAL; } else xn <<= 1; @@ -179,6 +172,66 @@ syndroms (gf_single_t *m, grub_size_t s, grub_size_t rs, } } +static void +gauss_eliminate (gf_single_t *eq, int n, int m, int *chosen) +{ + int i, j; + + for (i = 0 ; i < n; i++) + { + int nzidx; + int k; + gf_single_t r; + for (nzidx = 0; nzidx < m && (eq[i * (m + 1) + nzidx] == 0); + nzidx++); + if (nzidx == m) + continue; + chosen[i] = nzidx; + r = gf_invert [eq[i * (m + 1) + nzidx]]; + for (j = 0; j < m + 1; j++) + eq[i * (m + 1) + j] = gf_mul (eq[i * (m + 1) + j], r); + for (j = i + 1; j < n; j++) + { + gf_single_t rr = eq[j * (m + 1) + nzidx]; + for (k = 0; k < m + 1; k++) + eq[j * (m + 1) + k] ^= gf_mul (eq[i * (m + 1) + k], rr); + } + } +} + +static void +gauss_solve (gf_single_t *eq, int n, int m, gf_single_t *sol) +{ + int *chosen; + int i, j; + +#ifndef STANDALONE + chosen = xmalloc (n * sizeof (int)); + grub_memset (chosen, -1, n * sizeof (int)); +#else + chosen = (void *) scratch; + scratch += n; +#endif + for (i = 0; i < m; i++) + sol[i] = 0; + gauss_eliminate (eq, n, m, chosen); + for (i = n - 1; i >= 0; i--) + { + gf_single_t s = 0; + if (chosen[i] == -1) + continue; + for (j = 0; j < m; j++) + s ^= gf_mul (eq[i * (m + 1) + j], sol[j]); + s ^= eq[i * (m + 1) + m]; + sol[chosen[i]] = s; + } +#ifndef STANDALONE + free (chosen); +#else + scratch -= n; +#endif +} + static void rs_recover (gf_single_t *m, grub_size_t s, grub_size_t rs) { @@ -190,76 +243,61 @@ rs_recover (gf_single_t *m, grub_size_t s, grub_size_t rs) int errnum = 0; int i, j; +#ifndef STANDALONE sigma = xmalloc (rs2 * sizeof (gf_single_t)); errpot = xmalloc (rs2 * sizeof (gf_single_t)); errpos = xmalloc (rs2 * sizeof (int)); sy = xmalloc (rs * sizeof (gf_single_t)); +#else + sigma = (void *) scratch; + scratch += rs2 * sizeof (gf_single_t); + errpot = (void *) scratch; + scratch += rs2 * sizeof (gf_single_t); + errpos = (void *) scratch; + scratch += rs2 * sizeof (int); + sy = (void *) scratch; + scratch += rs * sizeof (gf_single_t); +#endif syndroms (m, s, rs, sy); { gf_single_t *eq; - int *chosen; +#ifndef STANDALONE eq = xmalloc (rs2 * (rs2 + 1) * sizeof (gf_single_t)); - chosen = xmalloc (rs2 * sizeof (int)); +#else + eq = (void *) scratch; + scratch += rs2 * (rs2 + 1) * sizeof (gf_single_t); +#endif - for (i = 0; i < rs; i++) + for (i = 0; i < (int) rs; i++) if (sy[i] != 0) break; /* No error detected. */ - if (i == rs) + if (i == (int) rs) return; - for (i = 0; i < rs2; i++) - for (j = 0; j < rs2 + 1; j++) + for (i = 0; i < (int) rs2; i++) + for (j = 0; j < (int) rs2 + 1; j++) eq[i * (rs2 + 1) + j] = sy[i+j]; - grub_memset (sigma, 0, rs2 * sizeof (gf_single_t)); - grub_memset (chosen, -1, rs2 * sizeof (int)); + for (i = 0; i < (int) rs2; i++) + sigma[i] = 0; - for (i = 0 ; i < rs2; i++) - { - int nzidx; - int k; - gf_single_t r; - for (nzidx = 0; nzidx < rs2 && (eq[i * (rs2 + 1) + nzidx] == 0); - nzidx++); - if (nzidx == rs2) - { - break; - } - chosen[i] = nzidx; - r = gf_invert (eq[i * (rs2 + 1) + nzidx]); - for (j = 0; j < rs2 + 1; j++) - eq[i * (rs2 + 1) + j] = gf_mul (eq[i * (rs2 + 1) + j], r); - for (j = i + 1; j < rs2; j++) - { - gf_single_t rr = eq[j * (rs2 + 1) + nzidx]; - for (k = 0; k < rs2 + 1; k++) - eq[j * (rs2 + 1) + k] ^= gf_mul (eq[i * (rs2 + 1) + k], rr);; - } - } - for (i = rs2 - 1; i >= 0; i--) - { - gf_single_t s = 0; - if (chosen[i] == -1) - continue; - for (j = 0; j < rs2; j++) - s ^= gf_mul (eq[i * (rs2 + 1) + j], sigma[j]); - s ^= eq[i * (rs2 + 1) + rs2]; - sigma[chosen[i]] = s; - } + gauss_solve (eq, rs2, rs2, sigma); - free (chosen); +#ifndef STANDALONE free (eq); +#else + scratch -= rs2 * (rs2 + 1) * sizeof (gf_single_t); +#endif } { - gf_single_t xn = 1, xx = gf_invert (2), yn = 1; - int lp = 0; - for (i = 0; i < rs + s; i++) + gf_single_t xn = 1, yn = 1; + for (i = 0; i < (int) (rs + s); i++) { gf_single_t ev = (gf_mul (pol_evaluate (sigma, rs2 - 1, xn), xn) ^ 1); if (ev == 0) @@ -268,96 +306,87 @@ rs_recover (gf_single_t *m, grub_size_t s, grub_size_t rs) errpos[errnum++] = s + rs - i - 1; } yn = gf_mul (yn, 2); - xn = gf_mul (xn, xx); + xn = gf_mul (xn, GF_INVERT2); } } { - gf_single_t *eq; - int *chosen; gf_single_t *errvals; + gf_single_t *eq; +#ifndef STANDALONE eq = xmalloc (rs * (errnum + 1) * sizeof (gf_single_t)); - chosen = xmalloc (rs * sizeof (int)); errvals = xmalloc (errnum * sizeof (int)); - - grub_memset (chosen, -1, rs * sizeof (int)); - grub_memset (errvals, 0, errnum * sizeof (gf_single_t)); +#else + eq = (void *) scratch; + scratch += rs * (errnum + 1) * sizeof (gf_single_t); + errvals = (void *) scratch; + scratch += errnum * sizeof (int); +#endif for (j = 0; j < errnum; j++) eq[j] = errpot[j]; eq[errnum] = sy[0]; - for (i = 1; i < rs; i++) + for (i = 1; i < (int) rs; i++) { - for (j = 0; j < errnum; j++) + for (j = 0; j < (int) errnum; j++) eq[(errnum + 1) * i + j] = gf_mul (errpot[j], eq[(errnum + 1) * (i - 1) + j]); eq[(errnum + 1) * i + errnum] = sy[i]; } - for (i = 0 ; i < rs; i++) - { - int nzidx; - int k; - gf_single_t r; - for (nzidx = 0; nzidx < errnum && (eq[i * (errnum + 1) + nzidx] == 0); - nzidx++); - if (nzidx == errnum) - continue; - chosen[i] = nzidx; - r = gf_invert (eq[i * (errnum + 1) + nzidx]); - for (j = 0; j < errnum + 1; j++) - eq[i * (errnum + 1) + j] = gf_mul (eq[i * (errnum + 1) + j], r); - for (j = i + 1; j < rs; j++) - { - gf_single_t rr = eq[j * (errnum + 1) + nzidx]; - for (k = 0; k < errnum + 1; k++) - eq[j * (errnum + 1) + k] ^= gf_mul (eq[i * (errnum + 1) + k], rr); - } - } - for (i = rs - 1; i >= 0; i--) - { - gf_single_t s = 0; - if (chosen[i] == -1) - continue; - for (j = 0; j < errnum; j++) - s ^= gf_mul (eq[i * (errnum + 1) + j], errvals[j]); - s ^= eq[i * (errnum + 1) + errnum]; - errvals[chosen[i]] = s; - } - for (i = 0; i < errnum; i++) + + gauss_solve (eq, rs, errnum, errvals); + + for (i = 0; i < (int) errnum; i++) m[errpos[i]] ^= errvals[i]; +#ifndef STANDALONE + free (eq); + free (errvals); +#else + scratch -= rs * (errnum + 1) * sizeof (gf_single_t); + scratch -= errnum * sizeof (int); +#endif } +#ifndef STANDALONE + free (sigma); + free (errpot); + free (errpos); free (sy); +#else + scratch -= rs2 * sizeof (gf_single_t); + scratch -= rs2 * sizeof (gf_single_t); + scratch -= rs2 * sizeof (int); + scratch -= rs * sizeof (gf_single_t); +#endif } static void decode_block (gf_single_t *ptr, grub_size_t s, gf_single_t *rptr, grub_size_t rs) { - grub_size_t ss; - int i, j, k; + int i, j; for (i = 0; i < SECTOR_SIZE; i++) { grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; grub_size_t rr = (rs + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; gf_single_t m[ds + rr]; - for (j = 0; j < ds; j++) + for (j = 0; j < (int) ds; j++) m[j] = ptr[SECTOR_SIZE * j + i]; - for (j = 0; j < rr; j++) + for (j = 0; j < (int) rr; j++) m[j + ds] = rptr[SECTOR_SIZE * j + i]; rs_recover (m, ds, rr); - for (j = 0; j < ds; j++) + for (j = 0; j < (int) ds; j++) ptr[SECTOR_SIZE * j + i] = m[j]; } } +#if !defined (STANDALONE) || defined (TEST) static void encode_block (gf_single_t *ptr, grub_size_t s, gf_single_t *rptr, grub_size_t rs) { - grub_size_t ss; int i, j; for (i = 0; i < SECTOR_SIZE; i++) { @@ -371,7 +400,9 @@ encode_block (gf_single_t *ptr, grub_size_t s, rptr[SECTOR_SIZE * j + i] = m[j + ds]; } } +#endif +#if !defined (STANDALONE) || defined (TEST) void grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, grub_size_t redundancy) @@ -400,11 +431,18 @@ grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, rs -= crs; } } +#endif void -grub_reed_solomon_recover (void *ptr, grub_size_t s, grub_size_t rs) +grub_reed_solomon_recover (void *ptr_, grub_size_t s, grub_size_t rs) { + gf_single_t *ptr = ptr_; gf_single_t *rptr = ptr + s; + +#if defined (STANDALONE) && !defined (TEST) + init_inverts (); +#endif + while (s > 0) { grub_size_t tt; @@ -432,6 +470,13 @@ main (int argc, char **argv) FILE *in, *out; grub_size_t s, rs; char *buf; + +#ifdef STANDALONE + scratch = xmalloc (1048576); +#endif + + init_inverts (); + in = fopen ("tst.bin", "rb"); if (!in) return 1; diff --git a/include/grub/offsets.h b/include/grub/offsets.h index d1cf8720f..b8fbe40d4 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -41,9 +41,9 @@ #define GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE 0x20 /* The size of the first region which won't be compressed. */ -#define GRUB_KERNEL_I386_PC_RAW_SIZE 0x5E0 +#define GRUB_KERNEL_I386_PC_RAW_SIZE 0xc6c -#define GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART 0x300 +#define GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART 0x748 /* The offset of GRUB_PREFIX. */ #define GRUB_KERNEL_I386_PC_PREFIX GRUB_KERNEL_I386_PC_RAW_SIZE From 3ac9e7920712be587214e904139a3871add55392 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 25 Sep 2010 20:40:26 +0200 Subject: [PATCH 3/7] Multiple bugs correction for Reed-Solomon --- grub-core/Makefile.am | 2 +- grub-core/kern/i386/pc/startup.S | 10 +++++----- grub-core/lib/reed_solomon.c | 28 +++++++++++++++++++--------- include/grub/offsets.h | 4 ++-- util/grub-setup.c | 2 +- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 307467f44..a740cb5cb 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -50,7 +50,7 @@ grub_script.yy.h: script/yylex.l grub_script.yy.c: grub_script.yy.h rs_decoder.S: $(srcdir)/lib/reed_solomon.c - $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -I$(top_builddir) -S -DSTANDALONE -o $@ $< + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -I$(top_builddir) -S -DSTANDALONE -o $@ $< -g0 CLEANFILES += grub_script.yy.c grub_script.yy.h diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S index 283fc4f49..9319df98e 100644 --- a/grub-core/kern/i386/pc/startup.S +++ b/grub-core/kern/i386/pc/startup.S @@ -206,16 +206,16 @@ LOCAL (codestart): incl %eax call grub_gate_a20 - movl EXT_C(grub_kernel_image_size), %eax - addl EXT_C(grub_total_module_size), %eax + movl EXT_C(grub_compressed_size), %edx + addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART), %edx movl reed_solomon_redundancy, %ecx - leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %edx - testl %eax, %eax + leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax + testl %edx, %edx jz post_reed_solomon call EXT_C (grub_reed_solomon_recover) jmp post_reed_solomon -#include "/home/phcoder/compile/grub-core/rs_decoder.S" +#include .text diff --git a/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c index 290eb9482..f87ff1552 100644 --- a/grub-core/lib/reed_solomon.c +++ b/grub-core/lib/reed_solomon.c @@ -55,10 +55,12 @@ typedef grub_uint8_t gf_single_t; typedef grub_uint16_t gf_double_t; #define GF_POLYNOMIAL 0x1d #define GF_INVERT2 0x8e -#ifdef STANDALONE -static char *scratch __attribute__ ((section(".text"))) = (void *) 0x100000; +#if defined (STANDALONE) && !defined (TEST) +static char *gf_invert __attribute__ ((section(".text"))) = (void *) 0x100000; +static char *scratch __attribute__ ((section(".text"))) = (void *) 0x100100; #else static char *scratch; +static grub_uint8_t gf_invert[256]; #endif #define SECTOR_SIZE 512 @@ -85,8 +87,6 @@ gf_mul (gf_single_t a, gf_single_t b) return gf_reduce (res); } -static grub_uint8_t gf_invert[256]; - static void init_inverts (void) { @@ -113,7 +113,7 @@ pol_evaluate (gf_single_t *pol, grub_size_t degree, gf_single_t x) return s; } -#if !defined (STANDALONE) || defined (TEST) +#if !defined (STANDALONE) static void rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) { @@ -382,7 +382,7 @@ decode_block (gf_single_t *ptr, grub_size_t s, } } -#if !defined (STANDALONE) || defined (TEST) +#if !defined (STANDALONE) static void encode_block (gf_single_t *ptr, grub_size_t s, gf_single_t *rptr, grub_size_t rs) @@ -402,7 +402,7 @@ encode_block (gf_single_t *ptr, grub_size_t s, } #endif -#if !defined (STANDALONE) || defined (TEST) +#if !defined (STANDALONE) void grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, grub_size_t redundancy) @@ -412,6 +412,8 @@ grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, gf_single_t *ptr = buffer; gf_single_t *rptr = ptr + s; + grub_printf ("solomon: %p, %x, %x\n", buffer, data_size, redundancy); + while (s > 0) { grub_size_t tt; @@ -439,7 +441,7 @@ grub_reed_solomon_recover (void *ptr_, grub_size_t s, grub_size_t rs) gf_single_t *ptr = ptr_; gf_single_t *rptr = ptr + s; -#if defined (STANDALONE) && !defined (TEST) +#if defined (STANDALONE) init_inverts (); #endif @@ -475,7 +477,9 @@ main (int argc, char **argv) scratch = xmalloc (1048576); #endif +#ifndef STANDALONE init_inverts (); +#endif in = fopen ("tst.bin", "rb"); if (!in) @@ -487,6 +491,10 @@ main (int argc, char **argv) buf = xmalloc (s + rs + SECTOR_SIZE); fread (buf, 1, s, in); + s = 0x5fbb; + rs = 0x6af9; + +#if 0 grub_reed_solomon_add_redundancy (buf, s, rs); out = fopen ("tst_rs.bin", "wb"); @@ -498,7 +506,9 @@ main (int argc, char **argv) out = fopen ("tst_dam.bin", "wb"); fwrite (buf, 1, s + rs, out); fclose (out); - +#endif + s = 0x5fbb; + rs = 0x6af9; grub_reed_solomon_recover (buf, s, rs); out = fopen ("tst_rec.bin", "wb"); diff --git a/include/grub/offsets.h b/include/grub/offsets.h index b8fbe40d4..28db0115c 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -41,9 +41,9 @@ #define GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE 0x20 /* The size of the first region which won't be compressed. */ -#define GRUB_KERNEL_I386_PC_RAW_SIZE 0xc6c +#define GRUB_KERNEL_I386_PC_RAW_SIZE 0xc80 -#define GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART 0x748 +#define GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART 0x75c /* The offset of GRUB_PREFIX. */ #define GRUB_KERNEL_I386_PC_PREFIX GRUB_KERNEL_I386_PC_RAW_SIZE diff --git a/util/grub-setup.c b/util/grub-setup.c index 1518bb0a8..953f0038b 100644 --- a/util/grub-setup.c +++ b/util/grub-setup.c @@ -438,7 +438,7 @@ setup (const char *dir, 0, GRUB_DISK_SECTOR_SIZE); block = first_block; - for (i = 1; i < core_sectors; i++) + for (i = 1; i < nsec; i++) save_blocklists (sectors[i] + grub_partition_get_start (container), 0, GRUB_DISK_SECTOR_SIZE); From 25e09515ad227965a31fde020aa406afdb0c4492 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 25 Sep 2010 21:42:13 +0200 Subject: [PATCH 4/7] Make mb header to protected part --- grub-core/kern/i386/pc/startup.S | 106 +++++++++++++++---------------- include/grub/offsets.h | 4 +- 2 files changed, 53 insertions(+), 57 deletions(-) diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S index 9319df98e..c4abc31b8 100644 --- a/grub-core/kern/i386/pc/startup.S +++ b/grub-core/kern/i386/pc/startup.S @@ -109,7 +109,58 @@ bss_start: bss_end: .long 0 #endif +/* + * This is the area for all of the special variables. + */ +VARIABLE(grub_boot_drive) + .byte 0 + +/* the real mode code continues... */ +LOCAL (codestart): + cli /* we're not safe here! */ + + /* set up %ds, %ss, and %es */ + xorw %ax, %ax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + /* set up the real mode/BIOS stack */ + movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp + movl %ebp, %esp + + sti /* we're safe again */ + + /* save the boot drive */ + ADDR32 movb %dl, EXT_C(grub_boot_drive) + + /* reset disk system (%ah = 0) */ + int $0x13 + + /* transition to protected mode */ + DATA32 call real_to_prot + + /* The ".code32" directive takes GAS out of 16-bit mode. */ + .code32 + + incl %eax + call grub_gate_a20 + + movl EXT_C(grub_compressed_size), %edx + addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART), %edx + movl reed_solomon_redundancy, %ecx + leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax + testl %edx, %edx + jz post_reed_solomon + call EXT_C (grub_reed_solomon_recover) + jmp post_reed_solomon + +#include + + .text + + . = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART /* * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself). * This uses the a.out kludge to load raw binary to the area starting at 1MB, @@ -173,53 +224,7 @@ multiboot_trampoline: movb $0xFF, %dh /* enter the usual booting */ call prot_to_real - .code16 -/* the real mode code continues... */ -LOCAL (codestart): - cli /* we're not safe here! */ - - /* set up %ds, %ss, and %es */ - xorw %ax, %ax - movw %ax, %ds - movw %ax, %ss - movw %ax, %es - - /* set up the real mode/BIOS stack */ - movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp - movl %ebp, %esp - - sti /* we're safe again */ - - /* save the boot drive */ - ADDR32 movb %dl, EXT_C(grub_boot_drive) - - /* reset disk system (%ah = 0) */ - int $0x13 - - /* transition to protected mode */ - DATA32 call real_to_prot - - /* The ".code32" directive takes GAS out of 16-bit mode. */ - .code32 - - incl %eax - call grub_gate_a20 - - movl EXT_C(grub_compressed_size), %edx - addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART), %edx - movl reed_solomon_redundancy, %ecx - leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax - testl %edx, %edx - jz post_reed_solomon - call EXT_C (grub_reed_solomon_recover) - jmp post_reed_solomon - -#include - - .text - - . = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART post_reed_solomon: #ifdef ENABLE_LZMA @@ -289,15 +294,6 @@ post_reed_solomon: */ call EXT_C(grub_main) -/* - * This is the area for all of the special variables. - */ - -VARIABLE(grub_boot_drive) - .byte 0 - - .p2align 2 /* force 4-byte alignment */ - #include "../realmode.S" /* diff --git a/include/grub/offsets.h b/include/grub/offsets.h index 28db0115c..f11dffaca 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -41,9 +41,9 @@ #define GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE 0x20 /* The size of the first region which won't be compressed. */ -#define GRUB_KERNEL_I386_PC_RAW_SIZE 0xc80 +#define GRUB_KERNEL_I386_PC_RAW_SIZE 0xc90 -#define GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART 0x75c +#define GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART 0x6f8 /* The offset of GRUB_PREFIX. */ #define GRUB_KERNEL_I386_PC_PREFIX GRUB_KERNEL_I386_PC_RAW_SIZE From 53c9e7798cd9c70bc7b04220fa514013dfc28a6b Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 25 Sep 2010 21:42:36 +0200 Subject: [PATCH 5/7] Remove debug printf --- grub-core/lib/reed_solomon.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c index f87ff1552..4c6e160e4 100644 --- a/grub-core/lib/reed_solomon.c +++ b/grub-core/lib/reed_solomon.c @@ -412,8 +412,6 @@ grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, gf_single_t *ptr = buffer; gf_single_t *rptr = ptr + s; - grub_printf ("solomon: %p, %x, %x\n", buffer, data_size, redundancy); - while (s > 0) { grub_size_t tt; From 40ca6b29fdcf97422cb8c882b5a9cffce87b2107 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 25 Sep 2010 21:43:04 +0200 Subject: [PATCH 6/7] Fix missing mreparm=3 --- grub-core/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index a740cb5cb..294888909 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -50,7 +50,7 @@ grub_script.yy.h: script/yylex.l grub_script.yy.c: grub_script.yy.h rs_decoder.S: $(srcdir)/lib/reed_solomon.c - $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -I$(top_builddir) -S -DSTANDALONE -o $@ $< -g0 + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -I$(top_builddir) -S -DSTANDALONE -o $@ $< -g0 -mregparm=3 CLEANFILES += grub_script.yy.c grub_script.yy.h From 4e2b20a79afe61df9901e943a453624f2453018f Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 26 Sep 2010 13:37:08 +0200 Subject: [PATCH 7/7] Add missing dependency on rs_Decoder.S --- grub-core/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 294888909..1881c5844 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -52,6 +52,8 @@ grub_script.yy.c: grub_script.yy.h rs_decoder.S: $(srcdir)/lib/reed_solomon.c $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -I$(top_builddir) -S -DSTANDALONE -o $@ $< -g0 -mregparm=3 +kern/i386/pc/startup.S: $(builddir)/rs_decoder.S + CLEANFILES += grub_script.yy.c grub_script.yy.h include $(srcdir)/Makefile.core.am