Commit 8b249b6856f16f09b0e5b79ce5f4d435e439b9d6

Authored by Sam Ravnborg
1 parent 8d1a0a13ed

fix modules_install via NFS

Rafael reported:

I get the following error from 'make modules_install' on my test boxes:

  HOSTCC  firmware/ihex2fw
/home/rafael/src/linux-2.6/firmware/ihex2fw.c:268: fatal error: opening dependency file firmware/.ihex2fw.d: Read-only file system
compilation terminated.
make[3]: *** [firmware/ihex2fw] Error 1
make[2]: *** [_modinst_post] Error 2
make[1]: *** [sub-make] Error 2
make: *** [all] Error 2

where the configuration is that the kernel is compiled on a build box
with 'make O=<destdir> -j5' and then <destdir> is mounted over NFS read-only by
each test box (full path to this directory is the same on the build box and on
the test boxes).  Then, I cd into <destdir>, run 'make modules_install' and get
the error above.

The issue turns out to be that we when we install firmware pick
up the list of firmware blobs from firmware/Makefile.
And this triggers the Makefile rules to update ihex2fw.

There were two solutions for this issue:
1) Move the list of firmware blobs to a separate file
2) Avoid ihex2fw rebuild by moving it to scripts

As I seriously beleive that the list of firmware blobs should be
done in a fundamental different way solution 2) was selected.

Reported-and-tested-by: "Rafael J. Wysocki" <rjw@sisk.pl>
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Cc: David Woodhouse <dwmw2@infradead.org>

Showing 6 changed files with 275 additions and 276 deletions Side-by-side Diff

... ... @@ -3,5 +3,4 @@
3 3 *.bin
4 4 *.csp
5 5 *.dsp
6   -ihex2fw
... ... @@ -99,10 +99,10 @@
99 99 cmd_ihex = $(OBJCOPY) -Iihex -Obinary $< $@
100 100  
101 101 quiet_cmd_ihex2fw = IHEX2FW $@
102   - cmd_ihex2fw = $(objtree)/$(obj)/ihex2fw $< $@
  102 + cmd_ihex2fw = $(objtree)/scripts/ihex2fw $< $@
103 103  
104 104 quiet_cmd_h16tofw = H16TOFW $@
105   - cmd_h16tofw = $(objtree)/$(obj)/ihex2fw -w $< $@
  105 + cmd_h16tofw = $(objtree)/scripts/ihex2fw -w $< $@
106 106  
107 107 quiet_cmd_fwbin = MK_FW $@
108 108 cmd_fwbin = FWNAME="$(patsubst firmware/%.gen.S,%,$@)"; \
109 109  
... ... @@ -165,11 +165,11 @@
165 165 # is actually meaningful, because the firmware has to be loaded in a certain
166 166 # order rather than as a single binary blob. Thus, we convert them into our
167 167 # more compact binary representation of ihex records (<linux/ihex.h>)
168   -$(obj)/%.fw: $(obj)/%.HEX $(obj)/ihex2fw | $(objtree)/$(obj)/$$(dir %)
  168 +$(obj)/%.fw: $(obj)/%.HEX | $(objtree)/$(obj)/$$(dir %)
169 169 $(call cmd,ihex2fw)
170 170  
171 171 # .H16 is our own modified form of Intel HEX, with 16-bit length for records.
172   -$(obj)/%.fw: $(obj)/%.H16 $(obj)/ihex2fw | $(objtree)/$(obj)/$$(dir %)
  172 +$(obj)/%.fw: $(obj)/%.H16 | $(objtree)/$(obj)/$$(dir %)
