aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-04-03 17:38:58 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-03 17:38:58 -0700
commitd0091e60a7e122b3e70658bf6e1148a389f71e90 (patch)
tree6df9b46c9522c24d3b8baa53aff4d069126696d8
parent196384b529f1018693f0242d9d25c517e816fdb6 (diff)
downloadhistory-d0091e60a7e122b3e70658bf6e1148a389f71e90.tar.gz
[PATCH] ppc64: Fix boot memory corruption
Nathan's patch "make OF node fixup code usable at runtim" is introducing a snaky bug. We do 2 passes over this code, one to measure how much memory will be needed so we can allocate a single block, and one to do the actual fixup. However, the new code does some result-checking of prom_alloc() which breaks this mecanism, as the first pass always starts at "0", thus we fail to measure the additional size properly and allocate a block smaller than what we'll actually use for the fixup. This cause us to override whatever sits there, with variable results depending on the memory layout of the machine (but typically crashes). This patch fixes it by starting the "measure" pass with an initial size set to 16 and not 0. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/ppc64/kernel/prom.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index 1a5f59b769b915..01739d5c47c7c0 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -601,8 +601,19 @@ void __init finish_device_tree(void)
/* Initialize virtual IRQ map */
virt_irq_init();
- /* Finish device-tree (pre-parsing some properties etc...) */
+ /*
+ * Finish device-tree (pre-parsing some properties etc...)
+ * We do this in 2 passes. One with "measure_only" set, which
+ * will only measure the amount of memory needed, then we can
+ * allocate that memory, and call finish_node again. However,
+ * we must be careful as most routines will fail nowadays when
+ * prom_alloc() returns 0, so we must make sure our first pass
+ * doesn't start at 0. We pre-initialize size to 16 for that
+ * reason and then remove those additional 16 bytes
+ */
+ size = 16;
finish_node(allnodes, &size, NULL, 0, 0, 1);
+ size -= 16;
end = start = (unsigned long)abs_to_virt(lmb_alloc(size, 128));
finish_node(allnodes, &end, NULL, 0, 0, 0);
BUG_ON(end != start + size);