OLD | NEW |
1 /* Copyright 2010, Google Inc. | 1 /* Copyright 2010, Google Inc. |
2 * All rights reserved. | 2 * All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 26 matching lines...) Expand all Loading... |
37 #include <stdlib.h> | 37 #include <stdlib.h> |
38 #include <string.h> | 38 #include <string.h> |
39 | 39 |
40 #include "flash.h" | 40 #include "flash.h" |
41 #include "fmap.h" | 41 #include "fmap.h" |
42 | 42 |
43 extern int fmap_find(struct flashchip *flash, uint8_t **buf) | 43 extern int fmap_find(struct flashchip *flash, uint8_t **buf) |
44 { | 44 { |
45 unsigned long int offset = 0; | 45 unsigned long int offset = 0; |
46 uint64_t sig, tmp64; | 46 uint64_t sig, tmp64; |
47 int i, fmap_found = 0; | |
48 /* Note: keep the strides sorted in largest to smallest order for | |
49 efficient operation below. Strides should all be powers of 2. */ | |
50 unsigned int strides[] = { 64 * 1024, 4 * 1024, 64 }; | |
51 struct fmap fmap; | 47 struct fmap fmap; |
52 » int fmap_size; | 48 » int fmap_size, fmap_found = 0, stride; |
53 | 49 |
54 memcpy(&sig, FMAP_SIGNATURE, strlen(FMAP_SIGNATURE)); | 50 memcpy(&sig, FMAP_SIGNATURE, strlen(FMAP_SIGNATURE)); |
55 | 51 |
56 /* | 52 /* |
57 * Find FMAP signature within image. The alignment requirements | |
58 * increased over time due to speed concerns, so we'll use an array to | |
59 * represent the strides we wish to attempt to use. | |
60 * | |
61 * For efficient operation, we start with the largest stride possible | 53 * For efficient operation, we start with the largest stride possible |
62 * and then decrease the stride on each iteration. We will check for a | 54 * and then decrease the stride on each iteration. We will check for a |
63 * remainder when modding the offset with the previous stride. This | 55 * remainder when modding the offset with the previous stride. This |
64 * makes it so that each offset is only checked once. | 56 * makes it so that each offset is only checked once. |
| 57 * |
| 58 * At some point, programmer transaction overhead becomes greater than |
| 59 * simply copying everything into RAM and checking one byte at a time. |
| 60 * At some arbitrary point, we'll stop being clever and use brute |
| 61 * force instead by copying the while ROM into RAM and searching one |
| 62 * byte at a time. |
| 63 * |
| 64 * In practice, the flash map is usually stored in a write-protected |
| 65 * section of flash which is often at the top of ROM where the boot |
| 66 * vector on x86 resides. Because of this, we will search from top |
| 67 * to bottom. |
65 */ | 68 */ |
66 » for (i = 0; i < ARRAY_SIZE(strides); i++) { | 69 » for (stride = (flash->total_size * 1024) / 2; stride >= 16; stride /= 2)
{ |
67 » » for (offset = flash->total_size * 1024 - strides[i]; | 70 » » for (offset = flash->total_size * 1024 - stride; |
68 offset > 0; | 71 offset > 0; |
69 » » offset -= strides[i]) { | 72 » » offset -= stride) { |
70 » » » if (i > 0) { | 73 » » » if (offset % (stride * 2) == 0) |
71 » » » » if (offset % strides[i-1] == 0) | |
72 continue; | 74 continue; |
73 } | |
74 | 75 |
75 if (flash->read(flash, (uint8_t *)&tmp64, | 76 if (flash->read(flash, (uint8_t *)&tmp64, |
76 offset, sizeof(tmp64))) { | 77 offset, sizeof(tmp64))) { |
77 msg_gdbg("failed to read flash at " | 78 msg_gdbg("failed to read flash at " |
78 "offset 0x%lx\n", offset); | 79 "offset 0x%lx\n", offset); |
79 return -1; | 80 return -1; |
80 } | 81 } |
81 | 82 |
82 if (!memcmp(&tmp64, &sig, sizeof(sig))) { | 83 if (!memcmp(&tmp64, &sig, sizeof(sig))) { |
83 fmap_found = 1; | 84 fmap_found = 1; |
84 break; | 85 break; |
85 } | 86 } |
86 } | 87 } |
87 if (fmap_found) | 88 if (fmap_found) |
88 break; | 89 break; |
89 } | 90 } |
90 | 91 |
| 92 /* brute force */ |
| 93 /* FIXME: This results in the entire ROM being read twice -- once here |
| 94 * and again in doit(). The performance penalty needs to be dealt |
| 95 * with before going upstream. |
| 96 */ |
| 97 if (!fmap_found) { |
| 98 uint8_t *image = malloc(flash->total_size * 1024); |
| 99 |
| 100 msg_gdbg("using brute force method to find fmap\n"); |
| 101 flash->read(flash, image, 0, flash->total_size * 1024); |
| 102 for (offset = flash->total_size * 1024 - sizeof(sig); |
| 103 offset > 0; |
| 104 offset--) { |
| 105 if (!memcmp(&image[offset], &sig, sizeof(sig))) { |
| 106 fmap_found = 1; |
| 107 break; |
| 108 } |
| 109 } |
| 110 free(image); |
| 111 } |
| 112 |
91 if (!fmap_found) | 113 if (!fmap_found) |
92 return 0; | 114 return 0; |
93 | 115 |
94 if (flash->read(flash, (uint8_t *)&fmap, offset, sizeof(fmap))) { | 116 if (flash->read(flash, (uint8_t *)&fmap, offset, sizeof(fmap))) { |
95 msg_gdbg("failed to read flash at offset 0x%lx\n", offset); | 117 msg_gdbg("failed to read flash at offset 0x%lx\n", offset); |
96 return -1; | 118 return -1; |
97 } | 119 } |
98 | 120 |
99 fmap_size = sizeof(fmap) + (fmap.nareas * sizeof(struct fmap_area)); | 121 fmap_size = sizeof(fmap) + (fmap.nareas * sizeof(struct fmap_area)); |
100 *buf = malloc(fmap_size); | 122 *buf = malloc(fmap_size); |
101 | 123 |
102 if (flash->read(flash, *buf, offset, fmap_size)) { | 124 if (flash->read(flash, *buf, offset, fmap_size)) { |
103 msg_gdbg("failed to read %d bytes at offset 0x%lx\n", | 125 msg_gdbg("failed to read %d bytes at offset 0x%lx\n", |
104 fmap_size, offset); | 126 fmap_size, offset); |
105 return -1; | 127 return -1; |
106 } | 128 } |
107 return fmap_size; | 129 return fmap_size; |
108 } | 130 } |
OLD | NEW |