aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2007-08-20 13:39:46 -0400
committerPaul Mackerras <paulus@samba.org>2007-08-22 01:21:48 -0400
commit0602801c22ea1767cd0298b11da140bd5cb764d2 (patch)
tree323d76381d007b23b2b60d9865a15193e83c2d7b /arch/powerpc
parent643d3c139b0a5289d7f0ba19fdcb24be6d7e768f (diff)
[POWERPC] bootwrapper: dt_xlate_range() bugfixes
1. The check whether ranges fits in the buffer was using elements rather than bytes. 2. Empty ranges were not properly treated as transparent, and missing ranges were treated as transparent. 3. The loop terminated when translating from the root rather than to. Once bug #2 was fixed, it failed due to a missing ranges in the root node. 4. In decoding the ranges property, the #size-cells used was that of the parent, not the child. Signed-off-by: Scott Wood <scottwood@freescale.com> Acked-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/boot/devtree.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c
index ae8b886f5a1..129e6d9b8d4 100644
--- a/arch/powerpc/boot/devtree.c
+++ b/arch/powerpc/boot/devtree.c
@@ -218,7 +218,7 @@ static int dt_xlate(void *node, int res, int reglen, unsigned long *addr,
218 u32 this_addr[MAX_ADDR_CELLS]; 218 u32 this_addr[MAX_ADDR_CELLS];
219 void *parent; 219 void *parent;
220 u64 ret_addr, ret_size; 220 u64 ret_addr, ret_size;
221 u32 naddr, nsize, prev_naddr; 221 u32 naddr, nsize, prev_naddr, prev_nsize;
222 int buflen, offset; 222 int buflen, offset;
223 223
224 parent = get_parent(node); 224 parent = get_parent(node);
@@ -233,7 +233,7 @@ static int dt_xlate(void *node, int res, int reglen, unsigned long *addr,
233 offset = (naddr + nsize) * res; 233 offset = (naddr + nsize) * res;
234 234
235 if (reglen < offset + naddr + nsize || 235 if (reglen < offset + naddr + nsize ||
236 sizeof(dt_xlate_buf) < offset + naddr + nsize) 236 sizeof(dt_xlate_buf) < (offset + naddr + nsize) * 4)
237 return 0; 237 return 0;
238 238
239 copy_val(last_addr, dt_xlate_buf + offset, naddr); 239 copy_val(last_addr, dt_xlate_buf + offset, naddr);
@@ -244,20 +244,26 @@ static int dt_xlate(void *node, int res, int reglen, unsigned long *addr,
244 ret_size |= dt_xlate_buf[offset + naddr + 1]; 244 ret_size |= dt_xlate_buf[offset + naddr + 1];
245 } 245 }
246 246
247 while ((node = get_parent(node))) { 247 for (;;) {
248 prev_naddr = naddr; 248 prev_naddr = naddr;
249 prev_nsize = nsize;
250 node = parent;
249 251
250 get_reg_format(node, &naddr, &nsize); 252 parent = get_parent(node);
253 if (!parent)
254 break;
255
256 get_reg_format(parent, &naddr, &nsize);
251 257
252 buflen = getprop(node, "ranges", dt_xlate_buf, 258 buflen = getprop(node, "ranges", dt_xlate_buf,
253 sizeof(dt_xlate_buf)); 259 sizeof(dt_xlate_buf));
254 if (buflen < 0) 260 if (buflen == 0)
255 continue; 261 continue;
256 if (buflen > sizeof(dt_xlate_buf)) 262 if (buflen < 0 || buflen > sizeof(dt_xlate_buf))
257 return 0; 263 return 0;
258 264
259 offset = find_range(last_addr, dt_xlate_buf, prev_naddr, 265 offset = find_range(last_addr, dt_xlate_buf, prev_naddr,
260 naddr, nsize, buflen / 4); 266 naddr, prev_nsize, buflen / 4);
261 267
262 if (offset < 0) 268 if (offset < 0)
263 return 0; 269 return 0;