X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=blobdiff_plain;f=fs%2Fproc%2Ftask_mmu.c;h=bc02b6b966dcf5e25b75fdc66a4029d4c989b666;hp=e418c5abdb0ef954eed21771ca0ff1fe9958077d;hb=c5fd6bc55245c79d586df8541498a3f2204ae7bc;hpb=ab61a6857269989acc6796ffc44e2b4f11a193dc diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index e418c5abdb0e..bc02b6b966dc 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -209,6 +209,196 @@ static int do_maps_open(struct inode *inode, struct file *file, return ret; } +#ifdef __arm__ +static void show_arm_map_vma(struct seq_file *m, struct vm_area_struct *vma) +{ + static const char *cache_attrs4[4] = { "noC", "WB-WA", "WT-noWA", "WB-noWA" }; + struct mm_struct *mm = vma->vm_mm; + struct file *file = vma->vm_file; + vm_flags_t flags = vma->vm_flags; + unsigned long start, end, end_b; + const char *name = NULL; + u32 *arm_pgd; + u32 *cpt, *cpt_e; + u32 desc1, desc2; + u32 tex_cb = 0; + u32 prrr, nmrr = 0; + u32 control = 0; + u32 xn = 1, ap = 0; + int desc_type; + int type; + char buf[64]; + char rw[4]; + int len; + int s; + + if (mm == NULL) + return; + + if (!file) { + name = arch_vma_name(vma); + if (!name) { + if (vma->vm_start <= mm->brk && + vma->vm_end >= mm->start_brk) { + name = "[heap]"; + } else if (vma->vm_start <= mm->start_stack && + vma->vm_end >= mm->start_stack) { + name = "[stack]"; + } + } + } + + arm_pgd = (u32 *)mm->pgd; + + asm ("mrc p15, 0, %0, c1, c0, 0" : "=r"(control)); + asm ("mrc p15, 0, %0, c10, c2, 0" : "=r"(prrr)); // primary region RR + asm ("mrc p15, 0, %0, c10, c2, 1" : "=r"(nmrr)); // normal memory RR + + start = vma->vm_start; + end = vma->vm_end; + + while (start < end) { + desc_type = '-'; + + desc1 = arm_pgd[start >> 20]; + + end_b = (start & ~0xfffff) + 0x100000; + for (; end_b < end; end_b += 0x100000) + if ((arm_pgd[end_b >> 20] ^ desc1) & 0xfffff) + break; + + switch (desc1 & 3) { + case 0: + sprintf(buf, "l1_fault"); + goto do_output; + case 1: + break; + case 2: + tex_cb = ((desc1 >> 2) & 0x03) | ((desc1 >> 10) & 0x1c); + s = (desc1 >> 16) & 1; + xn = (desc1 >> 4) & 1; + ap = ((desc1 >> 10) & 3) | ((desc1 >> 13) & 4); + desc_type = (desc1 & (1 << 18)) ? 's' : 'h'; + goto do_tex_cb; + case 3: + sprintf(buf, "reserved"); + goto do_output; + } + + cpt = __va(desc1 & 0xfffffc00); + desc2 = cpt[(start >> 12) & 0xff]; + + // find end + cpt_e = cpt; + for (end_b = start + 0x1000; end_b < end; end_b += 0x1000) { + if ((end_b & 0x000ff000) == 0) { + cpt_e = __va(arm_pgd[end_b >> 20] & 0xfffffc00); + if ((arm_pgd[end_b >> 20] ^ desc1) & 0x3ff) + break; + } + + // assume small pages + if ((cpt_e[(end_b >> 12) & 0xff] ^ desc2) & 0xfff) + break; + } + + switch (desc2 & 3) { + case 0: + sprintf(buf, "l2_fault"); + goto do_output; + case 1: + tex_cb = ((desc2 >> 2) & 0x03) | ((desc2 >> 10) & 0x1c); + s = (desc2 >> 10) & 1; + xn = (desc2 >> 15) & 1; + ap = ((desc2 >> 4) & 3) | ((desc2 >> 7) & 4); + break; + case 2: + case 3: + tex_cb = ((desc2 >> 2) & 0x03) | ((desc2 >> 4) & 0x1c); + s = (desc2 >> 10) & 1; + xn = desc2 & 1; + ap = ((desc2 >> 4) & 3) | ((desc2 >> 7) & 4); + break; + } + +do_tex_cb: + if (control & (1 << 28)) { // TEX remap + // S (shareable) bit remapping + char s_normal[2] = { (prrr >> 18) & 1, (prrr >> 19) & 1 }; + char s_device[2] = { (prrr >> 16) & 1, (prrr >> 17) & 1 }; + + buf[0] = 0; + tex_cb &= 7; + type = (prrr >> tex_cb * 2) & 3; + switch (type) { + case 0: + sprintf(buf, "strongly-ordered"); + break; + case 1: + sprintf(buf, "device"); + s = s_device[s]; + break; + case 3: + sprintf(buf, "reserved/normal"); + case 2: + s = s_normal[s]; + sprintf(buf + strlen(buf), "inner-%s-outer-%s", + cache_attrs4[(nmrr >> tex_cb * 2) & 3], + cache_attrs4[(nmrr >> (tex_cb * 2 + 16)) & 3]); + } + } + else if (tex_cb & 0x10) { // TEX[2] set + sprintf(buf, "inner-%s-outer-%s", + cache_attrs4[tex_cb & 3], cache_attrs4[(tex_cb >> 2) & 3]); + } + else { + switch (tex_cb) { + case 0x00: sprintf(buf, "strongly-ordered"); s = 1; break; + case 0x01: sprintf(buf, "shareable-device"); s = 1; break; + case 0x02: sprintf(buf, "inner-outer-WT-noWA"); break; + case 0x03: sprintf(buf, "inner-outer-WB-noWA"); break; + case 0x04: sprintf(buf, "inner-outer-non-cacheable"); break; + case 0x06: sprintf(buf, "implementation-defined"); break; + case 0x07: sprintf(buf, "inner-outer-WB-WA"); break; + case 0x08: sprintf(buf, "non-shareable-device"); s = 0; break; + default: sprintf(buf, "reserved"); break; + } + } + + if (s) + sprintf(buf + strlen(buf), "-shareable"); + +do_output: + // use user permissions here + if (control & (1 << 29)) // AFE + sprintf(rw, "%c%c", (ap & 2) ? 'r' : '-', + ((ap & 2) && !(ap & 4)) ? 'w' : '-'); + else + sprintf(rw, "%c%c", (ap & 2) ? 'r' : '-', + (ap == 3) ? 'w' : '-'); + + seq_printf(m, "%08lx-%08lx %s%c%c%c %-28s %n", + start, end_b, + rw, + xn ? '-' : 'x', + flags & VM_MAYSHARE ? 's' : 'p', + desc_type, + buf, &len); + + if (file) { + pad_len_spaces(m, len); + seq_path(m, &file->f_path, "\n"); + } else if (name) { + pad_len_spaces(m, len); + seq_puts(m, name); + } + seq_putc(m, '\n'); + + start = end_b; + } +} +#endif + static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) { struct mm_struct *mm = vma->vm_mm; @@ -308,6 +498,41 @@ const struct file_operations proc_maps_operations = { .release = seq_release_private, }; +#ifdef __arm__ +static int show_armv7_map(struct seq_file *m, void *v) +{ + struct vm_area_struct *vma = v; + struct proc_maps_private *priv = m->private; + struct task_struct *task = priv->task; + + show_arm_map_vma(m, vma); + + if (m->count < m->size) /* vma is copied successfully */ + m->version = (vma != get_gate_vma(task->mm)) + ? vma->vm_start : 0; + return 0; +} + +static const struct seq_operations proc_pid_armv7_maps_op = { + .start = m_start, + .next = m_next, + .stop = m_stop, + .show = show_armv7_map +}; +#endif + +static int armv7_maps_open(struct inode *inode, struct file *file) +{ + return do_maps_open(inode, file, &proc_pid_armv7_maps_op); +} + +const struct file_operations proc_armv7_maps_operations = { + .open = armv7_maps_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + /* * Proportional Set Size(PSS): my share of RSS. * @@ -409,6 +634,9 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, } else { spin_unlock(&walk->mm->page_table_lock); } + + if (pmd_trans_unstable(pmd)) + return 0; /* * The mmap_sem held all the way back in m_start() is what * keeps khugepaged out of here and from collapsing things @@ -507,6 +735,8 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, struct page *page; split_huge_page_pmd(walk->mm, pmd); + if (pmd_trans_unstable(pmd)) + return 0; pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); for (; addr != end; pte++, addr += PAGE_SIZE) { @@ -518,6 +748,9 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, if (!page) continue; + if (PageReserved(page)) + continue; + /* Clear accessed and referenced bits. */ ptep_test_and_clear_young(vma, addr, pte); ClearPageReferenced(page); @@ -596,7 +829,7 @@ const struct file_operations proc_clear_refs_operations = { }; struct pagemapread { - int pos, len; + int pos, len; /* units: PM_ENTRY_BYTES, not bytes */ u64 *buffer; }; @@ -667,6 +900,8 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, int err = 0; split_huge_page_pmd(walk->mm, pmd); + if (pmd_trans_unstable(pmd)) + return 0; /* find the first VMA at or above 'addr' */ vma = find_vma(walk->mm, addr); @@ -782,8 +1017,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, if (!count) goto out_task; - pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); - pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); + pm.len = (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); + pm.buffer = kmalloc(pm.len * PM_ENTRY_BYTES, GFP_TEMPORARY); ret = -ENOMEM; if (!pm.buffer) goto out_task; @@ -958,6 +1193,8 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, spin_unlock(&walk->mm->page_table_lock); } + if (pmd_trans_unstable(pmd)) + return 0; orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); do { struct page *page = can_gather_numa_stats(*pte, md->vma, addr);