Working of mmap() - memory-management

I am trying to get an idea on how does memory mapping take place using the system call mmap.
So far I know mmap takes arguments from the user and returns a logical address of where the file is stored. When the user tries to access it takes this address to the map table converts it to a a physical address and carries the operation as requested.
However I found articles as code example and Theoretical explanation
What it mentions is the memory mapping is carried out as:
A. Using system call mmap ()
B. file operations using (struct file *filp, struct vm_area_struct *vma)
What I am trying to figure out is:
How the arguments passed in the mmap system call are used in the struct vm_area_struct *vma) More generally how are these 2 related.
for instance: the struct vm_area_struct has arguments such as starting address, ending address permissions,etc. How are the values sent by the user used to fill values of these variables.
I am trying to write a driver so, Does the kernal fill the values for variables in the structure for us and I simply use it to call and pass values to remap_pfn_range
And a more fundamental question, why is a different file systems operation needed. The fact that mmap returns the virtual address means that it has already achieved a mapping doesnt it ?
Finally I am not that clear about how the entire process would work in user as well as kernal space. Any documentation explaining the process in details would be helpful.

Related

How do I create an instance of a class, variably sized, at a specific memory location?

I'm working on a project involving writing packets to a memory-mapped file. Our current strategy is to create a packet class containing the following members
uint32_t packetHeader;
uint8_t packetPayload[];
uint32_t packetChecksum;
When we create a packet, first we'd like to have its address in memory be a specified offset within the memory mapped file, which I think can be done with placement-new(). However, we'd also like for the packetPayload not to be a pointer to some memory from the heap, but contiguous with the rest of the class (so we can avoid memcpying from heap to our eventual output file)
i.e.
Memory
Beginning of class | BOC + 4 | (length of Payload) |
Header Payload Checksum
Would this be achievable using a length argument for the Packet class constructor? Or would we have to template this class for variably sized payloads?
Forget about trying to make that the layout of your class. You'll be fighting against the C++ language all the day long. Instead a class that provides access to the binary layout (in shared memory). But the class instance itself will not be in shared memory. And the byte range in shared/mapped memory will not be a C++ object at all, it just exists within the file mapping address range.
Presumably the length is fixed from the moment of creation? If so, then you can safely cache the length, pointer to the checksum, etc in your accessor object. Since this cache isn't inside the file, you can store whatever you want however you want without concern for its layout. You can even use virtual member functions, because the v-table is going in the class instance, not the range of the binary file.
Also, given that this lives in shared memory, if there are multiple writers you'll have to be very careful to synchronize between them. If you're just prepositioning a buffer in shared/mapped memory to avoid a copy later, but totally handing off ownership between processes so that the data is never shared by simultaneous accesses, it will be easier. You also probably want to calculate the checksum once after all the data is written, instead of trying to keep it up-to-date (and risking data races in the process) for every single write into the buffer.
First remember, that you need to know what your payload length is, somehow. Either you specify it in your instance somewhere, or you template your class over the payload length.
Having said that - you will need one of:
packetOffset being a pointer
A payload length member
A checksum offset member
and you'll want to use a named constructor idiom which takes the allocation length, and performs both the allocation and the setup of the offset/length/pointer member to a value corresponding to the length.

How to translate a delegate to absolute address in DRAM?

I'd like to translate the delegate members .ptr and .funcptr to an absolute address that matches something in the executable image in DRAM.
The goal is not to call, neither to modify, but rather to allow the target to disassemble itself at run-time, when its own image is loaded in DRAM.
So far it already works with global functions.
Is it possible ?
The address of a delegate is the value of the .funcptr property. The type of this property is a bit misleading - it is of type function and does not list the hidden argument that is actually expected for passing the context in, but for just getting the address, you can ignore the type (explicitly casting to void* or size_t if you like to change the type) and just look at the address.
This isn't the address in physical memory, you'd have to ask the operating system for that, but since the virtual address it gives is automatically translated by the processor, it is most likely what you want anyway.

