aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot/devtree.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/boot/devtree.c')
-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 ||