On 16 Jun, David S. Miller wrote:
> Yes, before 2.2.{8,9} there were several IOMMU mapping problems on
> sun4m systems. Please fetch the latest on the stable branch and try
> again.
Have done so. (fetched linux_2_2 branch) Same problem. Any comments
on what the problems were, or documentation on how IOMMU works?
I've recompiled the kernel from scratch, also.
Spent a few hours playing with the exploit module. My latest sloppy
version is attached. I had to add some exports to the kernel for this
thing to work (set_pte, init_task_union, others) Read on, about what it
does.
At first, I didn't think this was an IOMMU problem. I mean, regardless
of what the IOMMU does, I'm still mapping real memory, right? Unless
the IOMMU is just zero'ing memory out somehow (notice that the module
does no peripheral operations whatever), how can it be an IOMMU
problem? The CPU/memory interface is all on the MBus side, right?
On the other hand, I've been totally unable to explain this as anything
but an IOMMU effect. As you can see in the code, I've located the PTE
entry for the page, verified that it stays the same throughout, made it
invalid during the printk's (hoping to trigger a kernel fault, but no
luck), and run through the entire MMU table looking for a duplicate
entry. So there's no way I can think of that the CPU is doing this!
Any luck reproducing it?
I hope it's not something too stupid, like some broken file CVS didn't
update. On that note, what's happening with bitminder?
--
-bwb
Brent Baccala
[EMAIL PROTECTED]
-------------------------------------------------------------------------
To receive periodic news about what's happening at freesoft.org, send
email to "[EMAIL PROTECTED]", with "SUBSCRIBE" as the message, i.e:
echo SUBSCRIBE | mail [EMAIL PROTECTED]
-------------------------------------------------------------------------
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/pgtable.h>
/* Compile with:
*
* gcc -D__KERNEL__ -I/usr/src/linux-devel-new/include -Wall
* -Wstrict-prototypes -g -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
* -DMODULE -c -o exploit.o exploit.c
*
* Expected output is a list of 16 address:number pairs, where the numbers
* range from 10 to 1f (hex).
*
* On my SS20, SuperSparc 50 CPU, TI Viking MMU, the first number is correct
* (because the memory was examined before the first printk), and all
* the rest of the numbers are zero.
*
* It doesn't appear to be a caching problem. I've put flush_cache_all's
* at all the places indicated by comments, to no avail.
*/
int scan_ptd_for_duplicate_pte(pgd_t pgd, pte_t original_pte)
{
int j;
if ((pgd & 3 == 2) && (pgd & 0xfffffff0 == original_pte & 0xfffffff0)) return
pgd;
else if (pgd & 3 == 1) {
pmd_t *pmd = 0xf000000 + ((pgd & 0xfffffffc) << 4);
for (j=0; j<64; j++) {
scan_ptd_for_duplicate_pte(pmd[j], original_pte);
}
}
return 0;
}
int scan_for_duplicate_pte(pte_t original_pte)
{
pgd_t *pgd;
int i, j, k;
pgd = init_task.mm->pgd;
for (i=0; i<256; i++) {
int result = scan_ptd_for_duplicate_pte(pgd[i], original_pte);
if (result) return result;
}
return 0;
}
int init_module(void)
{
int *dma_area;
__u32 dvma_addr;
int i;
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
int duplicate_pte;
/* flush_cache_all(); */
dma_area = sparc_dvma_malloc(16 * sizeof(int),
"DMA test area", &dvma_addr);
pgd = pgd_offset(init_task.mm, dma_area);
pmd = pmd_offset(pgd, dma_area);
pte = pte_offset(pmd, dma_area);
duplicate_pte = scan_for_duplicate_pte(*((int *)pte));
/* flush_cache_all(); */
for (i=0; i<16; i++) dma_area[i] = mmu_v2p(dma_area+i);
/* flush_cache_all(); */
for (i=0; i<16; i++) {
int value = dma_area[i];
int pte_value = *((int *)pte);
set_pte(pte, pte_value & ~3);
printk("DMA test: %08x:%08x\n", dma_area+i, value);
set_pte(pte, pte_value);
}
printk("duplicate_pte = %08x\n", duplicate_pte);
printk("pgd = %08x:%08x\n", (int)pgd, *((int *)pgd));
printk("pmd = %08x:%08x\n", (int)pmd, *((int *)pmd));
printk("pte = %08x:%08x\n", (int)pte, *((int *)pte));
printk("duplicate_pte = %08x\n", scan_for_duplicate_pte(*((int *)pte)));
pgd = pgd_offset(init_task.mm, dma_area);
pmd = pmd_offset(pgd, dma_area);
pte = pte_offset(pmd, dma_area);
printk("pgd = %08x:%08x\n", (int)pgd, *((int *)pgd));
printk("pmd = %08x:%08x\n", (int)pmd, *((int *)pmd));
printk("pte = %08x:%08x\n", (int)pte, *((int *)pte));
/* flush_cache_all(); */
for (i=0; i<16; i++) dma_area[i] = 16+i;
/* flush_cache_all(); */
for (i=0; i<16; i++)
printk("DMA test: %08x:%08x\n", dma_area+i, dma_area[i]);
pgd = pgd_offset(init_task.mm, dma_area);
pmd = pmd_offset(pgd, dma_area);
pte = pte_offset(pmd, dma_area);
printk("pgd = %08x:%08x\n", (int)pgd, *((int *)pgd));
printk("pmd = %08x:%08x\n", (int)pmd, *((int *)pmd));
printk("pte = %08x:%08x\n", (int)pte, *((int *)pte));
release_region(dma_area, 16 * sizeof(int));
return -EIO;
}
void cleanup_module(void)
{
}