Merge branch 'merge'
authorPaul Mackerras <paulus@samba.org>
Mon, 12 Jun 2006 07:53:34 +0000 (17:53 +1000)
committerPaul Mackerras <paulus@samba.org>
Mon, 12 Jun 2006 07:53:34 +0000 (17:53 +1000)
1  2 
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/platforms/pseries/setup.c

@@@ -194,12 -194,19 +194,12 @@@ static int __initdata of_platform
  
  static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
  
 -static unsigned long __initdata prom_memory_limit;
 -
  static unsigned long __initdata alloc_top;
  static unsigned long __initdata alloc_top_high;
  static unsigned long __initdata alloc_bottom;
  static unsigned long __initdata rmo_top;
  static unsigned long __initdata ram_top;
  
 -#ifdef CONFIG_KEXEC
 -static unsigned long __initdata prom_crashk_base;
 -static unsigned long __initdata prom_crashk_size;
 -#endif
 -
  static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];
  static int __initdata mem_reserve_cnt;
  
@@@ -586,6 -593,45 +586,6 @@@ static void __init early_cmdline_parse(
                        RELOC(iommu_force_on) = 1;
        }
  #endif
 -
 -      opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
 -      if (opt) {
 -              opt += 4;
 -              RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt);
 -#ifdef CONFIG_PPC64
 -              /* Align to 16 MB == size of ppc64 large page */
 -              RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
 -#endif
 -      }
 -
 -#ifdef CONFIG_KEXEC
 -      /*
 -       * crashkernel=size@addr specifies the location to reserve for
 -       * crash kernel.
 -       */
 -      opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel="));
 -      if (opt) {
 -              opt += 12;
 -              RELOC(prom_crashk_size) = 
 -                      prom_memparse(opt, (const char **)&opt);
 -
 -              if (ALIGN(RELOC(prom_crashk_size), 0x1000000) !=
 -                      RELOC(prom_crashk_size)) {
 -                      prom_printf("Warning: crashkernel size is not "
 -                                      "aligned to 16MB\n");
 -              }
 -
 -              /*
 -               * At present, the crash kernel always run at 32MB.
 -               * Just ignore whatever user passed.
 -               */
 -              RELOC(prom_crashk_base) = 0x2000000;
 -              if (*opt == '@') {
 -                      prom_printf("Warning: PPC64 kdump kernel always runs "
 -                                      "at 32 MB\n");
 -              }
 -      }
 -#endif
  }
  
  #ifdef CONFIG_PPC_PSERIES
@@@ -776,6 -822,7 +776,7 @@@ static void __init prom_send_capabiliti
                /* try calling the ibm,client-architecture-support method */
                if (call_prom_ret("call-method", 3, 2, &ret,
                                  ADDR("ibm,client-architecture-support"),
+                                 root,
                                  ADDR(ibm_architecture_vec)) == 0) {
                        /* the call exists... */
                        if (ret)
@@@ -1068,6 -1115,29 +1069,6 @@@ static void __init prom_init_mem(void
                        RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end));
        }
  
 -      /*
 -       * If prom_memory_limit is set we reduce the upper limits *except* for
 -       * alloc_top_high. This must be the real top of RAM so we can put
 -       * TCE's up there.
 -       */
 -
 -      RELOC(alloc_top_high) = RELOC(ram_top);
 -
 -      if (RELOC(prom_memory_limit)) {
 -              if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) {
 -                      prom_printf("Ignoring mem=%x <= alloc_bottom.\n",
 -                              RELOC(prom_memory_limit));
 -                      RELOC(prom_memory_limit) = 0;
 -              } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) {
 -                      prom_printf("Ignoring mem=%x >= ram_top.\n",
 -                              RELOC(prom_memory_limit));
 -                      RELOC(prom_memory_limit) = 0;
 -              } else {
 -                      RELOC(ram_top) = RELOC(prom_memory_limit);
 -                      RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit));
 -              }
 -      }
 -
        /*
         * Setup our top alloc point, that is top of RMO or top of
         * segment 0 when running non-LPAR.
                RELOC(rmo_top) = RELOC(ram_top);
        RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top));
        RELOC(alloc_top) = RELOC(rmo_top);
 +      RELOC(alloc_top_high) = RELOC(ram_top);
  
        prom_printf("memory layout at init:\n");
 -      prom_printf("  memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
        prom_printf("  alloc_bottom : %x\n", RELOC(alloc_bottom));
        prom_printf("  alloc_top    : %x\n", RELOC(alloc_top));
        prom_printf("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
        prom_printf("  rmo_top      : %x\n", RELOC(rmo_top));
        prom_printf("  ram_top      : %x\n", RELOC(ram_top));
 -#ifdef CONFIG_KEXEC
 -      if (RELOC(prom_crashk_base)) {
 -              prom_printf("  crashk_base  : %x\n",  RELOC(prom_crashk_base));
 -              prom_printf("  crashk_size  : %x\n", RELOC(prom_crashk_size));
 -      }
 -#endif
  }
  
  
@@@ -1273,10 -1349,16 +1274,10 @@@ static void __init prom_initialize_tce_
  
        reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom);
  
 -      if (RELOC(prom_memory_limit)) {
 -              /*
 -               * We align the start to a 16MB boundary so we can map
 -               * the TCE area using large pages if possible.
 -               * The end should be the top of RAM so no need to align it.
 -               */
 -              RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom,
 -                                                        0x1000000);
 -              RELOC(prom_tce_alloc_end) = local_alloc_top;
 -      }
 +      /* These are only really needed if there is a memory limit in
 +       * effect, but we don't know so export them always. */
 +      RELOC(prom_tce_alloc_start) = local_alloc_bottom;
 +      RELOC(prom_tce_alloc_end) = local_alloc_top;
  
        /* Flag the first invalid entry */
        prom_debug("ending prom_initialize_tce_table\n");
@@@ -1541,6 -1623,15 +1542,15 @@@ static int __init prom_find_machine_typ
                        if (strstr(p, RELOC("Power Macintosh")) ||
                            strstr(p, RELOC("MacRISC")))
                                return PLATFORM_POWERMAC;
+ #ifdef CONFIG_PPC64
+                       /* We must make sure we don't detect the IBM Cell
+                        * blades as pSeries due to some firmware issues,
+                        * so we do it here.
+                        */
+                       if (strstr(p, RELOC("IBM,CBEA")) ||
+                           strstr(p, RELOC("IBM,CPBW-1.0")))
+                               return PLATFORM_GENERIC;
+ #endif /* CONFIG_PPC64 */
                        i += sl + 1;
                }
        }
@@@ -1950,7 -2041,11 +1960,7 @@@ static void __init flatten_device_tree(
        /* Version 16 is not backward compatible */
        hdr->last_comp_version = 0x10;
  
 -      /* Reserve the whole thing and copy the reserve map in, we
 -       * also bump mem_reserve_cnt to cause further reservations to
 -       * fail since it's too late.
 -       */
 -      reserve_mem(RELOC(dt_header_start), hdr->totalsize);
 +      /* Copy the reserve map in */
        memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map));
  
  #ifdef DEBUG_PROM
                                    RELOC(mem_reserve_map)[i].size);
        }
  #endif
 +      /* Bump mem_reserve_cnt to cause further reservations to fail
 +       * since it's too late.
 +       */
        RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE;
  
        prom_printf("Device tree strings 0x%x -> 0x%x\n",
@@@ -2188,6 -2280,10 +2198,6 @@@ unsigned long __init prom_init(unsigne
         */
        prom_init_mem();
  
 -#ifdef CONFIG_KEXEC
 -      if (RELOC(prom_crashk_base))
 -              reserve_mem(RELOC(prom_crashk_base), RELOC(prom_crashk_size));
 -#endif
        /*
         * Determine which cpu is actually running right _now_
         */
        /*
         * Fill in some infos for use by the kernel later on
         */
 -      if (RELOC(prom_memory_limit))
 -              prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit",
 -                           &RELOC(prom_memory_limit),
 -                           sizeof(prom_memory_limit));
  #ifdef CONFIG_PPC64
        if (RELOC(ppc64_iommu_off))
                prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
        }
  #endif
  
 -#ifdef CONFIG_KEXEC
 -      if (RELOC(prom_crashk_base)) {
 -              prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-base",
 -                      PTRRELOC(&prom_crashk_base),
 -                      sizeof(RELOC(prom_crashk_base)));
 -              prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-size",
 -                      PTRRELOC(&prom_crashk_size),
 -                      sizeof(RELOC(prom_crashk_size)));
 -      }
 -#endif
        /*
         * Fixup any known bugs in the device-tree
         */
@@@ -419,7 -419,9 +419,7 @@@ static long restore_user_regs(struct pt
  {
        long err;
        unsigned int save_r2 = 0;
 -#if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE)
        unsigned long msr;
 -#endif
  
        /*
         * restore general registers but not including MSR or SOFTE. Also
        if (!sig)
                save_r2 = (unsigned int)regs->gpr[2];
        err = restore_general_regs(regs, sr);
 +      err |= __get_user(msr, &sr->mc_gregs[PT_MSR]);
        if (!sig)
                regs->gpr[2] = (unsigned long) save_r2;
        if (err)
                return 1;
  
 +      /* if doing signal return, restore the previous little-endian mode */
 +      if (sig)
 +              regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
 +
        /*
         * Do this before updating the thread state in
         * current->thread.fpr/vr/evr.  That way, if we get preempted
        /* force the process to reload the altivec registers from
           current->thread when it next does altivec instructions */
        regs->msr &= ~MSR_VEC;
 -      if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_VEC) != 0) {
 +      if (msr & MSR_VEC) {
                /* restore altivec registers from the stack */
                if (__copy_from_user(current->thread.vr, &sr->mc_vregs,
                                     sizeof(sr->mc_vregs)))
        /* force the process to reload the spe registers from
           current->thread when it next does spe instructions */
        regs->msr &= ~MSR_SPE;
 -      if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_SPE) != 0) {
 +      if (msr & MSR_SPE) {
                /* restore spe registers from the stack */
                if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
                                     ELF_NEVRREG * sizeof(u32)))
