diff options
Diffstat (limited to 'arch')
45 files changed, 443 insertions, 636 deletions
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c index fa34a06..73aeaf5 100644 --- a/arch/i386/kernel/cpu/amd.c +++ b/arch/i386/kernel/cpu/amd.c @@ -195,7 +195,7 @@ static void __init init_amd(struct cpuinfo_x86 *c) c->x86_num_cores = 1; } -#ifdef CONFIG_X86_SMP +#ifdef CONFIG_X86_HT /* * On a AMD dual core setup the lower bits of the APIC id * distingush the cores. Assumes number of cores is a power @@ -203,8 +203,11 @@ static void __init init_amd(struct cpuinfo_x86 *c) */ if (c->x86_num_cores > 1) { int cpu = smp_processor_id(); - /* Fix up the APIC ID following AMD specifications. */ - cpu_core_id[cpu] >>= hweight32(c->x86_num_cores - 1); + unsigned bits = 0; + while ((1 << bits) < c->x86_num_cores) + bits++; + cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1); + phys_proc_id[cpu] >>= bits; printk(KERN_INFO "CPU %d(%d) -> Core %d\n", cpu, c->x86_num_cores, cpu_core_id[cpu]); } diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 11e6e6f..d199e52 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -244,11 +244,8 @@ static void __init early_cpu_detect(void) early_intel_workaround(c); -#ifdef CONFIG_SMP #ifdef CONFIG_X86_HT - phys_proc_id[smp_processor_id()] = -#endif - cpu_core_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; + phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; #endif } diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index cbea7ac..35bfe13 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -888,6 +888,7 @@ void *xquad_portio; cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; +EXPORT_SYMBOL(cpu_core_map); static void __init smp_boot_cpus(unsigned int max_cpus) { diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index db06f73..ab54279 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c @@ -238,19 +238,21 @@ void iounmap(volatile void __iomem *addr) addr < phys_to_virt(ISA_END_ADDRESS)) return; - p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); + write_lock(&vmlist_lock); + p = __remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); if (!p) { - printk("__iounmap: bad address %p\n", addr); - return; + printk("iounmap: bad address %p\n", addr); + goto out_unlock; } if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) { - /* p->size includes the guard page, but cpa doesn't like that */ change_page_attr(virt_to_page(__va(p->phys_addr)), p->size >> PAGE_SHIFT, PAGE_KERNEL); global_flush_tlb(); } +out_unlock: + write_unlock(&vmlist_lock); kfree(p); } diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S index 9b6a8e5..6c7ae60 100644 --- a/arch/ppc/kernel/head_44x.S +++ b/arch/ppc/kernel/head_44x.S @@ -330,8 +330,9 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - andis. r11, r10, 0x8000 - beq 3f + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l @@ -464,8 +465,9 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - andis. r11, r10, 0x8000 - beq 3f + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l @@ -533,8 +535,9 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - andis. r11, r10, 0x8000 - beq 3f + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 309797d..5c20266 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -499,7 +499,7 @@ static int __init set_preferred_console(void) { struct device_node *prom_stdout; char *name; - int offset; + int offset = 0; if (of_stdout_device == NULL) return -ENODEV; diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S index 8d08a2e..36c9b97 100644 --- a/arch/ppc/lib/string.S +++ b/arch/ppc/lib/string.S @@ -446,6 +446,7 @@ _GLOBAL(__copy_tofrom_user) #ifdef CONFIG_8xx /* Don't use prefetch on 8xx */ mtctr r0 + li r0,0 53: COPY_16_BYTES_WITHEX(0) bdnz 53b @@ -564,7 +565,9 @@ _GLOBAL(__copy_tofrom_user) /* or write fault in cacheline loop */ 105: li r9,1 92: li r3,LG_CACHELINE_BYTES - b 99f + mfctr r8 + add r0,r0,r8 + b 106f /* read fault in final word loop */ 108: li r9,0 b 93f @@ -585,7 +588,7 @@ _GLOBAL(__copy_tofrom_user) * r5 + (ctr << r3), and r9 is 0 for read or 1 for write. */ 99: mfctr r0 - slw r3,r0,r3 +106: slw r3,r0,r3 add. r3,r3,r5 beq 120f /* shouldn't happen */ cmpwi 0,r9,0 diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index be02a7f..363c157 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -179,6 +179,7 @@ void free_initmem(void) if (!have_of) FREESEC(openfirmware); printk("\n"); + ppc_md.progress = NULL; #undef FREESEC } diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c index 5c1a919e..75c8e98 100644 --- a/arch/ppc/syslib/mpc83xx_devices.c +++ b/arch/ppc/syslib/mpc83xx_devices.c @@ -61,6 +61,7 @@ static struct plat_serial8250_port serial_platform_data[] = { .iotype = UPIO_MEM, .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, }, + { }, }; struct platform_device ppc_sys_platform_devices[] = { diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c index a231795..1e658ef 100644 --- a/arch/ppc/syslib/mpc85xx_devices.c +++ b/arch/ppc/syslib/mpc85xx_devices.c @@ -61,6 +61,7 @@ static struct plat_serial8250_port serial_platform_data[] = { .iotype = UPIO_MEM, .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ, }, + { }, }; struct platform_device ppc_sys_platform_devices[] = { diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index 7619e16..9d4ed68 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -557,12 +557,10 @@ static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec) */ void openpic_cause_IPI(u_int ipi, cpumask_t cpumask) { - cpumask_t phys; DECL_THIS_CPU; CHECK_THIS_CPU; check_arg_ipi(ipi); - phys = physmask(cpumask); openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpus_addr(physmask(cpumask))[0]); } diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index 35ec42d..6f79b7b 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -1750,7 +1750,44 @@ static void __init flatten_device_tree(void) prom_printf("Device tree struct 0x%x -> 0x%x\n", RELOC(dt_struct_start), RELOC(dt_struct_end)); - } +} + + +static void __init fixup_device_tree(void) +{ + unsigned long offset = reloc_offset(); + phandle u3, i2c, mpic; + u32 u3_rev; + u32 interrupts[2]; + u32 parent; + + /* Some G5s have a missing interrupt definition, fix it up here */ + u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); + if ((long)u3 <= 0) + return; + i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); + if ((long)i2c <= 0) + return; + mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); + if ((long)mpic <= 0) + return; + + /* check if proper rev of u3 */ + if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) <= 0) + return; + if (u3_rev != 0x35) + return; + /* does it need fixup ? */ + if (prom_getproplen(i2c, "interrupts") > 0) + return; + /* interrupt on this revision of u3 is number 0 and level */ + interrupts[0] = 0; + interrupts[1] = 1; + prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); + parent = (u32)mpic; + prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); +} + static void __init prom_find_boot_cpu(void) { @@ -1920,6 +1957,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long } /* + * Fixup any known bugs in the device-tree + */ + fixup_device_tree(); + + /* * Now finally create the flattened device-tree */ prom_printf("copying OF device tree ...\n"); diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 2929834..33ca56c 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -8,6 +8,7 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/delay.h> #include <asm/pbm.h> @@ -379,6 +380,56 @@ bad: return PCI_DMA_ERROR_CODE; } +static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages) +{ + int limit; + + PCI_STC_FLUSHFLAG_INIT(strbuf); + if (strbuf->strbuf_ctxflush && + iommu->iommu_ctxflush) { + unsigned long matchreg, flushreg; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); + + limit = 100000; + pci_iommu_write(flushreg, ctx); + for(;;) { + if (((long)pci_iommu_read(matchreg)) >= 0L) + break; + limit--; + if (!limit) + break; + udelay(1); + } + if (!limit) + printk(KERN_WARNING "pci_strbuf_flush: ctx flush " + "timeout vaddr[%08x] ctx[%lx]\n", + vaddr, ctx); + } else { + unsigned long i; + + for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, vaddr); + } + + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + + limit = 100000; + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) { + limit--; + if (!limit) + break; + udelay(1); + membar("#LoadLoad"); + } + if (!limit) + printk(KERN_WARNING "pci_strbuf_flush: flushflag timeout " + "vaddr[%08x] ctx[%lx] npages[%ld]\n", + vaddr, ctx, npages); +} + /* Unmap a single streaming mode DMA translation. */ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { @@ -386,7 +437,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int struct pci_iommu *iommu; struct pci_strbuf *strbuf; iopte_t *base; - unsigned long flags, npages, i, ctx; + unsigned long flags, npages, ctx; if (direction == PCI_DMA_NONE) BUG(); @@ -414,29 +465,8 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; /* Step 1: Kick data out of streaming buffers if necessary. */ - if (strbuf->strbuf_enabled) { - u32 vaddr = bus_addr; - - PCI_STC_FLUSHFLAG_INIT(strbuf); - if (strbuf->strbuf_ctxflush && - iommu->iommu_ctxflush) { - unsigned long matchreg, flushreg; - - flushreg = strbuf->strbuf_ctxflush; - matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - do { - pci_iommu_write(flushreg, ctx); - } while(((long)pci_iommu_read(matchreg)) < 0L); - } else { - for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, vaddr); - } - - pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); - (void) pci_iommu_read(iommu->write_complete_reg); - while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); - } + if (strbuf->strbuf_enabled) + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); /* Step 2: Clear out first TSB entry. */ iopte_make_dummy(iommu, base); @@ -647,29 +677,8 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; /* Step 1: Kick data out of streaming buffers if necessary. */ - if (strbuf->strbuf_enabled) { - u32 vaddr = (u32) bus_addr; - - PCI_STC_FLUSHFLAG_INIT(strbuf); - if (strbuf->strbuf_ctxflush && - iommu->iommu_ctxflush) { - unsigned long matchreg, flushreg; - - flushreg = strbuf->strbuf_ctxflush; - matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - do { - pci_iommu_write(flushreg, ctx); - } while(((long)pci_iommu_read(matchreg)) < 0L); - } else { - for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, vaddr); - } - - pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); - (void) pci_iommu_read(iommu->write_complete_reg); - while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); - } + if (strbuf->strbuf_enabled) + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); /* Step 2: Clear out first TSB entry. */ iopte_make_dummy(iommu, base); @@ -715,28 +724,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size } /* Step 2: Kick data out of streaming buffers. */ - PCI_STC_FLUSHFLAG_INIT(strbuf); - if (iommu->iommu_ctxflush && - strbuf->strbuf_ctxflush) { - unsigned long matchreg, flushreg; - - flushreg = strbuf->strbuf_ctxflush; - matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - do { - pci_iommu_write(flushreg, ctx); - } while(((long)pci_iommu_read(matchreg)) < 0L); - } else { - unsigned long i; - - for (i = 0; i < npages; i++, bus_addr += IO_PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, bus_addr); - } - - /* Step 3: Perform flush synchronization sequence. */ - pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); - (void) pci_iommu_read(iommu->write_complete_reg); - while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -749,7 +737,8 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i struct pcidev_cookie *pcp; struct pci_iommu *iommu; struct pci_strbuf *strbuf; - unsigned long flags, ctx; + unsigned long flags, ctx, npages, i; + u32 bus_addr; pcp = pdev->sysdata; iommu = pcp->pbm->iommu; @@ -772,36 +761,14 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i } /* Step 2: Kick data out of streaming buffers. */ - PCI_STC_FLUSHFLAG_INIT(strbuf); - if (iommu->iommu_ctxflush && - strbuf->strbuf_ctxflush) { - unsigned long matchreg, flushreg; - - flushreg = strbuf->strbuf_ctxflush; - matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - do { - pci_iommu_write(flushreg, ctx); - } while (((long)pci_iommu_read(matchreg)) < 0L); - } else { - unsigned long i, npages; - u32 bus_addr; - - bus_addr = sglist[0].dma_address & IO_PAGE_MASK; - - for(i = 1; i < nelems; i++) - if (!sglist[i].dma_length) - break; - i--; - npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - bus_addr) >> IO_PAGE_SHIFT; - for (i = 0; i < npages; i++, bus_addr += IO_PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, bus_addr); - } - - /* Step 3: Perform flush synchronization sequence. */ - pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); - (void) pci_iommu_read(iommu->write_complete_reg); - while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); + bus_addr = sglist[0].dma_address & IO_PAGE_MASK; + for(i = 1; i < nelems; i++) + if (!sglist[i].dma_length) + break; + i--; + npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) + - bus_addr) >> IO_PAGE_SHIFT; + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); spin_unlock_irqrestore(&iommu->lock, flags); } diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 14d9c3a..76ea645 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -117,19 +117,34 @@ static void iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages #define STRBUF_TAG_VALID 0x02UL -static void strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages) +static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages) { + unsigned long n; + int limit; + iommu->strbuf_flushflag = 0UL; - while (npages--) - upa_writeq(base + (npages << IO_PAGE_SHIFT), + n = npages; + while (n--) + upa_writeq(base + (n << IO_PAGE_SHIFT), iommu->strbuf_regs + STRBUF_PFLUSH); /* Whoopee cushion! */ upa_writeq(__pa(&iommu->strbuf_flushflag), iommu->strbuf_regs + STRBUF_FSYNC); upa_readq(iommu->sbus_control_reg); - while (iommu->strbuf_flushflag == 0UL) + + limit = 100000; + while (iommu->strbuf_flushflag == 0UL) { + limit--; + if (!limit) + break; + udelay(1); membar("#LoadLoad"); + } + if (!limit) + printk(KERN_WARNING "sbus_strbuf_flush: flushflag timeout " + "vaddr[%08x] npages[%ld]\n", + base, npages); } static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages) @@ -406,7 +421,7 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, spin_lock_irqsave(&iommu->lock, flags); free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT); - strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -569,7 +584,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int iommu = sdev->bus->iommu; spin_lock_irqsave(&iommu->lock, flags); free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT); - strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -581,7 +596,7 @@ void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t base, size_t size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK)); spin_lock_irqsave(&iommu->lock, flags); - strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -605,7 +620,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base; spin_lock_irqsave(&iommu->lock, flags); - strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags); } diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64 index fd8d7e8..f162f50 100644 --- a/arch/um/Kconfig_x86_64 +++ b/arch/um/Kconfig_x86_64 @@ -6,6 +6,10 @@ config 64BIT bool default y +config TOP_ADDR + hex + default 0x80000000 + config 3_LEVEL_PGTABLES bool default y diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 0150038..14a12d6 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -20,9 +20,17 @@ #include "os.h" #ifdef CONFIG_NOCONFIG_CHAN + +/* The printk's here are wrong because we are complaining that there is no + * output device, but printk is printing to that output device. The user will + * never see the error. printf would be better, except it can't run on a + * kernel stack because it will overflow it. + * Use printk for now since that will avoid crashing. + */ + static void *not_configged_init(char *str, int device, struct chan_opts *opts) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(NULL); } @@ -30,27 +38,27 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts) static int not_configged_open(int input, int output, int primary, void *data, char **dev_out) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-ENODEV); } static void not_configged_close(int fd, void *data) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); } static int not_configged_read(int fd, char *c_out, void *data) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-EIO); } static int not_configged_write(int fd, const char *buf, int len, void *data) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-EIO); } @@ -58,7 +66,7 @@ static int not_configged_write(int fd, const char *buf, int len, void *data) static int not_configged_console_write(int fd, const char *buf, int len, void *data) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-EIO); } @@ -66,7 +74,7 @@ static int not_configged_console_write(int fd, const char *buf, int len, static int not_configged_window_size(int fd, void *data, unsigned short *rows, unsigned short *cols) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-ENODEV); } diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index faf714e..217438c 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c @@ -73,7 +73,6 @@ int mcast_setup(char *str, char **mac_out, void *data) struct mcast_init *init = data; char *port_str = NULL, *ttl_str = NULL, *remain; char *last; - int n; *init = ((struct mcast_init) { .addr = "239.192.168.1", @@ -89,13 +88,12 @@ int mcast_setup(char *str, char **mac_out, void *data) } if(port_str != NULL){ - n = simple_strtoul(port_str, &last, 10); + init->port = simple_strtoul(port_str, &last, 10); if((*last != '\0') || (last == port_str)){ printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", port_str); return(0); } - init->port = htons(n); } if(ttl_str != NULL){ diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c index 0fe1d9f..7a0d115 100644 --- a/arch/um/drivers/mcast_user.c +++ b/arch/um/drivers/mcast_user.c @@ -38,7 +38,7 @@ static struct sockaddr_in *new_addr(char *addr, unsigned short port) } sin->sin_family = AF_INET; sin->sin_addr.s_addr = in_aton(addr); - sin->sin_port = port; + sin->sin_port = htons(port); return(sin); } @@ -55,28 +55,25 @@ static int mcast_open(void *data) struct mcast_data *pri = data; struct sockaddr_in *sin = pri->mcast_addr; struct ip_mreq mreq; - int fd, yes = 1; + int fd = -EINVAL, yes = 1, err = -EINVAL;; - if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) { - fd = -EINVAL; + if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) goto out; - } fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0){ printk("mcast_open : data socket failed, errno = %d\n", errno); - fd = -ENOMEM; + fd = -errno; goto out; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { printk("mcast_open: SO_REUSEADDR failed, errno = %d\n", errno); - os_close_file(fd); - fd = -EINVAL; - goto out; + goto out_close; } /* set ttl according to config */ @@ -84,26 +81,20 @@ static int mcast_open(void *data) sizeof(pri->ttl)) < 0) { printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n", errno); - os_close_file(fd); - fd = -EINVAL; - goto out; + goto out_close; } /* set LOOP, so data does get fed back to local sockets */ if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) { printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n", errno); - os_close_file(fd); - fd = -EINVAL; - goto out; + goto out_close; } /* bind socket to mcast address */ if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) { printk("mcast_open : data bind failed, errno = %d\n", errno); - os_close_file(fd); - fd = -EINVAL; - goto out; + goto out_close; } /* subscribe to the multicast group */ @@ -117,12 +108,15 @@ static int mcast_open(void *data) "interface on the host.\n"); printk("eth0 should be configured in order to use the " "multicast transport.\n"); - os_close_file(fd); - fd = -EINVAL; + goto out_close; } out: - return(fd); + return fd; + + out_close: + os_close_file(fd); + return err; } static void mcast_close(int fd, void *data) @@ -164,14 +158,3 @@ struct net_user_info mcast_user_info = { .delete_address = NULL, .max_packet = MAX_PACKET - ETH_HEADER_OTHER }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 9a56ff9..88f956c 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -55,7 +55,7 @@ #include "mem_kern.h" #include "cow.h" -enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP }; +enum ubd_req { UBD_READ, UBD_WRITE }; struct io_thread_req { enum ubd_req op; @@ -68,8 +68,6 @@ struct io_thread_req { unsigned long sector_mask; unsigned long long cow_offset; unsigned long bitmap_words[2]; - int map_fd; - unsigned long long map_offset; int error; }; @@ -122,10 +120,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file, #define MAX_DEV (8) -/* Changed in early boot */ -static int ubd_do_mmap = 0; -#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE - static struct block_device_operations ubd_blops = { .owner = THIS_MODULE, .open = ubd_open, @@ -175,12 +169,6 @@ struct ubd { int no_cow; struct cow cow; struct platform_device pdev; - - int map_writes; - int map_reads; - int nomap_writes; - int nomap_reads; - int write_maps; }; #define DEFAULT_COW { \ @@ -200,11 +188,6 @@ struct ubd { .openflags = OPEN_FLAGS, \ .no_cow = 0, \ .cow = DEFAULT_COW, \ - .map_writes = 0, \ - .map_reads = 0, \ - .nomap_writes = 0, \ - .nomap_reads = 0, \ - .write_maps = 0, \ } struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; @@ -314,13 +297,6 @@ static int ubd_setup_common(char *str, int *index_out) int major; str++; - if(!strcmp(str, "mmap")){ - CHOOSE_MODE(printk("mmap not supported by the ubd " - "driver in tt mode\n"), - ubd_do_mmap = 1); - return(0); - } - if(!strcmp(str, "sync")){ global_openflags = of_sync(global_openflags); return(0); @@ -524,7 +500,7 @@ static void ubd_handler(void) { struct io_thread_req req; struct request *rq = elv_next_request(ubd_queue); - int n, err; + int n; do_ubd = NULL; intr_count++; @@ -538,19 +514,6 @@ static void ubd_handler(void) return; } - if((req.op != UBD_MMAP) && - ((req.offset != ((__u64) (rq->sector)) << 9) || - (req.length != (rq->current_nr_sectors) << 9))) - panic("I/O op mismatch"); - - if(req.map_fd != -1){ - err = physmem_subst_mapping(req.buffer, req.map_fd, - req.map_offset, 1); - if(err) - printk("ubd_handler - physmem_subst_mapping failed, " - "err = %d\n", -err); - } - ubd_finish(rq, req.error); reactivate_fd(thread_fd, UBD_IRQ); do_ubd_request(ubd_queue); @@ -583,14 +546,10 @@ static int ubd_file_size(struct ubd *dev, __u64 *size_out) static void ubd_close(struct ubd *dev) { - if(ubd_do_mmap) - physmem_forget_descriptor(dev->fd); os_close_file(dev->fd); if(dev->cow.file == NULL) return; - if(ubd_do_mmap) - physmem_forget_descriptor(dev->cow.fd); os_close_file(dev->cow.fd); vfree(dev->cow.bitmap); dev->cow.bitmap = NULL; @@ -1010,94 +969,13 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, req->bitmap_words, bitmap_len); } -static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset) -{ - __u64 sector; - unsigned char *bitmap; - int bit, i; - - /* mmap must have been requested on the command line */ - if(!ubd_do_mmap) - return(-1); - - /* The buffer must be page aligned */ - if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0) - return(-1); - - /* The request must be a page long */ - if((req->current_nr_sectors << 9) != PAGE_SIZE) - return(-1); - - if(dev->cow.file == NULL) - return(dev->fd); - - sector = offset >> 9; - bitmap = (unsigned char *) dev->cow.bitmap; - bit = ubd_test_bit(sector, bitmap); - - for(i = 1; i < req->current_nr_sectors; i++){ - if(ubd_test_bit(sector + i, bitmap) != bit) - return(-1); - } - - if(bit || (rq_data_dir(req) == WRITE)) - offset += dev->cow.data_offset; - - /* The data on disk must be page aligned */ - if((offset % UBD_MMAP_BLOCK_SIZE) != 0) - return(-1); - - return(bit ? dev->fd : dev->cow.fd); -} - -static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset, - struct request *req, - struct io_thread_req *io_req) -{ - int err; - - if(rq_data_dir(req) == WRITE){ - /* Writes are almost no-ops since the new data is already in the - * host page cache - */ - dev->map_writes++; - if(dev->cow.file != NULL) - cowify_bitmap(io_req->offset, io_req->length, - &io_req->sector_mask, &io_req->cow_offset, - dev->cow.bitmap, dev->cow.bitmap_offset, - io_req->bitmap_words, - dev->cow.bitmap_len); - } - else { - int w; - - if((dev->cow.file != NULL) && (fd == dev->cow.fd)) - w = 0; - else w = dev->openflags.w; - - if((dev->cow.file != NULL) && (fd == dev->fd)) - offset += dev->cow.data_offset; - - err = physmem_subst_mapping(req->buffer, fd, offset, w); - if(err){ - printk("physmem_subst_mapping failed, err = %d\n", - -err); - return(1); - } - dev->map_reads++; - } - io_req->op = UBD_MMAP; - io_req->buffer = req->buffer; - return(0); -} - /* Called with ubd_io_lock held */ static int prepare_request(struct request *req, struct io_thread_req *io_req) { struct gendisk *disk = req->rq_disk; struct ubd *dev = disk->private_data; __u64 offset; - int len, fd; + int len; if(req->rq_status == RQ_INACTIVE) return(1); @@ -1114,34 +992,12 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; io_req->fds[1] = dev->fd; - io_req->map_fd = -1; io_req->cow_offset = -1; io_req->offset = offset; io_req->length = len; io_req->error = 0; io_req->sector_mask = 0; - fd = mmap_fd(req, dev, io_req->offset); - if(fd > 0){ - /* If mmapping is otherwise OK, but the first access to the - * page is a write, then it's not mapped in yet. So we have - * to write the data to disk first, then we can map the disk - * page in and continue normally from there. - */ - if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){ - io_req->map_fd = dev->fd; - io_req->map_offset = io_req->offset + - dev->cow.data_offset; - dev->write_maps++; - } - else return(prepare_mmap_request(dev, fd, io_req->offset, req, - io_req)); - } - - if(rq_data_dir(req) == READ) - dev->nomap_reads++; - else dev->nomap_writes++; - io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; io_req->offsets[0] = 0; io_req->offsets[1] = dev->cow.data_offset; @@ -1229,143 +1085,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file, return(-EINVAL); } -static int ubd_check_remapped(int fd, unsigned long address, int is_write, - __u64 offset) -{ - __u64 bitmap_offset; - unsigned long new_bitmap[2]; - int i, err, n; - - /* If it's not a write access, we can't do anything about it */ - if(!is_write) - return(0); - - /* We have a write */ - for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){ - struct ubd *dev = &ubd_dev[i]; - - if((dev->fd != fd) && (dev->cow.fd != fd)) - continue; - - /* It's a write to a ubd device */ - - /* This should be impossible now */ - if(!dev->openflags.w){ - /* It's a write access on a read-only device - probably - * shouldn't happen. If the kernel is trying to change - * something with no intention of writing it back out, - * then this message will clue us in that this needs - * fixing - */ - printk("Write access to mapped page from readonly ubd " - "device %d\n", i); - return(0); - } - - /* It's a write to a writeable ubd device - it must be COWed - * because, otherwise, the page would have been mapped in - * writeable - */ - - if(!dev->cow.file) - panic("Write fault on writeable non-COW ubd device %d", - i); - - /* It should also be an access to the backing file since the - * COW pages should be mapped in read-write - */ - - if(fd == dev->fd) - panic("Write fault on a backing page of ubd " - "device %d\n", i); - - /* So, we do the write, copying the backing data to the COW - * file... - */ - - err = os_seek_file(dev->fd, offset + dev->cow.data_offset); - if(err < 0) - panic("Couldn't seek to %lld in COW file of ubd " - "device %d, err = %d", - offset + dev->cow.data_offset, i, -err); - - n = os_write_file(dev->fd, (void *) address, PAGE_SIZE); - if(n != PAGE_SIZE) - panic("Couldn't copy data to COW file of ubd " - "device %d, err = %d", i, -n); - - /* ... updating the COW bitmap... */ - - cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset, - dev->cow.bitmap, dev->cow.bitmap_offset, - new_bitmap, dev->cow.bitmap_len); - - err = os_seek_file(dev->fd, bitmap_offset); - if(err < 0) - panic("Couldn't seek to %lld in COW file of ubd " - "device %d, err = %d", bitmap_offset, i, -err); - - n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap)); - if(n != sizeof(new_bitmap)) - panic("Couldn't update bitmap of ubd device %d, " - "err = %d", i, -n); - - /* Maybe we can map the COW page in, and maybe we can't. If - * it is a pre-V3 COW file, we can't, since the alignment will - * be wrong. If it is a V3 or later COW file which has been - * moved to a system with a larger page size, then maybe we - * can't, depending on the exact location of the page. - */ - - offset += dev->cow.data_offset; - - /* Remove the remapping, putting the original anonymous page - * back. If the COW file can be mapped in, that is done. - * Otherwise, the COW page is read in. - */ - - if(!physmem_remove_mapping((void *) address)) - panic("Address 0x%lx not remapped by ubd device %d", - address, i); - if((offset % UBD_MMAP_BLOCK_SIZE) == 0) - physmem_subst_mapping((void *) address, dev->fd, - offset, 1); - else { - err = os_seek_file(dev->fd, offset); - if(err < 0) - panic("Couldn't seek to %lld in COW file of " - "ubd device %d, err = %d", offset, i, - -err); - - n = os_read_file(dev->fd, (void *) address, PAGE_SIZE); - if(n != PAGE_SIZE) - panic("Failed to read page from offset %llx of " - "COW file of ubd device %d, err = %d", - offset, i, -n); - } - - return(1); - } - - /* It's not a write on a ubd device */ - return(0); -} - -static struct remapper ubd_remapper = { - .list = LIST_HEAD_INIT(ubd_remapper.list), - .proc = ubd_check_remapped, -}; - -static int ubd_remapper_setup(void) -{ - if(ubd_do_mmap) - register_remapper(&ubd_remapper); - - return(0); -} - -__initcall(ubd_remapper_setup); - static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) { struct uml_stat buf1, buf2; @@ -1568,15 +1287,6 @@ void do_io(struct io_thread_req *req) int err; __u64 off; - if(req->op == UBD_MMAP){ - /* Touch the page to force the host to do any necessary IO to - * get it into memory - */ - n = *((volatile int *) req->buffer); - req->error = update_bitmap(req); - return; - } - nsectors = req->length / req->sectorsize; start = 0; do { diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h index 84ec7ff..6eaeb99 100644 --- a/arch/um/include/sysdep-i386/ptrace.h +++ b/arch/um/include/sysdep-i386/ptrace.h @@ -31,7 +31,6 @@ extern int sysemu_supported; #ifdef UML_CONFIG_MODE_SKAS #include "skas_ptregs.h" -#include "sysdep/faultinfo.h" #define REGS_IP(r) ((r)[HOST_IP]) #define REGS_SP(r) ((r)[HOST_SP]) @@ -59,6 +58,7 @@ extern int sysemu_supported; #define PTRACE_SYSEMU_SINGLESTEP 32 #endif +#include "sysdep/faultinfo.h" #include "choose-mode.h" union uml_pt_regs { diff --git a/arch/um/include/sysdep-x86_64/checksum.h b/arch/um/include/sysdep-x86_64/checksum.h index 572c6c1..ea97005 100644 --- a/arch/um/include/sysdep-x86_64/checksum.h +++ b/arch/um/include/sysdep-x86_64/checksum.h @@ -9,8 +9,6 @@ #include "linux/in6.h" #include "asm/uaccess.h" -extern unsigned int csum_partial_copy_from(const unsigned char *src, unsigned char *dst, int len, - int sum, int *err_ptr); extern unsigned csum_partial(const unsigned char *buff, unsigned len, unsigned sum); @@ -31,10 +29,15 @@ unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char * } static __inline__ -unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, - int len, int sum, int *err_ptr) +unsigned int csum_partial_copy_from_user(const unsigned char *src, + unsigned char *dst, int len, int sum, + int *err_ptr) { - return csum_partial_copy_from(src, dst, len, sum, err_ptr); + if(copy_from_user(dst, src, len)){ + *err_ptr = -EFAULT; + return(-1); + } + return csum_partial(dst, len, sum); } /** @@ -137,15 +140,6 @@ static inline unsigned add32_with_carry(unsigned a, unsigned b) return a; } -#endif +extern unsigned short ip_compute_csum(unsigned char * buff, int len); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +#endif diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h index 348e8fc..be8acd5 100644 --- a/arch/um/include/sysdep-x86_64/ptrace.h +++ b/arch/um/include/sysdep-x86_64/ptrace.h @@ -135,6 +135,7 @@ extern int mode_tt; __CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs)) #define UPT_SC(r) ((r)->tt.sc) #define UPT_SYSCALL_NR(r) __CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall) +#define UPT_SYSCALL_RET(r) UPT_RAX(r) extern int user_context(unsigned long sp); @@ -196,32 +197,32 @@ struct syscall_args { #define UPT_SET(regs, reg, val) \ - ({ unsigned long val; \ + ({ unsigned long __upt_val = val; \ switch(reg){ \ - case R8: UPT_R8(regs) = val; break; \ - case R9: UPT_R9(regs) = val; break; \ - case R10: UPT_R10(regs) = val; break; \ - case R11: UPT_R11(regs) = val; break; \ - case R12: UPT_R12(regs) = val; break; \ - case R13: UPT_R13(regs) = val; break; \ - case R14: UPT_R14(regs) = val; break; \ - case R15: UPT_R15(regs) = val; break; \ - case RIP: UPT_IP(regs) = val; break; \ - case RSP: UPT_SP(regs) = val; break; \ - case RAX: UPT_RAX(regs) = val; break; \ - case RBX: UPT_RBX(regs) = val; break; \ - case RCX: UPT_RCX(regs) = val; break; \ - case RDX: UPT_RDX(regs) = val; break; \ - case RSI: UPT_RSI(regs) = val; break; \ - case RDI: UPT_RDI(regs) = val; break; \ - case RBP: UPT_RBP(regs) = val; break; \ - case ORIG_RAX: UPT_ORIG_RAX(regs) = val; break; \ - case CS: UPT_CS(regs) = val; break; \ - case DS: UPT_DS(regs) = val; break; \ - case ES: UPT_ES(regs) = val; break; \ - case FS: UPT_FS(regs) = val; break; \ - case GS: UPT_GS(regs) = val; break; \ - case EFLAGS: UPT_EFLAGS(regs) = val; break; \ + case R8: UPT_R8(regs) = __upt_val; break; \ + case R9: UPT_R9(regs) = __upt_val; break; \ + case R10: UPT_R10(regs) = __upt_val; break; \ + case R11: UPT_R11(regs) = __upt_val; break; \ + case R12: UPT_R12(regs) = __upt_val; break; \ + case R13: UPT_R13(regs) = __upt_val; break; \ + case R14: UPT_R14(regs) = __upt_val; break; \ + case R15: UPT_R15(regs) = __upt_val; break; \ + case RIP: UPT_IP(regs) = __upt_val; break; \ + case RSP: UPT_SP(regs) = __upt_val; break; \ + case RAX: UPT_RAX(regs) = __upt_val; break; \ + case RBX: UPT_RBX(regs) = __upt_val; break; \ + case RCX: UPT_RCX(regs) = __upt_val; break; \ + case RDX: UPT_RDX(regs) = __upt_val; break; \ + case RSI: UPT_RSI(regs) = __upt_val; break; \ + case RDI: UPT_RDI(regs) = __upt_val; break; \ + case RBP: UPT_RBP(regs) = __upt_val; break; \ + case ORIG_RAX: UPT_ORIG_RAX(regs) = __upt_val; break; \ + case CS: UPT_CS(regs) = __upt_val; break; \ + case DS: UPT_DS(regs) = __upt_val; break; \ + case ES: UPT_ES(regs) = __upt_val; break; \ + case FS: UPT_FS(regs) = __upt_val; break; \ + case GS: UPT_GS(regs) = __upt_val; break; \ + case EFLAGS: UPT_EFLAGS(regs) = __upt_val; break; \ default : \ panic("Bad register in UPT_SET : %d\n", reg); \ break; \ @@ -245,14 +246,3 @@ struct syscall_args { CHOOSE_MODE((&(r)->tt.faultinfo), (&(r)->skas.faultinfo)) #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 9736ca2..a8918e80 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -14,7 +14,7 @@ obj-y = config.o exec_kern.o exitcode.o \ tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o umid.o \ user_util.o -obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o +obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o obj-$(CONFIG_TTY_LOG) += tty_log.o diff --git a/arch/um/kernel/checksum.c b/arch/um/kernel/checksum.c deleted file mode 100644 index e69de29..0000000 --- a/arch/um/kernel/checksum.c +++ /dev/null diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c new file mode 100644 index 0000000..82ecf90 --- /dev/null +++ b/arch/um/kernel/initrd.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/init.h" +#include "linux/bootmem.h" +#include "linux/initrd.h" +#include "asm/types.h" +#include "user_util.h" +#include "kern_util.h" +#include "initrd.h" +#include "init.h" +#include "os.h" + +/* Changed by uml_initrd_setup, which is a setup */ +static char *initrd __initdata = NULL; + +static int __init read_initrd(void) +{ + void *area; + long long size; + int err; + + if(initrd == NULL) return 0; + err = os_file_size(initrd, &size); + if(err) return 0; + area = alloc_bootmem(size); + if(area == NULL) return 0; + if(load_initrd(initrd, area, size) == -1) return 0; + initrd_start = (unsigned long) area; + initrd_end = initrd_start + size; + return 0; +} + +__uml_postsetup(read_initrd); + +static int __init uml_initrd_setup(char *line, int *add) +{ + initrd = line; + return 0; +} + +__uml_setup("initrd=", uml_initrd_setup, +"initrd=<initrd image>\n" +" This is used to boot UML from an initrd image. The argument is the\n" +" name of the file containing the image.\n\n" +); + +int load_initrd(char *filename, void *buf, int size) +{ + int fd, n; + + fd = os_open_file(filename, of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Opening '%s' failed - err = %d\n", filename, -fd); + return(-1); + } + n = os_read_file(fd, buf, size); + if(n != size){ + printk("Read of %d bytes from '%s' failed, err = %d\n", size, + filename, -n); + return(-1); + } + + os_close_file(fd); + return(0); +} +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 78d69dc..99439fa 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -57,6 +57,7 @@ EXPORT_SYMBOL(copy_to_user_tt); EXPORT_SYMBOL(strncpy_from_user_skas); EXPORT_SYMBOL(copy_to_user_skas); EXPORT_SYMBOL(copy_from_user_skas); +EXPORT_SYMBOL(clear_user_skas); #endif EXPORT_SYMBOL(uml_strdup); diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index f156661..c22825f 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -100,12 +100,37 @@ void mem_init(void) #endif } +/* + * Create a page table and place a pointer to it in a middle page + * directory entry. + */ +static void __init one_page_table_init(pmd_t *pmd) +{ + if (pmd_none(*pmd)) { + pte_t *pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pmd(pmd, __pmd(_KERNPG_TABLE + + (unsigned long) __pa(pte))); + if (pte != pte_offset_kernel(pmd, 0)) + BUG(); + } +} + +static void __init one_md_table_init(pud_t *pud) +{ +#ifdef CONFIG_3_LEVEL_PGTABLES + pmd_t *pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pud(pud, __pud(_KERNPG_TABLE + (unsigned long) __pa(pmd_table))); + if (pmd_table != pmd_offset(pud, 0)) + BUG(); +#endif +} + static void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) { pgd_t *pgd; + pud_t *pud; pmd_t *pmd; - pte_t *pte; int i, j; unsigned long vaddr; @@ -115,15 +140,12 @@ static void __init fixrange_init(unsigned long start, unsigned long end, pgd = pgd_base + i; for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) { - pmd = (pmd_t *)pgd; + pud = pud_offset(pgd, vaddr); + if (pud_none(*pud)) + one_md_table_init(pud); + pmd = pmd_offset(pud, vaddr); for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) { - if (pmd_none(*pmd)) { - pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pmd, __pmd(_KERNPG_TABLE + - (unsigned long) __pa(pte))); - if (pte != pte_offset_kernel(pmd, 0)) - BUG(); - } + one_page_table_init(pmd); vaddr += PMD_SIZE; } j = 0; diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 2b75d8d..2925e15 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -28,9 +28,9 @@ static inline void set_singlestepping(struct task_struct *child, int on) child->thread.singlestep_syscall = 0; #ifdef SUBARCH_SET_SINGLESTEPPING - SUBARCH_SET_SINGLESTEPPING(child, on) + SUBARCH_SET_SINGLESTEPPING(child, on); #endif - } +} /* * Called by kernel/ptrace.c when detaching.. @@ -83,7 +83,7 @@ long sys_ptrace(long request, long pid, long addr, long data) } #ifdef SUBACH_PTRACE_SPECIAL - SUBARCH_PTRACE_SPECIAL(child,request,addr,data) + SUBARCH_PTRACE_SPECIAL(child,request,addr,data); #endif ret = ptrace_check_attach(child, request == PTRACE_KILL); diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 5fca2c6..1de22d8 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -57,10 +57,11 @@ int handle_page_fault(unsigned long address, unsigned long ip, *code_out = SEGV_ACCERR; if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; + + if(!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto out; + page = address & PAGE_MASK; - pgd = pgd_offset(mm, page); - pud = pud_offset(pgd, page); - pmd = pmd_offset(pud, page); do { survive: switch (handle_mm_fault(mm, vma, address, is_write)){ @@ -106,33 +107,6 @@ out_of_memory: goto out; } -LIST_HEAD(physmem_remappers); - -void register_remapper(struct remapper *info) -{ - list_add(&info->list, &physmem_remappers); -} - -static int check_remapped_addr(unsigned long address, int is_write) -{ - struct remapper *remapper; - struct list_head *ele; - __u64 offset; - int fd; - - fd = phys_mapping(__pa(address), &offset); - if(fd == -1) - return(0); - - list_for_each(ele, &physmem_remappers){ - remapper = list_entry(ele, struct remapper, list); - if((*remapper->proc)(fd, address, is_write, offset)) - return(1); - } - - return(0); -} - /* * We give a *copy* of the faultinfo in the regs to segv. * This must be done, since nesting SEGVs could overwrite @@ -151,8 +125,6 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) flush_tlb_kernel_vm(); return(0); } - else if(check_remapped_addr(address & PAGE_MASK, is_write)) - return(0); else if(current->mm == NULL) panic("Segfault with no mm"); err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c index 92ec85d..84a9385 100644 --- a/arch/um/kernel/tt/ksyms.c +++ b/arch/um/kernel/tt/ksyms.c @@ -12,6 +12,7 @@ EXPORT_SYMBOL(__do_copy_to_user); EXPORT_SYMBOL(__do_strncpy_from_user); EXPORT_SYMBOL(__do_strnlen_user); EXPORT_SYMBOL(__do_clear_user); +EXPORT_SYMBOL(clear_user_tt); EXPORT_SYMBOL(tracing_pid); EXPORT_SYMBOL(honeypot); diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index 76eadb3..dd53555 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -73,6 +73,8 @@ SECTIONS .got : { *(.got.plt) *(.got) } .dynamic : { *(.dynamic) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index fcd67c3..4351e56 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -9,11 +9,11 @@ USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o SYMLINKS = bitops.c semaphore.c highmem.c module.c +include arch/um/scripts/Makefile.rules + bitops.c-dir = lib semaphore.c-dir = kernel highmem.c-dir = mm module.c-dir = kernel subdir- := util - -include arch/um/scripts/Makefile.rules diff --git a/arch/um/sys-i386/delay.c b/arch/um/sys-i386/delay.c index e9892ee..2c11b97 100644 --- a/arch/um/sys-i386/delay.c +++ b/arch/um/sys-i386/delay.c @@ -1,5 +1,7 @@ -#include "linux/delay.h" -#include "asm/param.h" +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <asm/param.h> void __delay(unsigned long time) { @@ -20,13 +22,19 @@ void __udelay(unsigned long usecs) int i, n; n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) ; + for(i=0;i<n;i++) + cpu_relax(); } +EXPORT_SYMBOL(__udelay); + void __const_udelay(unsigned long usecs) { int i, n; n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) ; + for(i=0;i<n;i++) + cpu_relax(); } + +EXPORT_SYMBOL(__const_udelay); diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 3d7da91..608466a 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -14,11 +14,11 @@ obj-$(CONFIG_MODULES) += module.o um_module.o USER_OBJS := ptrace_user.o sigcontext.o -include arch/um/scripts/Makefile.rules - SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \ semaphore.c thunk.S module.c +include arch/um/scripts/Makefile.rules + bitops.c-dir = lib csum-copy.S-dir = lib csum-partial.c-dir = lib @@ -28,6 +28,4 @@ semaphore.c-dir = kernel thunk.S-dir = lib module.c-dir = kernel -CFLAGS_csum-partial.o := -Dcsum_partial=arch_csum_partial - subdir- := util diff --git a/arch/um/sys-x86_64/delay.c b/arch/um/sys-x86_64/delay.c index 651332a..137f444 100644 --- a/arch/um/sys-x86_64/delay.c +++ b/arch/um/sys-x86_64/delay.c @@ -5,40 +5,37 @@ * Licensed under the GPL */ -#include "linux/delay.h" -#include "asm/processor.h" -#include "asm/param.h" +#include <linux/module.h> +#include <linux/delay.h> +#include <asm/processor.h> +#include <asm/param.h> void __delay(unsigned long loops) { unsigned long i; - for(i = 0; i < loops; i++) ; + for(i = 0; i < loops; i++) + cpu_relax(); } void __udelay(unsigned long usecs) { - int i, n; + unsigned long i, n; n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) ; + for(i=0;i<n;i++) + cpu_relax(); } +EXPORT_SYMBOL(__udelay); + void __const_udelay(unsigned long usecs) { - int i, n; + unsigned long i, n; n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) ; + for(i=0;i<n;i++) + cpu_relax(); } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +EXPORT_SYMBOL(__const_udelay); diff --git a/arch/um/sys-x86_64/ksyms.c b/arch/um/sys-x86_64/ksyms.c index a27f0ee..8592738 100644 --- a/arch/um/sys-x86_64/ksyms.c +++ b/arch/um/sys-x86_64/ksyms.c @@ -16,5 +16,4 @@ EXPORT_SYMBOL(__up_wakeup); EXPORT_SYMBOL(__memcpy); /* Networking helper routines. */ -/*EXPORT_SYMBOL(csum_partial_copy_from); -EXPORT_SYMBOL(csum_partial_copy_to);*/ +EXPORT_SYMBOL(ip_compute_csum); diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index b593bb2..74eee5c 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c @@ -5,10 +5,11 @@ */ #define __FRAME_OFFSETS -#include "asm/ptrace.h" -#include "linux/sched.h" -#include "linux/errno.h" -#include "asm/elf.h" +#include <asm/ptrace.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <asm/uaccess.h> +#include <asm/elf.h> /* XXX x86_64 */ unsigned long not_ss; diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index dd99146..d4a5965 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c @@ -15,6 +15,7 @@ #include "asm/unistd.h" #include "asm/prctl.h" /* XXX This should get the constants from libc */ #include "choose-mode.h" +#include "kern.h" asmlinkage long sys_uname64(struct new_utsname __user * name) { diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c index 5e14792..513d17c 100644 --- a/arch/um/sys-x86_64/user-offsets.c +++ b/arch/um/sys-x86_64/user-offsets.c @@ -3,6 +3,14 @@ #include <signal.h> #define __FRAME_OFFSETS #include <asm/ptrace.h> +#include <asm/types.h> +/* For some reason, x86_64 defines u64 and u32 only in <pci/types.h>, which I + * refuse to include here, even though they're used throughout the headers. + * These are used in asm/user.h, and that include can't be avoided because of + * the sizeof(struct user_regs_struct) below. + */ +typedef __u64 u64; +typedef __u32 u32; #include <asm/user.h> #define DEFINE(sym, val) \ diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index ac76843..80e9b49 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -42,6 +42,8 @@ int sis_apic_bug; /* not actually supported, dummy for compile */ +static int no_timer_check; + static DEFINE_SPINLOCK(ioapic_lock); /* @@ -1601,7 +1603,7 @@ static inline void check_timer(void) * Ok, does IRQ0 through the IOAPIC work? */ unmask_IO_APIC_irq(0); - if (timer_irq_works()) { + if (!no_timer_check && timer_irq_works()) { nmi_watchdog_default(); if (nmi_watchdog == NMI_IO_APIC) { disable_8259A_irq(0); @@ -1671,6 +1673,13 @@ static inline void check_timer(void) panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n"); } +static int __init notimercheck(char *s) +{ + no_timer_check = 1; + return 1; +} +__setup("no_timer_check", notimercheck); + /* * * IRQ's that are handled by the PIC in the MPS IOAPIC case. diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index 60dc9b9..525f6a1 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -380,7 +380,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; switch (addr) { - case 0 ... sizeof(struct user_regs_struct): + case 0 ... sizeof(struct user_regs_struct) - sizeof(long): tmp = getreg(child, addr); break; case offsetof(struct user, u_debugreg[0]): @@ -425,7 +425,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; switch (addr) { - case 0 ... sizeof(struct user_regs_struct): + case 0 ... sizeof(struct user_regs_struct) - sizeof(long): ret = putreg(child, addr, data); break; /* Disallows to set a breakpoint into the vsyscall */ diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index b9fd025..99f038e 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -719,7 +719,6 @@ static void __init display_cacheinfo(struct cpuinfo_x86 *c) } } -#ifdef CONFIG_SMP /* * On a AMD dual core setup the lower bits of the APIC id distingush the cores. * Assumes number of cores is a power of two. @@ -729,16 +728,24 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) #ifdef CONFIG_SMP int cpu = smp_processor_id(); int node = 0; + unsigned bits; if (c->x86_num_cores == 1) return; - /* Fix up the APIC ID following the AMD specification. */ - cpu_core_id[cpu] >>= hweight32(c->x86_num_cores - 1); + + bits = 0; + while ((1 << bits) < c->x86_num_cores) + bits++; + + /* Low order bits define the core id (index of core in socket) */ + cpu_core_id[cpu] = phys_proc_id[cpu] & ((1 << bits)-1); + /* Convert the APIC ID into the socket ID */ + phys_proc_id[cpu] >>= bits; #ifdef CONFIG_NUMA /* When an ACPI SRAT table is available use the mappings from SRAT instead. */ if (acpi_numa <= 0) { - node = cpu_core_id[cpu]; + node = phys_proc_id[cpu]; if (!node_online(node)) node = first_node(node_online_map); cpu_to_node[cpu] = node; @@ -746,18 +753,11 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) node = cpu_to_node[cpu]; } #endif - /* For now: - better than BAD_APIC_ID at least*/ - phys_proc_id[cpu] = cpu_core_id[cpu]; printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n", cpu, c->x86_num_cores, node, cpu_core_id[cpu]); #endif } -#else -static void __init amd_detect_cmp(struct cpuinfo_x86 *c) -{ -} -#endif static int __init init_amd(struct cpuinfo_x86 *c) { @@ -963,8 +963,7 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c) } #ifdef CONFIG_SMP - phys_proc_id[smp_processor_id()] = - cpu_core_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; + phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; #endif } diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index d439ced..3fdcdba 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -452,7 +452,9 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) regs->rip -= 2; } if (regs->rax == (unsigned long)-ERESTART_RESTARTBLOCK) { - regs->rax = __NR_restart_syscall; + regs->rax = test_thread_flag(TIF_IA32) ? + __NR_ia32_restart_syscall : + __NR_restart_syscall; regs->rip -= 2; } } diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 5abdee1..f1ec0f3 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -94,6 +94,7 @@ int smp_threads_ready; cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; +EXPORT_SYMBOL(cpu_core_map); /* * Trampoline 80x86 program as an array. diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c index c6fb0cb..58aac23 100644 --- a/arch/x86_64/mm/ioremap.c +++ b/arch/x86_64/mm/ioremap.c @@ -133,7 +133,7 @@ ioremap_change_attr(unsigned long phys_addr, unsigned long size, unsigned long flags) { int err = 0; - if (flags && phys_addr + size - 1 < (end_pfn_map << PAGE_SHIFT)) { + if (phys_addr + size - 1 < (end_pfn_map << PAGE_SHIFT)) { unsigned long npages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; unsigned long vaddr = (unsigned long) __va(phys_addr); @@ -214,7 +214,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr)); return NULL; } - if (ioremap_change_attr(phys_addr, size, flags) < 0) { + if (flags && ioremap_change_attr(phys_addr, size, flags) < 0) { area->flags &= 0xffffff; vunmap(addr); return NULL; @@ -251,7 +251,7 @@ void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) void iounmap(volatile void __iomem *addr) { - struct vm_struct *p, **pprev; + struct vm_struct *p; if (addr <= high_memory) return; @@ -260,24 +260,11 @@ void iounmap(volatile void __iomem *addr) return; write_lock(&vmlist_lock); - for (p = vmlist, pprev = &vmlist; p != NULL; pprev = &p->next, p = *pprev) - if (p->addr == (void *)(PAGE_MASK & (unsigned long)addr)) - break; - if (!p) { - printk("__iounmap: bad address %p\n", addr); - goto out_unlock; - } - *pprev = p->next; - unmap_vm_area(p); - if ((p->flags >> 20) && - p->phys_addr + p->size - 1 < virt_to_phys(high_memory)) { - /* p->size includes the guard page, but cpa doesn't like that */ - change_page_attr_addr((unsigned long)__va(p->phys_addr), - p->size >> PAGE_SHIFT, - PAGE_KERNEL); - global_flush_tlb(); - } -out_unlock: + p = __remove_vm_area((void *)((unsigned long)addr & PAGE_MASK)); + if (!p) + printk("iounmap: bad address %p\n", addr); + else if (p->flags >> 20) + ioremap_change_attr(p->phys_addr, p->size, 0); write_unlock(&vmlist_lock); kfree(p); } |