173 173 $(call cmd,h16tofw)
174 174  
175 175 $(firmware-dirs):
... ... @@ -186,6 +186,4 @@
186 186 # Without this, built-in.o won't be created when it's empty, and the
187 187 # final vmlinux link will fail.
188 188 obj-n := dummy
189   -
190   -hostprogs-y := ihex2fw
firmware/ihex2fw.c
1   -/*
2   - * Parser/loader for IHEX formatted data.
3   - *
4   - * Copyright © 2008 David Woodhouse <dwmw2@infradead.org>
5   - * Copyright © 2005 Jan Harkes <jaharkes@cs.cmu.edu>
6   - *
7   - * This program is free software; you can redistribute it and/or modify
8   - * it under the terms of the GNU General Public License version 2 as
9   - * published by the Free Software Foundation.
10   - */
11   -
12   -#include <stdint.h>
13   -#include <arpa/inet.h>
14   -#include <stdio.h>
15   -#include <errno.h>
16   -#include <sys/types.h>
17   -#include <sys/stat.h>
18   -#include <sys/mman.h>
19   -#include <fcntl.h>
20   -#include <string.h>
21   -#include <unistd.h>
22   -#include <stdlib.h>
23   -#define _GNU_SOURCE
24   -#include <getopt.h>
25   -
26   -
27   -struct ihex_binrec {
28   - struct ihex_binrec *next; /* not part of the real data structure */
29   - uint32_t addr;
30   - uint16_t len;
31   - uint8_t data[];
32   -};
33   -
34   -/**
35   - * nybble/hex are little helpers to parse hexadecimal numbers to a byte value
36   - **/
37   -static uint8_t nybble(const uint8_t n)
38   -{
39   - if (n >= '0' && n <= '9') return n - '0';
40   - else if (n >= 'A' && n <= 'F') return n - ('A' - 10);
41   - else if (n >= 'a' && n <= 'f') return n - ('a' - 10);
42   - return 0;
43   -}
44   -
45   -static uint8_t hex(const uint8_t *data, uint8_t *crc)
46   -{
47   - uint8_t val = (nybble(data[0]) << 4) | nybble(data[1]);
48   - *crc += val;
49   - return val;
50   -}
51   -
52   -static int process_ihex(uint8_t *data, ssize_t size);
53   -static void file_record(struct ihex_binrec *record);
54   -static int output_records(int outfd);
55   -
56   -static int sort_records = 0;
57   -static int wide_records = 0;
58   -
59   -int usage(void)
60   -{
61   - fprintf(stderr, "ihex2fw: Convert ihex files into binary "
62   - "representation for use by Linux kernel\n");
63   - fprintf(stderr, "usage: ihex2fw [<options>] <src.HEX> <dst.fw>\n");
64   - fprintf(stderr, " -w: wide records (16-bit length)\n");
65   - fprintf(stderr, " -s: sort records by address\n");
66   - return 1;
67   -}
68   -
69   -int main(int argc, char **argv)
70   -{
71   - int infd, outfd;
72   - struct stat st;
73   - uint8_t *data;
74   - int opt;
75   -
76   - while ((opt = getopt(argc, argv, "ws")) != -1) {
77   - switch (opt) {
78   - case 'w':
79   - wide_records = 1;
80   - break;
81   - case 's':
82   - sort_records = 1;
83   - break;
84   - default:
85   - return usage();
86   - }
87   - }
88   -
89   - if (optind + 2 != argc)
90   - return usage();
91   -
92   - if (!strcmp(argv[optind], "-"))
93   - infd = 0;
94   - else
95   - infd = open(argv[optind], O_RDONLY);
96   - if (infd == -1) {
97   - fprintf(stderr, "Failed to open source file: %s",
98   - strerror(errno));
99   - return usage();
100   - }
101   - if (fstat(infd, &st)) {
102   - perror("stat");
103   - return 1;
104   - }
105   - data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, infd, 0);
106   - if (data == MAP_FAILED) {
107   - perror("mmap");
108   - return 1;
109   - }
110   -
111   - if (!strcmp(argv[optind+1], "-"))
112   - outfd = 1;
113   - else
114   - outfd = open(argv[optind+1], O_TRUNC|O_CREAT|O_WRONLY, 0644);
115   - if (outfd == -1) {
116   - fprintf(stderr, "Failed to open destination file: %s",
117   - strerror(errno));
118   - return usage();
119   - }
120   - if (process_ihex(data, st.st_size))
121   - return 1;
122   -
123   - output_records(outfd);
124   - return 0;
125   -}
126   -
127   -static int process_ihex(uint8_t *data, ssize_t size)
128   -{
129   - struct ihex_binrec *record;
130   - uint32_t offset = 0;
131   - uint8_t type, crc = 0, crcbyte = 0;
132   - int i, j;
133   - int line = 1;
134   - int len;
135   -
136   - i = 0;
137   -next_record:
138   - /* search for the start of record character */
139   - while (i < size) {
140   - if (data[i] == '\n') line++;
141   - if (data[i++] == ':') break;
142   - }
143   -
144   - /* Minimum record length would be about 10 characters */
145   - if (i + 10 > size) {
146   - fprintf(stderr, "Can't find valid record at line %d\n", line);
147   - return -EINVAL;
148   - }
149   -
150   - len = hex(data + i, &crc); i += 2;
151   - if (wide_records) {
152   - len <<= 8;
153   - len += hex(data + i, &crc); i += 2;
154   - }
155   - record = malloc((sizeof (*record) + len + 3) & ~3);
156   - if (!record) {
157   - fprintf(stderr, "out of memory for records\n");
158   - return -ENOMEM;
159   - }
160   - memset(record, 0, (sizeof(*record) + len + 3) & ~3);
161   - record->len = len;
162   -
163   - /* now check if we have enough data to read everything */
164   - if (i + 8 + (record->len * 2) > size) {
165   - fprintf(stderr, "Not enough data to read complete record at line %d\n",
166   - line);
167   - return -EINVAL;
168   - }
169   -
170   - record->addr = hex(data + i, &crc) << 8; i += 2;
171   - record->addr |= hex(data + i, &crc); i += 2;
172   - type = hex(data + i, &crc); i += 2;
173   -
174   - for (j = 0; j < record->len; j++, i += 2)
175   - record->data[j] = hex(data + i, &crc);
176   -
177   - /* check CRC */
178   - crcbyte = hex(data + i, &crc); i += 2;
179   - if (crc != 0) {
180   - fprintf(stderr, "CRC failure at line %d: got 0x%X, expected 0x%X\n",
181   - line, crcbyte, (unsigned char)(crcbyte-crc));
182   - return -EINVAL;
183   - }
184   -
185   - /* Done reading the record */
186   - switch (type) {
187   - case 0:
188   - /* old style EOF record? */
189   - if (!record->len)
190   - break;
191   -
192   - record->addr += offset;
193   - file_record(record);
194   - goto next_record;
195   -
196   - case 1: /* End-Of-File Record */
197   - if (record->addr || record->len) {
198   - fprintf(stderr, "Bad EOF record (type 01) format at line %d",
199   - line);
200   - return -EINVAL;
201   - }
202   - break;
203   -
204   - case 2: /* Extended Segment Address Record (HEX86) */
205   - case 4: /* Extended Linear Address Record (HEX386) */
206   - if (record->addr || record->len != 2) {
207   - fprintf(stderr, "Bad HEX86/HEX386 record (type %02X) at line %d\n",
208   - type, line);
209   - return -EINVAL;
210   - }
211   -
212   - /* We shouldn't really be using the offset for HEX86 because
213   - * the wraparound case is specified quite differently. */
214   - offset = record->data[0] << 8 | record->data[1];
215   - offset <<= (type == 2 ? 4 : 16);
216   - goto next_record;
217   -
218   - case 3: /* Start Segment Address Record */
219   - case 5: /* Start Linear Address Record */
220   - if (record->addr || record->len != 4) {
221   - fprintf(stderr, "Bad Start Address record (type %02X) at line %d\n",
222   - type, line);
223   - return -EINVAL;
224   - }
225   -
226   - /* These records contain the CS/IP or EIP where execution
227   - * starts. Don't really know what to do with them. */
228   - goto next_record;
229   -
230   - default:
231   - fprintf(stderr, "Unknown record (type %02X)\n", type);
232   - return -EINVAL;
233   - }
234   -
235   - return 0;
236   -}
237   -
238   -static struct ihex_binrec *records;
239   -
240   -static void file_record(struct ihex_binrec *record)
241   -{
242   - struct ihex_binrec **p = &records;
243   -
244   - while ((*p) && (!sort_records || (*p)->addr < record->addr))
245   - p = &((*p)->next);
246   -
247   - record->next = *p;
248   - *p = record;
249   -}
250   -
251   -static int output_records(int outfd)
252   -{
253   - unsigned char zeroes[6] = {0, 0, 0, 0, 0, 0};
254   - struct ihex_binrec *p = records;
255   -
256   - while (p) {
257   - uint16_t writelen = (p->len + 9) & ~3;
258   -
259   - p->addr = htonl(p->addr);
260   - p->len = htons(p->len);
261   - write(outfd, &p->addr, writelen);
262   - p = p->next;
263   - }
264   - /* EOF record is zero length, since we don't bother to represent
265   - the type field in the binary version */
266   - write(outfd, zeroes, 6);
267   - return 0;
268   -}
1 1 #
2 2 # Generated files
3 3 #
  4 +ihex2fw