@@@ -760,10 -757,10 +760,10 @@@ static int handle_rt_signal(unsigned lo
  
        /* Save user registers on the stack */
        frame = &rt_sf->uc.uc_mcontext;
 -      if (vdso32_rt_sigtramp && current->thread.vdso_base) {
 +      if (vdso32_rt_sigtramp && current->mm->context.vdso_base) {
                if (save_user_regs(regs, frame, 0))
                        goto badframe;
 -              regs->link = current->thread.vdso_base + vdso32_rt_sigtramp;
 +              regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp;
        } else {
                if (save_user_regs(regs, frame, __NR_rt_sigreturn))
                        goto badframe;
        regs->gpr[5] = (unsigned long) &rt_sf->uc;
        regs->gpr[6] = (unsigned long) rt_sf;
        regs->nip = (unsigned long) ka->sa.sa_handler;
 +      /* enter the signal handler in big-endian mode */
 +      regs->msr &= ~MSR_LE;
        regs->trap = 0;
        return 1;
  
@@@ -808,10 -803,13 +808,13 @@@ static int do_setcontext(struct ucontex
                if (__get_user(cmcp, &ucp->uc_regs))
                        return -EFAULT;
                mcp = (struct mcontext __user *)(u64)cmcp;
+               /* no need to check access_ok(mcp), since mcp < 4GB */
        }
  #else
        if (__get_user(mcp, &ucp->uc_regs))
                return -EFAULT;
+       if (!access_ok(VERIFY_READ, mcp, sizeof(*mcp)))
+               return -EFAULT;
  #endif
        restore_sigmask(&set);
        if (restore_user_regs(regs, mcp, sig))
@@@ -913,13 -911,14 +916,14 @@@ int sys_debug_setcontext(struct ucontex
  {
        struct sig_dbg_op op;
        int i;
+       unsigned char tmp;
        unsigned long new_msr = regs->msr;
  #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
        unsigned long new_dbcr0 = current->thread.dbcr0;
  #endif
  
        for (i=0; i<ndbg; i++) {
-               if (__copy_from_user(&op, dbg, sizeof(op)))
+               if (copy_from_user(&op, dbg + i, sizeof(op)))
                        return -EFAULT;
                switch (op.dbg_type) {
                case SIG_DBG_SINGLE_STEPPING:
        current->thread.dbcr0 = new_dbcr0;
  #endif
  
+       if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx))
+           || __get_user(tmp, (u8 __user *) ctx)
+           || __get_user(tmp, (u8 __user *) (ctx + 1) - 1))
+               return -EFAULT;
        /*
         * If we get a fault copying the context into the kernel's
         * image of the user's registers, we can't just return -EFAULT
@@@ -1034,10 -1038,10 +1043,10 @@@ static int handle_signal(unsigned long 
            || __put_user(sig, &sc->signal))
                goto badframe;
  
 -      if (vdso32_sigtramp && current->thread.vdso_base) {
 +      if (vdso32_sigtramp && current->mm->context.vdso_base) {
                if (save_user_regs(regs, &frame->mctx, 0))
                        goto badframe;
 -              regs->link = current->thread.vdso_base + vdso32_sigtramp;
 +              regs->link = current->mm->context.vdso_base + vdso32_sigtramp;
        } else {
                if (save_user_regs(regs, &frame->mctx, __NR_sigreturn))
                        goto badframe;
        regs->gpr[3] = sig;
        regs->gpr[4] = (unsigned long) sc;
        regs->nip = (unsigned long) ka->sa.sa_handler;
 +      /* enter the signal handler in big-endian mode */
 +      regs->msr &= ~MSR_LE;
        regs->trap = 0;
  
        return 1;
@@@ -141,7 -141,9 +141,7 @@@ static long restore_sigcontext(struct p
        unsigned long err = 0;
        unsigned long save_r13 = 0;
        elf_greg_t *gregs = (elf_greg_t *)regs;
 -#ifdef CONFIG_ALTIVEC
        unsigned long msr;
 -#endif
        int i;
  
        /* If this is not a signal return, we preserve the TLS in r13 */
        err |= __copy_from_user(regs, &sc->gp_regs,
                                PT_MSR*sizeof(unsigned long));
  
 -      /* skip MSR and SOFTE */
 +      /* get MSR separately, transfer the LE bit if doing signal return */
 +      err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
 +      if (sig)
 +              regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
 +
 +      /* skip SOFTE */
        for (i = PT_MSR+1; i <= PT_RESULT; i++) {
                if (i == PT_SOFTE)
                        continue;
  
  #ifdef CONFIG_ALTIVEC
        err |= __get_user(v_regs, &sc->v_regs);
 -      err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
        if (err)
                return err;
+       if (v_regs && !access_ok(VERIFY_READ, v_regs, 34 * sizeof(vector128)))
+               return -EFAULT;
        /* Copy 33 vec registers (vr0..31 and vscr) from the stack */
        if (v_regs != 0 && (msr & MSR_VEC) != 0)
                err |= __copy_from_user(current->thread.vr, v_regs,
@@@ -396,8 -396,8 +398,8 @@@ static int setup_rt_frame(int signr, st
        current->thread.fpscr.val = 0;
  
        /* Set up to return from userspace. */
 -      if (vdso64_rt_sigtramp && current->thread.vdso_base) {
 -              regs->link = current->thread.vdso_base + vdso64_rt_sigtramp;
 +      if (vdso64_rt_sigtramp && current->mm->context.vdso_base) {
 +              regs->link = current->mm->context.vdso_base + vdso64_rt_sigtramp;
        } else {
                err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
                if (err)
  
        /* Set up "regs" so we "return" to the signal handler. */
        err |= get_user(regs->nip, &funct_desc_ptr->entry);
 +      /* enter the signal handler in big-endian mode */
 +      regs->msr &= ~MSR_LE;
        regs->gpr[1] = newsp;
        err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
        regs->gpr[3] = signr;
@@@ -235,14 -235,14 +235,14 @@@ static void __init pSeries_setup_arch(v
        if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
                vpa_init(boot_cpuid);
                if (get_lppaca()->shared_proc) {
 -                      printk(KERN_INFO "Using shared processor idle loop\n");
 +                      printk(KERN_DEBUG "Using shared processor idle loop\n");
                        ppc_md.power_save = pseries_shared_idle_sleep;
                } else {
 -                      printk(KERN_INFO "Using dedicated idle loop\n");
 +                      printk(KERN_DEBUG "Using dedicated idle loop\n");
                        ppc_md.power_save = pseries_dedicated_idle_sleep;
                }
        } else {
 -              printk(KERN_INFO "Using default idle loop\n");
 +              printk(KERN_DEBUG "Using default idle loop\n");
        }
  
        if (firmware_has_feature(FW_FEATURE_LPAR))
@@@ -389,6 -389,7 +389,7 @@@ static int __init pSeries_probe_hyperta
  
  static int __init pSeries_probe(void)
  {
+       unsigned long root = of_get_flat_dt_root();
        char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
                                          "device_type", NULL);
        if (dtype == NULL)
        if (strcmp(dtype, "chrp"))
                return 0;
  
+       /* Cell blades firmware claims to be chrp while it's not. Until this
+        * is fixed, we need to avoid those here.
+        */
+       if (of_flat_dt_is_compatible(root, "IBM,CPBW-1.0") ||
+           of_flat_dt_is_compatible(root, "IBM,CBEA"))
+               return 0;
        DBG("pSeries detected, looking for LPAR capability...\n");
  
        /* Now try to figure out if we are running on LPAR */