Write embedding zone using Reed-Solomon.
* Makefile.util.def (grub-setup): Add grub-core/lib/reed_solomon.c. * grub-core/Makefile.am (rs_decoder.S): New target. (kern/i386/pc/startup.S): Depend on rs_decoder.S. * grub-core/kern/i386/pc/startup.S (reed_solomon_redundancy): New field. (multiboot): Move to RS part. (post_reed_solomon): New label. (grub_boot_drive): Move to non-RS part since it's modified in memory on boot. Include rs_decoder.S. * grub-core/lib/reed_solomon.c: New file. * include/grub/offsets.h (GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY): New definition. (GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE): Removed. (GRUB_KERNEL_I386_PC_RAW_SIZE): Updated. (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART): New definition. * include/grub/partition.h (grub_partition_map): Change prototype of embed to allow returning additional sectors. * include/grub/reed_solomon.h: New file. * util/grub-setup.c (setup): Handle Reed-Solomon.
This commit is contained in:
commit
b65830fae1
11 changed files with 687 additions and 65 deletions
24
ChangeLog
24
ChangeLog
|
@ -1,3 +1,27 @@
|
|||
2010-09-29 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Write embedding zone using Reed-Solomon.
|
||||
|
||||
* Makefile.util.def (grub-setup): Add grub-core/lib/reed_solomon.c.
|
||||
* grub-core/Makefile.am (rs_decoder.S): New target.
|
||||
(kern/i386/pc/startup.S): Depend on rs_decoder.S.
|
||||
* grub-core/kern/i386/pc/startup.S (reed_solomon_redundancy): New field.
|
||||
(multiboot): Move to RS part.
|
||||
(post_reed_solomon): New label.
|
||||
(grub_boot_drive): Move to non-RS part since it's modified in memory
|
||||
on boot.
|
||||
Include rs_decoder.S.
|
||||
* grub-core/lib/reed_solomon.c: New file.
|
||||
* include/grub/offsets.h (GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY):
|
||||
New definition.
|
||||
(GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE): Removed.
|
||||
(GRUB_KERNEL_I386_PC_RAW_SIZE): Updated.
|
||||
(GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART): New definition.
|
||||
* include/grub/partition.h (grub_partition_map): Change prototype of
|
||||
embed to allow returning additional sectors.
|
||||
* include/grub/reed_solomon.h: New file.
|
||||
* util/grub-setup.c (setup): Handle Reed-Solomon.
|
||||
|
||||
2010-09-28 Colin Watson <cjwatson@ubuntu.com>
|
||||
|
||||
* grub-core/loader/multiboot_mbi2.c (grub_multiboot_make_mbi): Fix
|
||||
|
|
|
@ -244,6 +244,7 @@ program = {
|
|||
common = util/grub-setup.c;
|
||||
common = util/raid.c;
|
||||
common = util/lvm.c;
|
||||
common = grub-core/lib/reed_solomon.c;
|
||||
|
||||
sparc64_ieee1275 = util/ieee1275/ofpath.c;
|
||||
|
||||
|
|
|
@ -48,6 +48,12 @@ 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 $@ $< -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
|
||||
|
|
|
@ -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:
|
||||
|
@ -107,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 <rs_decoder.S>
|
||||
|
||||
.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,
|
||||
|
@ -171,38 +224,8 @@ 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
|
||||
post_reed_solomon:
|
||||
|
||||
#ifdef ENABLE_LZMA
|
||||
movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
|
||||
|
@ -271,15 +294,6 @@ LOCAL (codestart):
|
|||
*/
|
||||
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"
|
||||
|
||||
/*
|
||||
|
|
518
grub-core/lib/reed_solomon.c
Normal file
518
grub-core/lib/reed_solomon.c
Normal file
|
@ -0,0 +1,518 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifdef TEST
|
||||
#include <stdio.h>
|
||||
#define xmalloc malloc
|
||||
#define grub_memset memset
|
||||
#define grub_memcpy memcpy
|
||||
#endif
|
||||
|
||||
#ifndef STANDALONE
|
||||
#ifdef TEST
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
typedef unsigned int grub_size_t;
|
||||
typedef unsigned char grub_uint8_t;
|
||||
typedef unsigned short grub_uint16_t;
|
||||
#else
|
||||
#include <grub/types.h>
|
||||
#include <grub/reed_solomon.h>
|
||||
#include <grub/util/misc.h>
|
||||
#include <grub/misc.h>
|
||||
#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 <grub/types.h>
|
||||
#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;
|
||||
#define GF_POLYNOMIAL 0x1d
|
||||
#define GF_INVERT2 0x8e
|
||||
#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
|
||||
#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 void
|
||||
init_inverts (void)
|
||||
{
|
||||
gf_single_t a = 1, ai = 1;
|
||||
do
|
||||
{
|
||||
a = gf_mul (a, 2);
|
||||
ai = gf_mul (ai, GF_INVERT2);
|
||||
gf_invert[a] = ai;
|
||||
}
|
||||
while (a != 1);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if !defined (STANDALONE)
|
||||
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);
|
||||
}
|
||||
#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;
|
||||
unsigned 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
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
#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;
|
||||
|
||||
#ifndef STANDALONE
|
||||
eq = xmalloc (rs2 * (rs2 + 1) * sizeof (gf_single_t));
|
||||
#else
|
||||
eq = (void *) scratch;
|
||||
scratch += rs2 * (rs2 + 1) * sizeof (gf_single_t);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < (int) rs; i++)
|
||||
if (sy[i] != 0)
|
||||
break;
|
||||
|
||||
/* No error detected. */
|
||||
if (i == (int) rs)
|
||||
return;
|
||||
|
||||
for (i = 0; i < (int) rs2; i++)
|
||||
for (j = 0; j < (int) rs2 + 1; j++)
|
||||
eq[i * (rs2 + 1) + j] = sy[i+j];
|
||||
|
||||
for (i = 0; i < (int) rs2; i++)
|
||||
sigma[i] = 0;
|
||||
|
||||
gauss_solve (eq, rs2, rs2, sigma);
|
||||
|
||||
#ifndef STANDALONE
|
||||
free (eq);
|
||||
#else
|
||||
scratch -= rs2 * (rs2 + 1) * sizeof (gf_single_t);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
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)
|
||||
{
|
||||
errpot[errnum] = yn;
|
||||
errpos[errnum++] = s + rs - i - 1;
|
||||
}
|
||||
yn = gf_mul (yn, 2);
|
||||
xn = gf_mul (xn, GF_INVERT2);
|
||||
}
|
||||
}
|
||||
{
|
||||
gf_single_t *errvals;
|
||||
gf_single_t *eq;
|
||||
|
||||
#ifndef STANDALONE
|
||||
eq = xmalloc (rs * (errnum + 1) * sizeof (gf_single_t));
|
||||
errvals = xmalloc (errnum * sizeof (int));
|
||||
#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 < (int) rs; i++)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 < (int) ds; j++)
|
||||
m[j] = ptr[SECTOR_SIZE * j + i];
|
||||
for (j = 0; j < (int) rr; j++)
|
||||
m[j + ds] = rptr[SECTOR_SIZE * j + i];
|
||||
|
||||
rs_recover (m, ds, rr);
|
||||
|
||||
for (j = 0; j < (int) ds; j++)
|
||||
ptr[SECTOR_SIZE * j + i] = m[j];
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined (STANDALONE)
|
||||
static void
|
||||
encode_block (gf_single_t *ptr, grub_size_t s,
|
||||
gf_single_t *rptr, grub_size_t rs)
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined (STANDALONE)
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
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)
|
||||
init_inverts ();
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
#ifdef STANDALONE
|
||||
scratch = xmalloc (1048576);
|
||||
#endif
|
||||
|
||||
#ifndef STANDALONE
|
||||
init_inverts ();
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
s = 0x5fbb;
|
||||
rs = 0x6af9;
|
||||
|
||||
#if 0
|
||||
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);
|
||||
#endif
|
||||
s = 0x5fbb;
|
||||
rs = 0x6af9;
|
||||
grub_reed_solomon_recover (buf, s, rs);
|
||||
|
||||
out = fopen ("tst_rec.bin", "wb");
|
||||
fwrite (buf, 1, s, out);
|
||||
fclose (out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -34,11 +34,13 @@
|
|||
/* The offset of GRUB_INSTALL_BSD_PART. */
|
||||
#define GRUB_KERNEL_I386_PC_INSTALL_BSD_PART 0x18
|
||||
|
||||
/* The offset of multiboot signature. */
|
||||
#define GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE 0x1c
|
||||
/* Offset of reed_solomon_redundancy. */
|
||||
#define GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY 0x1c
|
||||
|
||||
/* 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 0xc90
|
||||
|
||||
#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
|
||||
|
|
|
@ -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;
|
||||
|
|
30
include/grub/reed_solomon.h
Normal file
30
include/grub/reed_solomon.h
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
|
@ -48,6 +48,7 @@
|
|||
#include <assert.h>
|
||||
#include <grub/emu/getroot.h>
|
||||
#include "progname.h"
|
||||
#include <grub/reed_solomon.h>
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
#include <argp.h>
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -433,12 +438,26 @@ 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);
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue