summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/linuxboot.c60
1 files changed, 41 insertions, 19 deletions
diff --git a/firmware/linuxboot.c b/firmware/linuxboot.c
index aa907ac7bb..f9732f6ace 100644
--- a/firmware/linuxboot.c
+++ b/firmware/linuxboot.c
@@ -32,9 +32,20 @@
32#define HAVE_UIMAGE_COMP_NONE 32#define HAVE_UIMAGE_COMP_NONE
33#define HAVE_UIMAGE_COMP_GZIP 33#define HAVE_UIMAGE_COMP_GZIP
34 34
35enum {
36 E_OUT_OF_MEMORY = -1,
37 E_BUFFER_OVERFLOW = -2,
38 E_MAGIC_MISMATCH = -3,
39 E_HCRC_MISMATCH = -4,
40 E_DCRC_MISMATCH = -5,
41 E_UNSUPPORTED_COMPRESSION = -6,
42 E_READ = -7,
43 E_INFLATE = -8,
44 E_INFLATE_UNCONSUMED = -9,
45};
46
35uint32_t uimage_crc(uint32_t crc, const void* data, size_t size) 47uint32_t uimage_crc(uint32_t crc, const void* data, size_t size)
36{ 48{
37 /* is this endian swapping required...? */
38 return letoh32(crc_32r(data, size, htole32(crc ^ 0xffffffff))) ^ 0xffffffff; 49 return letoh32(crc_32r(data, size, htole32(crc ^ 0xffffffff))) ^ 0xffffffff;
39} 50}
40 51
@@ -48,10 +59,10 @@ uint32_t uimage_calc_hcrc(const struct uimage_header* uh)
48static int uimage_check_header(const struct uimage_header* uh) 59static int uimage_check_header(const struct uimage_header* uh)
49{ 60{
50 if(uimage_get_magic(uh) != IH_MAGIC) 61 if(uimage_get_magic(uh) != IH_MAGIC)
51 return -1; 62 return E_MAGIC_MISMATCH;
52 63
53 if(uimage_get_hcrc(uh) != uimage_calc_hcrc(uh)) 64 if(uimage_get_hcrc(uh) != uimage_calc_hcrc(uh))
54 return -2; 65 return E_HCRC_MISMATCH;
55 66
56 return 0; 67 return 0;
57} 68}
@@ -73,7 +84,7 @@ static int uimage_alloc_state(const struct uimage_header* uh)
73#endif 84#endif
74 85
75 default: 86 default:
76 return -1; 87 return E_UNSUPPORTED_COMPRESSION;
77 } 88 }
78} 89}
79 90
@@ -84,18 +95,21 @@ struct uimage_inflatectx
84 void* rctx; 95 void* rctx;
85 uint32_t dcrc; 96 uint32_t dcrc;
86 size_t remain; 97 size_t remain;
98 int err;
87}; 99};
88 100
89static uint32_t uimage_inflate_reader(void* block, uint32_t block_size, void* ctx) 101static uint32_t uimage_inflate_reader(void* block, uint32_t block_size, void* ctx)
90{ 102{
91 struct uimage_inflatectx* c = ctx; 103 struct uimage_inflatectx* c = ctx;
92 ssize_t len = c->reader(block, block_size, c->rctx); 104 ssize_t len = c->reader(block, block_size, c->rctx);
93 if(len > 0) { 105 if(len < 0) {
94 len = MIN(c->remain, (size_t)len); 106 c->err = E_READ;
95 c->remain -= len; 107 return 0;
96 c->dcrc = uimage_crc(c->dcrc, block, len);
97 } 108 }
98 109
110 len = MIN(c->remain, (size_t)len);
111 c->remain -= len;
112 c->dcrc = uimage_crc(c->dcrc, block, len);
99 return len; 113 return len;
100} 114}
101 115
@@ -112,6 +126,7 @@ static int uimage_decompress_gzip(const struct uimage_header* uh, int state_h,
112 r_ctx.rctx = rctx; 126 r_ctx.rctx = rctx;
113 r_ctx.dcrc = 0; 127 r_ctx.dcrc = 0;
114 r_ctx.remain = uimage_get_size(uh); 128 r_ctx.remain = uimage_get_size(uh);
129 r_ctx.err = 0;
115 130
116 struct inflate_bufferctx w_ctx; 131 struct inflate_bufferctx w_ctx;
117 w_ctx.buf = out; 132 w_ctx.buf = out;
@@ -120,13 +135,20 @@ static int uimage_decompress_gzip(const struct uimage_header* uh, int state_h,
120 int ret = inflate(hbuf, INFLATE_GZIP, 135 int ret = inflate(hbuf, INFLATE_GZIP,
121 uimage_inflate_reader, &r_ctx, 136 uimage_inflate_reader, &r_ctx,
122 inflate_buffer_writer, &w_ctx); 137 inflate_buffer_writer, &w_ctx);
123 if(ret) 138 if(ret) {
124 return ret; 139 if(r_ctx.err)
140 return r_ctx.err;
141 else if(w_ctx.end == w_ctx.buf)
142 return E_BUFFER_OVERFLOW;
143 else
144 /* note: this will likely mask DCRC_MISMATCH errors */
145 return E_INFLATE;
146 }
125 147
126 if(r_ctx.remain > 0) 148 if(r_ctx.remain > 0)
127 return -1; 149 return E_INFLATE_UNCONSUMED;
128 if(r_ctx.dcrc != uimage_get_dcrc(uh)) 150 if(r_ctx.dcrc != uimage_get_dcrc(uh))
129 return -2; 151 return E_DCRC_MISMATCH;
130 152
131 *out_size = w_ctx.end - w_ctx.buf; 153 *out_size = w_ctx.end - w_ctx.buf;
132 return 0; 154 return 0;
@@ -144,14 +166,14 @@ static int uimage_decompress(const struct uimage_header* uh, int state_h,
144#ifdef HAVE_UIMAGE_COMP_NONE 166#ifdef HAVE_UIMAGE_COMP_NONE
145 case IH_COMP_NONE: 167 case IH_COMP_NONE:
146 if(*out_size < in_size) 168 if(*out_size < in_size)
147 return -2; 169 return E_BUFFER_OVERFLOW;
148 170
149 len = reader(out, in_size, rctx); 171 len = reader(out, in_size, rctx);
150 if(len < 0 || (size_t)len != in_size) 172 if(len < 0 || (size_t)len != in_size)
151 return -3; 173 return E_READ;
152 174
153 if(uimage_crc(0, out, in_size) != uimage_get_dcrc(uh)) 175 if(uimage_crc(0, out, in_size) != uimage_get_dcrc(uh))
154 return -4; 176 return E_DCRC_MISMATCH;
155 177
156 *out_size = in_size; 178 *out_size = in_size;
157 break; 179 break;
@@ -163,7 +185,7 @@ static int uimage_decompress(const struct uimage_header* uh, int state_h,
163#endif 185#endif
164 186
165 default: 187 default:
166 return -1; 188 return E_UNSUPPORTED_COMPRESSION;
167 } 189 }
168 190
169 return 0; 191 return 0;
@@ -173,7 +195,7 @@ int uimage_load(struct uimage_header* uh, size_t* out_size,
173 uimage_reader reader, void* rctx) 195 uimage_reader reader, void* rctx)
174{ 196{
175 if(reader(uh, sizeof(*uh), rctx) != (ssize_t)sizeof(*uh)) 197 if(reader(uh, sizeof(*uh), rctx) != (ssize_t)sizeof(*uh))
176 return -1; /* read error */ 198 return E_READ;
177 199
178 int ret = uimage_check_header(uh); 200 int ret = uimage_check_header(uh);
179 if(ret) 201 if(ret)
@@ -181,12 +203,12 @@ int uimage_load(struct uimage_header* uh, size_t* out_size,
181 203
182 int state_h = uimage_alloc_state(uh); 204 int state_h = uimage_alloc_state(uh);
183 if(state_h < 0) 205 if(state_h < 0)
184 return state_h; 206 return E_OUT_OF_MEMORY;
185 207
186 *out_size = 0; 208 *out_size = 0;
187 int out_h = core_alloc_maximum("uimage", out_size, &buflib_ops_locked); 209 int out_h = core_alloc_maximum("uimage", out_size, &buflib_ops_locked);
188 if(out_h <= 0) { 210 if(out_h <= 0) {
189 ret = -1; 211 ret = E_OUT_OF_MEMORY;
190 goto err; 212 goto err;
191 } 213 }
192 214