diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2005-04-03 17:38:58 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-03 17:38:58 -0700 |
commit | d0091e60a7e122b3e70658bf6e1148a389f71e90 (patch) | |
tree | 6df9b46c9522c24d3b8baa53aff4d069126696d8 | |
parent | 196384b529f1018693f0242d9d25c517e816fdb6 (diff) | |
download | history-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.c | 13 |
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); |