Re: Process VM Addr to Kernel VM Addr at Interrupt Time.

Greg Johnson (gjohnson@research.canon.com.au)
Tue, 11 May 1999 10:03:43 +1000 (EST)


Regarding a post I made over a week ago, here is the solution that
I used, for anyone that is interrested.

I also have a question at the end for people in the know.

My solution is this. I have the advatage with my particular problem, that
all the data structures that are referenced by the user space pointers
are garenteed (by the user application) to be so aligned that they
do not cross page boundaries. In addition, the size of the data is small,
8 words for one structure and 2 words for the other. This means that
I do not have to deal with non-contigeous pages in the kernels address
space. Phew!

This code is used to provide the conversion from user to kernel space.
There is nothing special about this code, the concepts are covered
in Rubini and it is used in the udma patch.

The only tricky bit here is that mm needs to be a pointer to
the struct mm_struct. Of the application in question. The ISR would
need to know this somehow. In my case, the driver keeps a pointer to
the struct task_struct of the process currently using the card, and
as such can find out the struct mm struct.

--

#include <linux/sched.h> #include <asm/page.h> #include <asm/pgtable.h>

...

pgd_t *pgd; /* Page Directory */ pmd_t *pmd; /* Page Midlevel Directory */ pte_t *pte; /* Page Table Entry */ addr_t page_addr; /* Base address of a page of memory */ addr_t addr_offset; /* Offset into a page of memory */ addr_t k_addr; /* Kernel address (base + offset) */

/* * Work through the 3 levels of page tables. */ pgd = pgd_offset(mm, u_addr); pmd = pmd_offset(pgd, u_addr); pte = pte_offset(pmd, u_addr);

/* * Check if the actual page is in memory first. Should be locked down * already so should never fail. */ if (!pte_present(*pte)) return 0;

/* * Get the base address of the page of physical memory that the * user address maps to. This is the address within the kernels * semi-virtual address, that is in Linux 2.2.x it will be different * to the wire level address. In Linux 2.0.x is is the same however. * NOTE: Check this when porting to Linux 2.2.x. */ page_addr = pte_page(*pte);

/* * Calculate the offset of the virtual address within a page of memory. */ addr_offset = u_addr & (PAGE_SIZE - 1);

/* * Add the offset to the kernel page address. */ k_addr = page_addr + addr_offset;

return k_addr;

--

There is one bit of uncertanty I have here. This code does not take in to account the PAGE_OFFSET for kernel addresses, this does not matter with 2.0.x kernels since the offset is 0, but it may matter in 2.2.x kernels.

QUESTION:

If someone could clarify this point I would appreciate it.

My understanding is that kernel addresses are in fact virtual, ie addresses returned from vmalloc and friends. These addresses are different from the actual hardware/wire-level addresses and the user virtual addresses. In the case of pte_page above, does it return a kernel virtual address or a hardware/wire-level address? Also, does kmalloc return a kernel virtual address or hardware/wire-level address?

This is of some concern since in the code I have seen, ~PAGE_OFFSET is anded with the result of pte_page, it would seem to me (but I am unsure) that this would have the effect of masking some high order bits of the value returned from pte_page to resolve a kernel virtual address to a hardware/wire-level address (in Linux 2.2.x). Is this the intension?

Regards.

Greg.

-- 
+----------------------------------------------------+
| Do you want to know more?                          |
|               --== Greg Johnson ==--               |
| HW/SW Engineer      gjohnson@research.canon.com.au |
| Canon   Information  Systems   Research  Australia |
| 1 Thomas Holt Dr, North Ryde, NSW, 2113, Australia |
| "I FLEXed my BISON and it went YACC!" - me.        |
+----------------------------------------------------+

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/