C part of Reed-Solomon
This commit is contained in:
		
							parent
							
								
									6d0fa83c79
								
							
						
					
					
						commit
						4f0de6881c
					
				
					 9 changed files with 553 additions and 23 deletions
				
			
		|  | @ -244,6 +244,7 @@ program = { | ||||||
|   common = util/grub-setup.c; |   common = util/grub-setup.c; | ||||||
|   common = util/raid.c; |   common = util/raid.c; | ||||||
|   common = util/lvm.c; |   common = util/lvm.c; | ||||||
|  |   common = util/reed_solomon.c; | ||||||
| 
 | 
 | ||||||
|   sparc64_ieee1275 = util/ieee1275/ofpath.c; |   sparc64_ieee1275 = util/ieee1275/ofpath.c; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -100,6 +100,8 @@ VARIABLE(grub_install_dos_part) | ||||||
| 	.long	0xFFFFFFFF
 | 	.long	0xFFFFFFFF
 | ||||||
| VARIABLE(grub_install_bsd_part) | VARIABLE(grub_install_bsd_part) | ||||||
| 	.long	0xFFFFFFFF
 | 	.long	0xFFFFFFFF
 | ||||||
|  | reed_solomon_redundancy: | ||||||
|  | 	.long	0
 | ||||||
| 
 | 
 | ||||||
| #ifdef APPLE_CC | #ifdef APPLE_CC | ||||||
| bss_start: | bss_start: | ||||||
|  |  | ||||||
|  | @ -124,9 +124,9 @@ gpt_partition_map_iterate (grub_disk_t disk, | ||||||
| 
 | 
 | ||||||
| #ifdef GRUB_UTIL | #ifdef GRUB_UTIL | ||||||
| static grub_err_t | 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_embed_type_t embed_type, | ||||||
| 			 grub_disk_addr_t *sectors) | 			 grub_disk_addr_t **sectors) | ||||||
| { | { | ||||||
|   grub_disk_addr_t start = 0, len = 0; |   grub_disk_addr_t start = 0, len = 0; | ||||||
|   unsigned i; |   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;" | 		       "This GPT partition label has no BIOS Boot Partition;" | ||||||
| 		       " embedding won't be possible!"); | 		       " embedding won't be possible!"); | ||||||
| 
 | 
 | ||||||
|   if (len < nsectors) |   if (len < *nsectors) | ||||||
|     return grub_error (GRUB_ERR_OUT_OF_RANGE, |     return grub_error (GRUB_ERR_OUT_OF_RANGE, | ||||||
| 		       "Your BIOS Boot Partition is too small;" | 		       "Your BIOS Boot Partition is too small;" | ||||||
| 		       " embedding won't be possible!"); | 		       " embedding won't be possible!"); | ||||||
| 
 | 
 | ||||||
