swapper_pg_dir:
        .space  4096
 
-#ifdef CONFIG_SMP
-/* 1 page segment table per cpu (max 48, cpu0 allocated at STAB0_PHYS_ADDR) */
-       .globl  stab_array
-stab_array:
-       .space  4096 * 48
-#endif
-       
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
  * Used to pass parameters into the kernel like root=/dev/sda1, etc.
 
 
 static volatile unsigned int cpu_callin_map[NR_CPUS];
 
-extern unsigned char stab_array[];
-
 void smp_call_function_interrupt(void);
 
 int smt_enabled_at_boot = 1;
 
        paca[cpu].default_decr = tb_ticks_per_jiffy;
 
-       if (!cpu_has_feature(CPU_FTR_SLB)) {
-               void *tmp;
-
-               /* maximum of 48 CPUs on machines with a segment table */
-               if (cpu >= 48)
-                       BUG();
-
-               tmp = &stab_array[PAGE_SIZE * cpu];
-               memset(tmp, 0, PAGE_SIZE); 
-               paca[cpu].stab_addr = (unsigned long)tmp;
-               paca[cpu].stab_real = virt_to_abs(tmp);
-       }
-
        /* Make sure callin-map entry is 0 (can be leftover a CPU
         * hotplug
         */
 
 #include <asm/mmu_context.h>
 #include <asm/paca.h>
 #include <asm/cputable.h>
+#include <asm/lmb.h>
+#include <asm/abs_addr.h>
 
 struct stab_entry {
        unsigned long esid_data;
 
 extern void slb_initialize(void);
 
+/*
+ * Allocate segment tables for secondary CPUs.  These must all go in
+ * the first (bolted) segment, so that do_stab_bolted won't get a
+ * recursive segment miss on the segment table itself.
+ */
+void stabs_alloc(void)
+{
+       int cpu;
+
+       if (cpu_has_feature(CPU_FTR_SLB))
+               return;
+
+       for_each_cpu(cpu) {
+               unsigned long newstab;
+
+               if (cpu == 0)
+                       continue; /* stab for CPU 0 is statically allocated */
+
+               newstab = lmb_alloc_base(PAGE_SIZE, PAGE_SIZE, 1<<SID_SHIFT);
+               if (! newstab)
+                       panic("Unable to allocate segment table for CPU %d.\n",
+                             cpu);
+
+               newstab += KERNELBASE;
+
+               memset((void *)newstab, 0, PAGE_SIZE);
+
+               paca[cpu].stab_addr = newstab;
+               paca[cpu].stab_real = virt_to_abs(newstab);
+               printk(KERN_DEBUG "Segment table for CPU %d at 0x%lx virtual, 0x%lx absolute\n", cpu, paca[cpu].stab_addr, paca[cpu].stab_real);
+       }
+}
+
 /*
  * Build an entry for the base kernel segment and put it into
  * the segment table or SLB.  All other segment table or SLB