2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
23 #define xmalloc malloc
24 #define grub_memset memset
25 #define grub_memcpy memcpy
34 typedef unsigned int grub_size_t
;
35 typedef unsigned char grub_uint8_t
;
37 #include <grub/types.h>
38 #include <grub/reed_solomon.h>
39 #include <grub/util/misc.h>
40 #include <grub/misc.h>
44 #define SECTOR_SIZE 512
45 #define MAX_BLOCK_SIZE (200 * SECTOR_SIZE)
49 typedef unsigned int grub_size_t
;
50 typedef unsigned char grub_uint8_t
;
52 #include <grub/types.h>
53 #include <grub/misc.h>
56 grub_reed_solomon_recover (void *ptr_
, grub_size_t s
, grub_size_t rs
);
60 typedef grub_uint8_t gf_single_t
;
61 #define GF_POLYNOMIAL 0x1d
62 #define GF_INVERT2 0x8e
63 #if defined (STANDALONE) && !defined (TEST)
64 static gf_single_t
* const gf_powx
__attribute__ ((section(".text"))) = (void *) 0x100000;
65 static gf_single_t
* const gf_powx_inv
__attribute__ ((section(".text"))) = (void *) 0x100200;
66 static int *const chosenstat
__attribute__ ((section(".text"))) = (void *) 0x100300;
67 static gf_single_t
*const sigma
__attribute__ ((section(".text"))) = (void *) 0x100700;
68 static gf_single_t
*const errpot
__attribute__ ((section(".text"))) = (void *) 0x100800;
69 static int *const errpos
__attribute__ ((section(".text"))) = (void *) 0x100900;
70 static gf_single_t
*const sy
__attribute__ ((section(".text"))) = (void *) 0x100d00;
71 static gf_single_t
*const mstat
__attribute__ ((section(".text"))) = (void *) 0x100e00;
72 static gf_single_t
*const errvals
__attribute__ ((section(".text"))) = (void *) 0x100f00;
73 static gf_single_t
*const eqstat
__attribute__ ((section(".text"))) = (void *) 0x101000;
74 /* Next available address: (void *) 0x112000. */
77 static gf_single_t gf_powx
[255 * 2];
78 static gf_single_t gf_powx_inv
[256];
79 static int chosenstat
[256];
80 static gf_single_t sigma
[256];
81 static gf_single_t errpot
[256];
82 static int errpos
[256];
83 static gf_single_t sy
[256];
84 static gf_single_t mstat
[256];
85 static gf_single_t errvals
[256];
86 static gf_single_t eqstat
[65536 + 256];
90 gf_mul (gf_single_t a
, gf_single_t b
)
94 return gf_powx
[(int) gf_powx_inv
[a
] + (int) gf_powx_inv
[b
]];
97 static inline gf_single_t
98 gf_invert (gf_single_t a
)
100 return gf_powx
[255 - (int) gf_powx_inv
[a
]];
107 grub_uint8_t cur
= 1;
110 for (i
= 0; i
< 255; i
++)
113 gf_powx
[i
+ 255] = cur
;
114 gf_powx_inv
[cur
] = i
;
115 if (cur
& (1ULL << (GF_SIZE
- 1)))
116 cur
= (cur
<< 1) ^ GF_POLYNOMIAL
;
123 pol_evaluate (gf_single_t
*pol
, grub_size_t degree
, int log_x
)
128 for (i
= degree
; i
>= 0; i
--)
131 s
^= gf_powx
[(int) gf_powx_inv
[pol
[i
]] + log_xn
];
133 if (log_xn
>= ((1 << GF_SIZE
) - 1))
134 log_xn
-= ((1 << GF_SIZE
) - 1);
139 #if !defined (STANDALONE)
141 rs_encode (gf_single_t
*data
, grub_size_t s
, grub_size_t rs
)
143 gf_single_t
*rs_polynomial
;
146 m
= xmalloc ((s
+ rs
) * sizeof (gf_single_t
));
147 grub_memcpy (m
, data
, s
* sizeof (gf_single_t
));
148 grub_memset (m
+ s
, 0, rs
* sizeof (gf_single_t
));
149 rs_polynomial
= xmalloc ((rs
+ 1) * sizeof (gf_single_t
));
150 grub_memset (rs_polynomial
, 0, (rs
+ 1) * sizeof (gf_single_t
));
151 rs_polynomial
[rs
] = 1;
152 /* Multiply with X - a^r */
153 for (j
= 0; j
< rs
; j
++)
155 for (i
= 0; i
< rs
; i
++)
156 if (rs_polynomial
[i
])
157 rs_polynomial
[i
] = (rs_polynomial
[i
+ 1]
158 ^ gf_powx
[j
+ (int) gf_powx_inv
[rs_polynomial
[i
]]]);
160 rs_polynomial
[i
] = rs_polynomial
[i
+ 1];
161 if (rs_polynomial
[rs
])
162 rs_polynomial
[rs
] = gf_powx
[j
+ (int) gf_powx_inv
[rs_polynomial
[rs
]]];
164 for (j
= 0; j
< s
; j
++)
167 gf_single_t f
= m
[j
];
168 for (i
= 0; i
<= rs
; i
++)
169 m
[i
+j
] ^= gf_mul (rs_polynomial
[i
], f
);
171 free (rs_polynomial
);
172 grub_memcpy (data
+ s
, m
+ s
, rs
* sizeof (gf_single_t
));
178 gauss_eliminate (gf_single_t
*eq
, int n
, int m
, int *chosen
)
182 for (i
= 0 ; i
< n
; i
++)
187 for (nzidx
= 0; nzidx
< m
&& (eq
[i
* (m
+ 1) + nzidx
] == 0);
192 r
= gf_invert (eq
[i
* (m
+ 1) + nzidx
]);
193 for (j
= 0; j
< m
+ 1; j
++)
194 eq
[i
* (m
+ 1) + j
] = gf_mul (eq
[i
* (m
+ 1) + j
], r
);
195 for (j
= i
+ 1; j
< n
; j
++)
197 gf_single_t rr
= eq
[j
* (m
+ 1) + nzidx
];
198 for (k
= 0; k
< m
+ 1; k
++)
199 eq
[j
* (m
+ 1) + k
] ^= gf_mul (eq
[i
* (m
+ 1) + k
], rr
);
205 gauss_solve (gf_single_t
*eq
, int n
, int m
, gf_single_t
*sol
)
209 for (i
= 0; i
< n
; i
++)
211 for (i
= 0; i
< m
; i
++)
213 gauss_eliminate (eq
, n
, m
, chosenstat
);
214 for (i
= n
- 1; i
>= 0; i
--)
217 if (chosenstat
[i
] == -1)
219 for (j
= 0; j
< m
; j
++)
220 s
^= gf_mul (eq
[i
* (m
+ 1) + j
], sol
[j
]);
221 s
^= eq
[i
* (m
+ 1) + m
];
222 sol
[chosenstat
[i
]] = s
;
227 rs_recover (gf_single_t
*mm
, grub_size_t s
, grub_size_t rs
)
229 grub_size_t rs2
= rs
/ 2;
233 for (i
= 0; i
< (int) rs
; i
++)
234 sy
[i
] = pol_evaluate (mm
, s
+ rs
- 1, i
);
236 for (i
= 0; i
< (int) rs
; i
++)
240 /* No error detected. */
246 for (i
= 0; i
< (int) rs2
; i
++)
247 for (j
= 0; j
< (int) rs2
+ 1; j
++)
248 eqstat
[i
* (rs2
+ 1) + j
] = sy
[i
+j
];
250 for (i
= 0; i
< (int) rs2
; i
++)
253 gauss_solve (eqstat
, rs2
, rs2
, sigma
);
256 for (i
= 0; i
< (int) (rs
+ s
); i
++)
257 if (pol_evaluate (sigma
, rs2
- 1, 255 - i
) == gf_powx
[i
])
259 errpot
[errnum
] = gf_powx
[i
];
260 errpos
[errnum
++] = s
+ rs
- i
- 1;
263 for (j
= 0; j
< errnum
; j
++)
265 eqstat
[errnum
] = sy
[0];
266 for (i
= 1; i
< (int) rs
; i
++)
268 for (j
= 0; j
< (int) errnum
; j
++)
269 eqstat
[(errnum
+ 1) * i
+ j
] = gf_mul (errpot
[j
],
270 eqstat
[(errnum
+ 1) * (i
- 1)
272 eqstat
[(errnum
+ 1) * i
+ errnum
] = sy
[i
];
275 gauss_solve (eqstat
, rs
, errnum
, errvals
);
277 for (i
= 0; i
< (int) errnum
; i
++)
278 mm
[errpos
[i
]] ^= errvals
[i
];
283 decode_block (gf_single_t
*ptr
, grub_size_t s
,
284 gf_single_t
*rptr
, grub_size_t rs
)
287 for (i
= 0; i
< SECTOR_SIZE
; i
++)
289 grub_size_t ds
= (s
+ SECTOR_SIZE
- 1 - i
) / SECTOR_SIZE
;
290 grub_size_t rr
= (rs
+ SECTOR_SIZE
- 1 - i
) / SECTOR_SIZE
;
296 for (j
= 0; j
< (int) ds
; j
++)
297 mstat
[j
] = ptr
[SECTOR_SIZE
* j
+ i
];
298 for (j
= 0; j
< (int) rr
; j
++)
299 mstat
[j
+ ds
] = rptr
[SECTOR_SIZE
* j
+ i
];
301 rs_recover (mstat
, ds
, rr
);
303 for (j
= 0; j
< (int) ds
; j
++)
304 ptr
[SECTOR_SIZE
* j
+ i
] = mstat
[j
];
308 #if !defined (STANDALONE)
310 encode_block (gf_single_t
*ptr
, grub_size_t s
,
311 gf_single_t
*rptr
, grub_size_t rs
)
314 for (i
= 0; i
< SECTOR_SIZE
; i
++)
316 grub_size_t ds
= (s
+ SECTOR_SIZE
- 1 - i
) / SECTOR_SIZE
;
317 grub_size_t rr
= (rs
+ SECTOR_SIZE
- 1 - i
) / SECTOR_SIZE
;
323 m
= xmalloc (ds
+ rr
);
324 for (j
= 0; j
< ds
; j
++)
325 m
[j
] = ptr
[SECTOR_SIZE
* j
+ i
];
326 rs_encode (m
, ds
, rr
);
327 for (j
= 0; j
< rr
; j
++)
328 rptr
[SECTOR_SIZE
* j
+ i
] = m
[j
+ ds
];
334 #if !defined (STANDALONE)
336 grub_reed_solomon_add_redundancy (void *buffer
, grub_size_t data_size
,
337 grub_size_t redundancy
)
339 grub_size_t s
= data_size
;
340 grub_size_t rs
= redundancy
;
341 gf_single_t
*ptr
= buffer
;
342 gf_single_t
*rptr
= ptr
+ s
;
345 tmp
= xmalloc (data_size
);
346 grub_memcpy (tmp
, buffer
, data_size
);
361 if (tt
> MAX_BLOCK_SIZE
)
363 cs
= ((cs
* (MAX_BLOCK_SIZE
/ 512)) / tt
) * 512;
364 crs
= ((crs
* (MAX_BLOCK_SIZE
/ 512)) / tt
) * 512;
366 encode_block (ptr
, cs
, rptr
, crs
);
374 assert (grub_memcmp (tmp
, buffer
, data_size
) == 0);
381 grub_reed_solomon_recover (void *ptr_
, grub_size_t s
, grub_size_t rs
)
383 gf_single_t
*ptr
= ptr_
;
384 gf_single_t
*rptr
= ptr
+ s
;
399 if (tt
> MAX_BLOCK_SIZE
)
401 cs
= ((cs
* (MAX_BLOCK_SIZE
/ 512)) / tt
) * 512;
402 crs
= ((crs
* (MAX_BLOCK_SIZE
/ 512)) / tt
) * 512;
404 decode_block (ptr
, cs
, rptr
, crs
);
414 main (int argc
, char **argv
)
420 grub_memset (gf_powx
, 0xee, sizeof (gf_powx
));
421 grub_memset (gf_powx_inv
, 0xdd, sizeof (gf_powx_inv
));
428 in
= fopen ("tst.bin", "rb");
431 fseek (in
, 0, SEEK_END
);
433 fseek (in
, 0, SEEK_SET
);
435 buf
= xmalloc (s
+ rs
+ SECTOR_SIZE
);
436 fread (buf
, 1, s
, in
);
439 grub_reed_solomon_add_redundancy (buf
, s
, rs
);
441 out
= fopen ("tst_rs.bin", "wb");
442 fwrite (buf
, 1, s
+ rs
, out
);
445 out
= fopen ("tst_rs.bin", "rb");
446 fseek (out
, 0, SEEK_END
);
448 fseek (out
, 0, SEEK_SET
);
452 buf
= xmalloc (s
+ rs
+ SECTOR_SIZE
);
453 fread (buf
, 1, s
+ rs
, out
);
457 grub_memset (buf
+ 512 * 15, 0, 512);
460 out
= fopen ("tst_dam.bin", "wb");
461 fwrite (buf
, 1, s
+ rs
, out
);
463 grub_reed_solomon_recover (buf
, s
, rs
);
465 out
= fopen ("tst_rec.bin", "wb");
466 fwrite (buf
, 1, s
, out
);