How device name is copied in ip_rt_ioctl in fib_frontend.c

I have one doubt in ip_rt_ioctl function
In case of route addition, first a copy_from_user is made for the structure struct rtentry and then the copied data from is subsequently used in rtentry_to_fib_config function, including the rtentry.rt_dev field which usually is the device name.
My understanding is copy_from_user does a shallow copy. So since the rtentry.rt_dev field is again a character pointer. So likely the contents of the pointer will not get copied.
Hence even after copy the device name will be pointer to the user space address.
So is it right to access the user space address from kernel space ?
It's OK to refer to user-space address from kernel-space while kernel is bound to that process' context (this is true for syscall handlers). In that case, proper page table is set and it's safe to refer to user process' memory.
However, you should always check validity of address or use copy_from_user() that does that.

Accessing user space data from linux kernel

This is an assignment problem which asks for partial implementation of process checkpointing:
The test program allocates an array, does a system call and passes the start and end address of array to the call. In the system call function I have to save the contents in the give range to a file.
From my understanding, I could simply use copy_from_usr function to save the contents from the give range. However since the assignment is based on topic "Process address space", I probably need to walk through page tables. Say I manage to get the struct pages that correspond to given range. How do I get the data corresponding to the pages?
Can I just use page_to_virt function and access data directly?
Since the array is contiguous in virtual space, I guess I will just need to translate the starting address to page and then back to virtual address and then just copy the range size of data to file. Is that right?
I think copy_from_user() is ok, nothing else needed. When executing the system call, although it trap to kernel space, the context is still the process context which doing the system call. The kernel still use the process's page table. So just to use copy_from_user(), and nothing else needed.
Okey, if you want to do this experiment, I think you can use the void __user *vaddr to traverse the mm->pgd(page table), using pgd_offset/pud_offset/pmd_offset/pte_offset to get the page physical address(page size alignment). Then in kernel space, using ioremap() to create a kernel space mapping, then using the kernel virtual address(page size) + offset(inside the page), you get the start virtual address of the array. Now in kernel, you can using the virtual address to access the array.

User space access from Kernel space - get_user_pages

I'd like pass a pointer from a user space memory into a function in my kernel module. I don't want to use copy_from_user. I've read that I should use get_user_pages function.
For example one page.
struct page **pages;
pages = kmalloc(1 * sizeof(*pages), GFP_KERNEL);
down_read(&current->mm->mmap_sem);
get_user_pages(current,current->mm,uaddr, 1, 1, 0,pages,NULL);
up_read(&current->mm->mmap_sem);
uaddr is an address in User Space.
After doing this, am I allowed to cast and pass uaddr into my kernel module function? Or maybe I have to use these struct pages in some way?
Why do I have to use down/up read?
After everything do I have to use SetPageDirty() and page_cache_release() functions ?
No, you cannot directly access the userspace pages via uaddr. The struct pages are filled out to allow the kernel to access the physical pages that correspond to the userspace pages. Note also that they are most unlikely to be contiguous, so one must be careful to use the correct page index into the array from the start of the uaddr.
You are changing the page mapping structures for this process, so need to protect them while the page mapping in the kernel is set up.
When you are done with the mappings that were setup by get_user_pages(), you must 'release' them by the referenced functions.
This is not what get_user_pages is for (and no - you can't then just cast and pass uaddr into your kernel module function).
If you don't want to call copy_from_user in the calling function, then just pass a void __user * to your module function and have it do the copy_from_user.
You can only use the user pages for page type activity, for example setting up Scatter/Gather DMA into userspace memory. You cannot use it to directly access user space from kernel mode code. Hence the copy_to/from functions that are there for that reason. Unless your moving large amounts of data why not use these functions?
Once you get the valid user space address, use get_user_pages to get the struct page pointer. once struct page pointer received , to access it in the kernel mode you have to map it to kernel virtual address by using kmap. hope that helps

Resources