aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2007-04-26 13:08:13 -0400
committerPaul Mackerras <paulus@samba.org>2007-04-27 07:13:56 -0400
commite4bb688d9f11d7fee927312cc97d443472c7c212 (patch)
treefcaa10701b293cfa1dcb7c3dca3e4b4435a81a80 /arch/powerpc/boot
parent3c5f6162549b9045a2925dff64c140c7f49ea344 (diff)
[POWERPC] bootwrapper: Fix array handling in dt_xlate_reg().
This fixes a few bugs in how dt_xlate_reg() handles address arrays: 1. copy_val() was copying into the wrong end of the array, resulting in random stack garbage at the other end. 2. dt_xlate_reg() was getting the result from the wrong end of the array. 3. add_reg() and sub_reg() were treating the arrays as little-endian rather than big-endian. 4. add_reg() only returned an error on a carry out of the entire array, rather than out of the naddr portion. 5. The requested reg resource was checked to see if it exceeded the size of the reg property, but not to see if it exceeded the size of the buffer. Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/boot')
-rw-r--r--arch/powerpc/boot/devtree.c23
1 files changed, 11 insertions, 12 deletions
diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c
index 23492d7fb556..ac4b5ee92d58 100644
--- a/arch/powerpc/boot/devtree.c
+++ b/arch/powerpc/boot/devtree.c
@@ -123,15 +123,17 @@ static void get_reg_format(void *node, u32 *naddr, u32 *nsize)
123 123
124static void copy_val(u32 *dest, u32 *src, int naddr) 124static void copy_val(u32 *dest, u32 *src, int naddr)
125{ 125{
126 memset(dest, 0, (MAX_ADDR_CELLS - naddr) * 4); 126 int pad = MAX_ADDR_CELLS - naddr;
127 memcpy(dest, src, naddr * 4); 127
128 memset(dest, 0, pad * 4);
129 memcpy(dest + pad, src, naddr * 4);
128} 130}
129 131
130static int sub_reg(u32 *reg, u32 *sub) 132static int sub_reg(u32 *reg, u32 *sub)
131{ 133{
132 int i, borrow = 0; 134 int i, borrow = 0;
133 135
134 for (i = 0; i < MAX_ADDR_CELLS; i++) { 136 for (i = MAX_ADDR_CELLS - 1; i >= 0; i--) {
135 int prev_borrow = borrow; 137 int prev_borrow = borrow;
136 borrow = reg[i] < sub[i] + prev_borrow; 138 borrow = reg[i] < sub[i] + prev_borrow;
137 reg[i] -= sub[i] + prev_borrow; 139 reg[i] -= sub[i] + prev_borrow;
@@ -140,11 +142,11 @@ static int sub_reg(u32 *reg, u32 *sub)
140 return !borrow; 142 return !borrow;
141} 143}
142 144
143static int add_reg(u32 *reg, u32 *add) 145static int add_reg(u32 *reg, u32 *add, int naddr)
144{ 146{
145 int i, carry = 0; 147 int i, carry = 0;
146 148
147 for (i = 0; i < MAX_ADDR_CELLS; i++) { 149 for (i = MAX_ADDR_CELLS - 1; i >= MAX_ADDR_CELLS - naddr; i--) {
148 u64 tmp = (u64)reg[i] + add[i] + carry; 150 u64 tmp = (u64)reg[i] + add[i] + carry;
149 carry = tmp >> 32; 151 carry = tmp >> 32;
150 reg[i] = (u32)tmp; 152 reg[i] = (u32)tmp;
@@ -228,7 +230,8 @@ int dt_xlate_reg(void *node, int res, unsigned long *addr,
228 buflen = getprop(node, "reg", buf, sizeof(buf)) / 4; 230 buflen = getprop(node, "reg", buf, sizeof(buf)) / 4;
229 offset = (naddr + nsize) * res; 231 offset = (naddr + nsize) * res;
230 232
231 if (buflen < offset + naddr + nsize) 233 if (buflen < offset + naddr + nsize ||
234 sizeof(buf) < offset + naddr + nsize)
232 return 0; 235 return 0;
233 236
234 copy_val(last_addr, buf + offset, naddr); 237 copy_val(last_addr, buf + offset, naddr);
@@ -263,18 +266,14 @@ int dt_xlate_reg(void *node, int res, unsigned long *addr,
263 266
264 copy_val(this_addr, buf + offset + prev_naddr, naddr); 267 copy_val(this_addr, buf + offset + prev_naddr, naddr);
265 268
266 if (!add_reg(last_addr, this_addr)) 269 if (!add_reg(last_addr, this_addr, naddr))
267 return 0; 270 return 0;
268 } 271 }
269 272
270 if (naddr > 2) 273 if (naddr > 2)
271 return 0; 274 return 0;
272 275
273 ret_addr = last_addr[0]; 276 ret_addr = ((u64)last_addr[2] << 32) | last_addr[3];
274 if (naddr == 2) {
275 ret_addr <<= 32;
276 ret_addr |= last_addr[1];
277 }
278 277
279 if (sizeof(void *) == 4 && 278 if (sizeof(void *) == 4 &&
280 (ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL || 279 (ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL ||