blob: 3b8e57969f2a0a6b1bd0ee9ca77c972709478d9f [file] [log] [blame]
Nick Sanders47219162011-03-13 01:30:54 -08001/* Copyright 2010, Google Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Alternatively, this software may be distributed under the terms of the
31 * GNU General Public License ("GPL") version 2 as published by the Free
32 * Software Foundation.
33 *
34 * This is ported from the flashmap utility: http://flashmap.googlecode.com
35 */
36
37#include <stdlib.h>
38#include <string.h>
39
40#include "flash.h"
41#include "fmap.h"
42
43extern int fmap_find(struct flashchip *flash, uint8_t **buf)
44{
45 unsigned long int offset = 0;
46 uint64_t sig, tmp64;
Nick Sanders47219162011-03-13 01:30:54 -080047 struct fmap fmap;
Nick Sanders56e829f2011-03-13 01:41:22 -080048 int fmap_size, fmap_found = 0, stride;
Nick Sanders47219162011-03-13 01:30:54 -080049
50 memcpy(&sig, FMAP_SIGNATURE, strlen(FMAP_SIGNATURE));
51
52 /*
Nick Sanders47219162011-03-13 01:30:54 -080053 * For efficient operation, we start with the largest stride possible
54 * and then decrease the stride on each iteration. We will check for a
55 * remainder when modding the offset with the previous stride. This
56 * makes it so that each offset is only checked once.
Nick Sanders56e829f2011-03-13 01:41:22 -080057 *
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.
Nick Sanders47219162011-03-13 01:30:54 -080068 */
Nick Sanders56e829f2011-03-13 01:41:22 -080069 for (stride = (flash->total_size * 1024) / 2; stride >= 16; stride /= 2) {
70 for (offset = flash->total_size * 1024 - stride;
Nick Sanders47219162011-03-13 01:30:54 -080071 offset > 0;
Nick Sanders56e829f2011-03-13 01:41:22 -080072 offset -= stride) {
73 if (offset % (stride * 2) == 0)
Nick Sanders47219162011-03-13 01:30:54 -080074 continue;
Nick Sanders47219162011-03-13 01:30:54 -080075
76 if (flash->read(flash, (uint8_t *)&tmp64,
77 offset, sizeof(tmp64))) {
78 msg_gdbg("failed to read flash at "
79 "offset 0x%lx\n", offset);
80 return -1;
81 }
82
83 if (!memcmp(&tmp64, &sig, sizeof(sig))) {
84 fmap_found = 1;
85 break;
86 }
87 }
88 if (fmap_found)
89 break;
90 }
91
Nick Sanders56e829f2011-03-13 01:41:22 -080092 /* 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
Nick Sanders47219162011-03-13 01:30:54 -0800113 if (!fmap_found)
114 return 0;
115
116 if (flash->read(flash, (uint8_t *)&fmap, offset, sizeof(fmap))) {
117 msg_gdbg("failed to read flash at offset 0x%lx\n", offset);
118 return -1;
119 }
120
121 fmap_size = sizeof(fmap) + (fmap.nareas * sizeof(struct fmap_area));
122 *buf = malloc(fmap_size);
123
124 if (flash->read(flash, *buf, offset, fmap_size)) {
125 msg_gdbg("failed to read %d bytes at offset 0x%lx\n",
126 fmap_size, offset);
127 return -1;
128 }
129 return fmap_size;
130}