4 5 conmakehash
5 6 kallsyms
6 7 pnmtologo
... ... @@ -2,11 +2,12 @@
2 2 # scripts contains sources for various helper programs used throughout
3 3 # the kernel for the build process.
4 4 # ---------------------------------------------------------------------------
  5 +# ihex2fw: Parser/loader for IHEX formatted data
5 6 # kallsyms: Find all symbols in vmlinux
6 7 # pnmttologo: Convert pnm files to logo files
7   -# conmakehash: Create chartable
8 8 # conmakehash: Create arrays for initializing the kernel console tables
9 9  
  10 +hostprogs-y := ihex2fw
10 11 hostprogs-$(CONFIG_KALLSYMS) += kallsyms
11 12 hostprogs-$(CONFIG_LOGO) += pnmtologo
12 13 hostprogs-$(CONFIG_VT) += conmakehash
  1 +/*
  2 + * Parser/loader for IHEX formatted data.
  3 + *
  4 + * Copyright © 2008 David Woodhouse <dwmw2@infradead.org>
  5 + * Copyright © 2005 Jan Harkes <jaharkes@cs.cmu.edu>
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License version 2 as
  9 + * published by the Free Software Foundation.
  10 + */
  11 +
  12 +#include <stdint.h>
  13 +#include <arpa/inet.h>
  14 +#include <stdio.h>
  15 +#include <errno.h>
  16 +#include <sys/types.h>
  17 +#include <sys/stat.h>
  18 +#include <sys/mman.h>
  19 +#include <fcntl.h>
  20 +#include <string.h>
  21 +#include <unistd.h>
  22 +#include <stdlib.h>
  23 +#define _GNU_SOURCE
  24 +#include <getopt.h>
  25 +
  26 +
  27 +struct ihex_binrec {
  28 + struct ihex_binrec *next; /* not part of the real data structure */
  29 + uint32_t addr;
  30 + uint16_t len;
  31 + uint8_t data[];
  32 +};
  33 +
  34 +/**
  35 + * nybble/hex are little helpers to parse hexadecimal numbers to a byte value
  36 + **/
  37 +static uint8_t nybble(const uint8_t n)
  38 +{
  39 + if (n >= '0' && n <= '9') return n - '0';
  40 + else if (n >= 'A' && n <= 'F') return n - ('A' - 10);
  41 + else if (n >= 'a' && n <= 'f') return n - ('a' - 10);
  42 + return 0;
  43 +}
  44 +
  45 +static uint8_t hex(const uint8_t *data, uint8_t *crc)
  46 +{
  47 + uint8_t val = (nybble(data[0]) << 4) | nybble(data[1]);
  48 + *crc += val;
  49 + return val;
  50 +}
  51 +
  52 +static int process_ihex(uint8_t *data, ssize_t size);
  53 +static void file_record(struct ihex_binrec *record);
  54 +static int output_records(int outfd);
  55 +
  56 +static int sort_records = 0;
  57 +static int wide_records = 0;
  58 +
  59 +int usage(void)
  60 +{
  61 + fprintf(stderr, "ihex2fw: Convert ihex files into binary "
  62 + "representation for use by Linux kernel\n");
  63 + fprintf(stderr, "usage: ihex2fw [<options>] <src.HEX> <dst.fw>\n");
  64 + fprintf(stderr, " -w: wide records (16-bit length)\n");
  65 + fprintf(stderr, " -s: sort records by address\n");
  66 + return 1;
  67 +}
  68 +
  69 +int main(int argc, char **argv)
  70 +{
  71 + int infd, outfd;
  72 + struct stat st;
  73 + uint8_t *data;
  74 + int opt;
  75 +
  76 + while ((opt = getopt(argc, argv, "ws")) != -1) {
  77 + switch (opt) {
  78 + case 'w':
  79 + wide_records = 1;
  80 + break;
  81 + case 's':
  82 + sort_records = 1;
  83 + break;
  84 + default:
  85 + return usage();
  86 + }
  87 + }
  88 +
  89 + if (optind + 2 != argc)
  90 + return usage();
  91 +
  92 + if (!strcmp(argv[optind], "-"))
  93 + infd = 0;
  94 + else
  95 + infd = open(argv[optind], O_RDONLY);
  96 + if (infd == -1) {
  97 + fprintf(stderr, "Failed to open source file: %s",
  98 + strerror(errno));
  99 + return usage();
  100 + }
  101 + if (fstat(infd, &st)) {
  102 + perror("stat");
  103 + return 1;
  104 + }
  105 + data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, infd, 0);
  106 + if (data == MAP_FAILED) {
  107 + perror("mmap");
  108 + return 1;
  109 + }
  110 +
  111 + if (!strcmp(argv[optind+1], "-"))
  112 + outfd = 1;
  113 + else
  114 + outfd = open(argv[optind+1], O_TRUNC|O_CREAT|O_WRONLY, 0644);
  115 + if (outfd == -1) {
  116 + fprintf(stderr, "Failed to open destination file: %s",
  117 + strerror(errno));
  118 + return usage();
  119 + }
  120 + if (process_ihex(data, st.st_size))
  121 + return 1;
  122 +
  123 + output_records(outfd);
  124 + return 0;
  125 +}
  126 +
  127 +static int process_ihex(uint8_t *data, ssize_t size)
  128 +{
  129 + struct ihex_binrec *record;
  130 + uint32_t offset = 0;
  131 + uint8_t type, crc = 0, crcbyte = 0;
  132 + int i, j;
  133 + int line = 1;
  134 + int len;
  135 +
  136 + i = 0;
  137 +next_record:
  138 + /* search for the start of record character */
  139 + while (i < size) {
  140 + if (data[i] == '\n') line++;
  141 + if (data[i++] == ':') break;
  142 + }
  143 +
  144 + /* Minimum record length would be about 10 characters */
  145 + if (i + 10 > size) {
  146 + fprintf(stderr, "Can't find valid record at line %d\n", line);
  147 + return -EINVAL;
  148 + }
  149 +
  150 + len = hex(data + i, &crc); i += 2;
  151 + if (wide_records) {
  152 + len <<= 8;
  153 + len += hex(data + i, &crc); i += 2;
  154 + }
  155 + record = malloc((sizeof (*record) + len + 3) & ~3);
  156 + if (!record) {
  157 + fprintf(stderr, "out of memory for records\n");
  158 + return -ENOMEM;
  159 + }
  160 + memset(record, 0, (sizeof(*record) + len + 3) & ~3);
  161 + record->len = len;
  162 +
  163 + /* now check if we have enough data to read everything */
  164 + if (i + 8 + (record->len * 2) > size) {
  165 + fprintf(stderr, "Not enough data to read complete record at line %d\n",
  166 + line);
  167 + return -EINVAL;
  168 + }
  169 +
  170 + record->addr = hex(data + i, &crc) << 8; i += 2;
  171 + record->addr |= hex(data + i, &crc); i += 2;
  172 + type = hex(data + i, &crc); i += 2;
  173 +
  174 + for (j = 0; j < record->len; j++, i += 2)
  175 + record->data[j] = hex(data + i, &crc);
  176 +
  177 + /* check CRC */
  178 + crcbyte = hex(data + i, &crc); i += 2;
  179 + if (crc != 0) {
  180 + fprintf(stderr, "CRC failure at line %d: got 0x%X, expected 0x%X\n",
  181 + line, crcbyte, (unsigned char)(crcbyte-crc));
  182 + return -EINVAL;
  183 + }
  184 +
  185 + /* Done reading the record */
  186 + switch (type) {
  187 + case 0:
  188 + /* old style EOF record? */
  189 + if (!record->len)
  190 + break;
  191 +
  192 + record->addr += offset;
  193 + file_record(record);
  194 + goto next_record;
  195 +
  196 + case 1: /* End-Of-File Record */
  197 + if (record->addr || record->len) {
  198 + fprintf(stderr, "Bad EOF record (type 01) format at line %d",
  199 + line);
  200 + return -EINVAL;
  201 + }
  202 + break;
  203 +
  204 + case 2: /* Extended Segment Address Record (HEX86) */
  205 + case 4: /* Extended Linear Address Record (HEX386) */
  206 + if (record->addr || record->len != 2) {
  207 + fprintf(stderr, "Bad HEX86/HEX386 record (type %02X) at line %d\n",
  208 + type, line);
  209 + return -EINVAL;
  210 + }
  211 +
  212 + /* We shouldn't really be using the offset for HEX86 because
  213 + * the wraparound case is specified quite differently. */
  214 + offset = record->data[0] << 8 | record->data[1];
  215 + offset <<= (type == 2 ? 4 : 16);
  216 + goto next_record;
  217 +
  218 + case 3: /* Start Segment Address Record */
  219 + case 5: /* Start Linear Address Record */
  220 + if (record->addr || record->len != 4) {
  221 + fprintf(stderr, "Bad Start Address record (type %02X) at line %d\n",
  222 + type, line);
  223 + return -EINVAL;
  224 + }
  225 +
  226 + /* These records contain the CS/IP or EIP where execution
  227 + * starts. Don't really know what to do with them. */
  228 + goto next_record;
  229 +
  230 + default:
  231 + fprintf(stderr, "Unknown record (type %02X)\n", type);
  232 + return -EINVAL;
  233 + }
  234 +
  235 + return 0;
  236 +}
  237 +
  238 +static struct ihex_binrec *records;
  239 +
  240 +static void file_record(struct ihex_binrec *record)
  241 +{
  242 + struct ihex_binrec **p = &records;
  243 +
  244 + while ((*p) && (!sort_records || (*p)->addr < record->addr))
  245 + p = &((*p)->next);
  246 +
  247 + record->next = *p;
  248 + *p = record;
  249 +}
  250 +
  251 +static int output_records(int outfd)
  252 +{
  253 + unsigned char zeroes[6] = {0, 0, 0, 0, 0, 0};
  254 + struct ihex_binrec *p = records;
  255 +
  256 + while (p) {
  257 + uint16_t writelen = (p->len + 9) & ~3;
  258 +
  259 + p->addr = htonl(p->addr);
  260 + p->len = htons(p->len);
  261 + write(outfd, &p->addr, writelen);
  262 + p = p->next;
  263 + }
  264 + /* EOF record is zero length, since we don't bother to represent
  265 + the type field in the binary version */
  266 + write(outfd, zeroes, 6);
  267 + return 0;
  268 +}