|   for (i = 0; i < nsectors; i++) |   *nsectors = len; | ||||||
|     sectors[i] = start + i; |   *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; |   return GRUB_ERR_NONE; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -145,9 +145,9 @@ grub_partition_msdos_iterate (grub_disk_t disk, | ||||||
| 
 | 
 | ||||||
| #ifdef GRUB_UTIL | #ifdef GRUB_UTIL | ||||||
| static grub_err_t | 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_embed_type_t embed_type, | ||||||
| 			grub_disk_addr_t *sectors) | 			grub_disk_addr_t **sectors) | ||||||
| { | { | ||||||
|   grub_disk_addr_t end = ~0ULL; |   grub_disk_addr_t end = ~0ULL; | ||||||
|   struct grub_msdos_partition_mbr mbr; |   struct grub_msdos_partition_mbr mbr; | ||||||
|  | @ -232,11 +232,15 @@ pc_partition_map_embed (struct grub_disk *disk, unsigned int nsectors, | ||||||
| 	break; | 	break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   if (end >= nsectors + 1) |   if (end >= *nsectors + 1) | ||||||
|     { |     { | ||||||
|       int i; |       int i; | ||||||
|       for (i = 0; i < nsectors; i++) |       *nsectors = end - 1; | ||||||
| 	sectors[i] = 1 + i; |       *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; |       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 " | 		       "This msdos-style partition label has no " | ||||||
| 		       "post-MBR gap; embedding won't be possible!"); | 		       "post-MBR gap; embedding won't be possible!"); | ||||||
| 
 | 
 | ||||||
|   if (nsectors > 62) |   if (*nsectors > 62) | ||||||
|     return grub_error (GRUB_ERR_OUT_OF_RANGE, |     return grub_error (GRUB_ERR_OUT_OF_RANGE, | ||||||
| 		       "Your core.img is unusually large.  " | 		       "Your core.img is unusually large.  " | ||||||
| 		       "It won't fit in the embedding area."); | 		       "It won't fit in the embedding area."); | ||||||
|  |  | ||||||
|  | @ -34,11 +34,16 @@ | ||||||
| /* The offset of GRUB_INSTALL_BSD_PART.  */ | /* The offset of GRUB_INSTALL_BSD_PART.  */ | ||||||
| #define GRUB_KERNEL_I386_PC_INSTALL_BSD_PART	0x18 | #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.  */ | /* 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.  */ | /* 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.  */ | /* The offset of GRUB_PREFIX.  */ | ||||||
| #define GRUB_KERNEL_I386_PC_PREFIX		GRUB_KERNEL_I386_PC_RAW_SIZE | #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)); | 				      const grub_partition_t partition)); | ||||||
| #ifdef GRUB_UTIL | #ifdef GRUB_UTIL | ||||||
|   /* Determine sectors available for embedding.  */ |   /* Determine sectors available for embedding.  */ | ||||||
|   grub_err_t (*embed) (struct grub_disk *disk, unsigned int nsectors, |   grub_err_t (*embed) (struct grub_disk *disk, unsigned int *nsectors, | ||||||
| 		       grub_embed_type_t embed_type, grub_disk_addr_t *sectors); | 		       grub_embed_type_t embed_type, | ||||||
|  | 		       grub_disk_addr_t **sectors); | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
| typedef struct grub_partition_map *grub_partition_map_t; | 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 <assert.h> | ||||||
| #include <grub/emu/getroot.h> | #include <grub/emu/getroot.h> | ||||||
| #include "progname.h" | #include "progname.h" | ||||||
|  | #include <grub/reed_solomon.h> | ||||||
| 
 | 
 | ||||||
| #define _GNU_SOURCE	1 | #define _GNU_SOURCE	1 | ||||||
| #include <argp.h> | #include <argp.h> | ||||||
|  | @ -336,9 +337,10 @@ setup (const char *dir, | ||||||
|     grub_partition_t container = dest_dev->disk->partition; |     grub_partition_t container = dest_dev->disk->partition; | ||||||
|     int multiple_partmaps = 0; |     int multiple_partmaps = 0; | ||||||
|     grub_err_t err; |     grub_err_t err; | ||||||
|     grub_disk_addr_t sectors[core_sectors]; |     grub_disk_addr_t *sectors; | ||||||
|     int i; |     int i; | ||||||
|     grub_fs_t fs; |     grub_fs_t fs; | ||||||
|  |     unsigned int nsec; | ||||||
| 
 | 
 | ||||||
|     /* Unlike root_dev, with dest_dev we're interested in the partition map even
 |     /* Unlike root_dev, with dest_dev we're interested in the partition map even
 | ||||||
|        if dest_dev itself is a whole disk.  */ |        if dest_dev itself is a whole disk.  */ | ||||||
|  | @ -419,8 +421,11 @@ setup (const char *dir, | ||||||
| 	goto unable_to_embed; | 	goto unable_to_embed; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|     err = dest_partmap->embed (dest_dev->disk, core_sectors, |     nsec = core_sectors; | ||||||
| 			       GRUB_EMBED_PCBIOS, sectors); |     err = dest_partmap->embed (dest_dev->disk, &nsec, | ||||||
|  | 			       GRUB_EMBED_PCBIOS, §ors); | ||||||
|  |     if (nsec > 2 * core_sectors) | ||||||
|  |       nsec = 2 * core_sectors; | ||||||
|      |      | ||||||
|     if (err) |     if (err) | ||||||
|       { |       { | ||||||
|  | @ -439,6 +444,20 @@ setup (const char *dir, | ||||||
| 
 | 
 | ||||||
|     write_rootdev (core_img, root_dev, boot_img, first_sector); |     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.  */ |     /* Make sure that the second blocklist is a terminator.  */ | ||||||
|     block = first_block - 1; |     block = first_block - 1; | ||||||
|     block->start = 0; |     block->start = 0; | ||||||
|  | @ -446,14 +465,13 @@ setup (const char *dir, | ||||||
|     block->segment = 0; |     block->segment = 0; | ||||||
| 
 | 
 | ||||||
|     /* Write the core image onto the disk.  */ |     /* 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, |       grub_disk_write (dest_dev->disk, sectors[i], 0, | ||||||
| 		       (core_size - i * GRUB_DISK_SECTOR_SIZE | 		       GRUB_DISK_SECTOR_SIZE, | ||||||
| 			< GRUB_DISK_SECTOR_SIZE) ? core_size |  | ||||||
| 		       - i * GRUB_DISK_SECTOR_SIZE |  | ||||||
| 		       : GRUB_DISK_SECTOR_SIZE, |  | ||||||
| 		       core_img + i * GRUB_DISK_SECTOR_SIZE); | 		       core_img + i * GRUB_DISK_SECTOR_SIZE); | ||||||
| 
 | 
 | ||||||
|  |     grub_free (sectors); | ||||||
|  | 
 | ||||||
|     goto finish; |     goto finish; | ||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
							
								
								
									
										465
									
								
								util/reed_solomon.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								util/reed_solomon.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 <http://www.gnu.org/licenses/>.
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifdef TEST | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | 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 <grub/types.h> | ||||||
|  | #include <grub/reed_solomon.h> | ||||||
|  | #include <grub/util/misc.h> | ||||||
|  | #include <grub/misc.h> | ||||||
|  | #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 | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue