Virtual Memory

Memory Problems:

  • Not enough RAM.
    • As per Address line, a program can access any bye in their 32-bit address space. in case of the 1GB physical memory. what if the program is trying the access more than 1GB memory area access?  the progress will crash.  
  • Holes in our Address space.
  • Programs writing over each other on the same address space.


How we do we solve this:

  • key to problem "same Memory space".
  • can we give each its own virtual memory space?
  • if so we can:
    • separately map each programs memory space to the RAM memory space.
    • and even move it to disk if we run out of Memory.

Virtual Memory:

        In computing, virtual memory, or virtual storage is a memory management technique that provides an "idealized abstraction of the storage resources that are actually available on a given machine" which "creates the illusion to users of a very large (main) memory".





Address Translation and MMU :

  • The mechanism to convert the virtual Address to Physical Address.
  • This activity is done by the MMU. 
  • Page table is introduced on Manage page (fixed size chunk in virtual Memory) and Frame (Fixed size of the chunk in physical Memory).
  • Each page is given a number, called a page number
  • Each frame is given a number, called a page frame number (PFN)

    Virtual Memory addressed composed two parts:
page number(20 bit) and offset (12 bit)

  • Os first extracts the offset and virtual page number from the virtual address then walks through the
  • Process page table in order to match virtual page number to physical Page Frame Number (PFN).
  • Offset is used to point to right location into the frame. 
  • The Page table not only holds mapping b/w physical and virtual page number. but also access control information(read/write access )




How we provide the separate mapping :



Virtual Memory real-world Problem:

  • VM is Greate 
    • unlimited programs/Memory, protection flexibility etc 
  • But it comes is high cost:
    • Every Memory operation has to lookup in the page table.
    • Need to access 1) Page table 
      and 2) the Memory address (2x Memory access ).
  • Fortunately, SoC manufacturers worked hard to find a clever trick to address this performance issue: modern CPUs use a small associative and very fast memory called translation lookaside buffer (TLB), 
  • that means heard ware page table cache.  

TLB example  and understanding


One issue with Page table:

  • For 32-bit Machine with 4kb pages we need:
    • 1M page table entries ( 32 bit - 12 bit for page offset = 20bits, 2^20= 1M )
    • Each PTE is about 4 bytes (20 bit for phy page + permission bit).
    • 4MB in total. 
  • Not bad...
    • except each program needs its own page table...
      • if we have 100 programs running, we need 400MB of page table 😔
  • and here's the tough part:
    • we can't swap the page tables out to disk. 
    • if the page table is not RAM, we have no way to access it to find it. 
  • How can we fix this?

solution:  Level Paging. 




system Memory Layout -Kernel space and Userspace :

  • on the Linux, each process owns a virtual address space. (like sandboxing)
  • Address space of 4GB on a 32-bit system. 
  • this 4GB address space split into:
    • user-space virtual address.
    • kernel-space virtual address.
  • split is based on the CONFIG_PAGE_OFFSET (ARM: 0xC0000000 )


The reason why kernel shares its address with every process:

  • Every single process at a given moment uses the system calls, which will invoke kernel space.
  • Mapping the kernel's virtual memory address into each process's virtual address space allows us
    • avoid the cost of switching out the memory address space on each entry to (and exit from)
      the kernel.


Kernel addresses - Concept of the Low Memory and High Memory.  

  • Low memory
    • which is the first 896 MB
    • Early in the boot, the kernel permanently maps this 896 MB.
    • also called a logical address. 
  • High memory. 
    • Top 128 MB in kernel space:
    • temporarily map physical memory above 1 GB
    • The physical memory above 896 MB is mapped on demand to the 128 MB of
      the HIGHMEM region.

    • Mapping to access high memory is created on the fly by the kernel and destroyed when
      done.

  • Memory zones in Kernel space:
    • ZONE_DMA:
      • This contains page frames of memory below 16 MB, reserved for Direct Memory Access (DMA)
    • ZONE_LOW:
      • This contains page frames of memory above 16 MB and below 896 MB, for normal use
    • ZONE_HIGH:
      • This contains page frames of memory at and above 896 MB

User space addresses - 

  • Each process is represented in the kernel as an instance of struct task_struct,   (see include/linux/sched.h)
  • Memory-mapped of the given process present at  struct mm_struct (see include/linux/mm_types.h).
  • From the process point of view, memory mapping can be seen as nothing but a set of page
    table entries dedicated to a consecutive virtual address range. 
  • That consecutive virtual address range is called the memory area, or virtual memory area (VMA).
  • Each memory mapping is described by a start address and length, permissions (such as whether the program can read, write, or execute from that memory), and associated resources (such as
    physical pages, swap pages, file contents, and so on)
  • vm_area_struct  

Virtual Memory Area- 

  • Kernel uses virtual memory areas to keep track of the process's memory mappings
  • each process has one VMA for Data section, one for code section ... 

  • Each line in the preceding excerpt represents a VMA, and the fields map the following pattern: {address (start-end)} {permissions} {offset} {device (major:minor)} {inode} {pathname (image)} (major:minor)} {inode} {pathname (image)}:



Memory allocation Mechanism:


  • page allocator (Buddy system) which only works with pages (a page being the smallest memory unit
    it can deliver). 

  • SLAB allocator which is built on top of the page allocator, getting pages from it and returning smaller memory entities (by mean of slabs and caches).
  • kmalloc allocator relies on slab allocator 

Page allocator 

  • is the lowest level allocator on the Linux system,
  • The system's physical memory is made up of fixed-size blocks (called page frames).
  • A page frame is represented in the kernel as an instance of the struct page structure.    

Page allocation API:

  • Allocation and deallocation are happed on the Buddy algorithm. 
  • Pages are allocated in blocks that are powers of 2 (1page,2 pages,4page,6 pages).
    • struct page *alloc_pages(gfp_t mask, unsigned int order)
    • void __free_pages(struct page *page, unsigned int order);
  • below API will return located address (virtual address of course)
    • unsigned long __get_free_pages(gfp_t mask, unsigned int order);
    • free_pages(unsigned long addr, unsigned int order);
      • Mask:
        • GFP_USER: For user memory allocation.
        • GFP_KERNEL: The commonly used flag for kernel allocation.
        • GFP_HIGHMEM: Requests memory from the HIGH_MEM zone.
        • GFP_ATOMIC: Allocates memory in an atomic manner that cannot sleep.
  • Conversatio API 
    • struct page *virt_to_page(void *kaddr);
    • void *page_to_virt(struct page *pg)

Buddy alogoridhma:

  • Adv : coalescing (combined two holes inorder to produce the larger holes)
  • dis adv : internal framentation 
    



Kmalloc
  • kernal memory allocation function
  • kmalloc returns contiguous physical Memory and in virtual Memory.
  • void *Kmalloc (size_t size,  int flags);
    • size in bytes 
    • flags
      • GFP_KERNEL: standard flag, always allocate memory in low_mem
      • GFP_ATOMIC: only flag we can use in interrupt context. 
      • GFP_USER :  This allocates memory to a user space process. Memory is then
        distinct and separated from that allocated to the kernel

      • GFP_HIGHUSER: allocates memory from the HIGH_MEMORY zone
      • GFP_DMA:  allocates memory from the DMA zone
    • on successful allocation of memroy return virtual address of chunk allocated. 
    • k_free to release the allocated memory
Let's see an example:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mm.h>
MODULE_LICENSE("GPL");
void *ptr;
static int
alloc_init(void)
{
size_t size = 1024; /* allocate 1024 bytes */
ptr = kmalloc(size,GFP_KERNEL);
if(!ptr) {
/* handle error */
pr_err("memory allocation failed\n");
return -ENOMEM;
}
else
pr_info("Memory allocated successfully\n");
return 0;
}
static void alloc_exit(void)
{
kfree(ptr);
pr_info("Memory freed\n");
}
module_init(alloc_init);
module_exit(alloc_exit);

vmalloc

  • Return memory only contiguous in virtual space.
  • Returned Memory always comes from thehigh memory zone. 
  • addressed returned can't be translated in to phy onces or into bus address, because your can't assert that memory in phy contiguous. 
  • that means vmalloc  to can't be used for outside microprocessor (can' use for DMA purpose).
  • vmalloc is slower than kmalloc.
#include<linux/init.h>
#include<linux/module.h>
#include <linux/vmalloc.h>
void *ptr;
static int my_vmalloc_init(void)
{
unsigned long size = 8192;
ptr = vmalloc(size);
if(!ptr)
{
/* handle error */
printk("memory allocation failed\n");
return -ENOMEM;
}
else
pr_info("Memory allocated successfully\n");
return 0;
}
static void my_vmalloc_exit(void) /* function called at the time of rmmod */
{
vfree(ptr); //free the allocated memory
printk("Memory freed\n");
}
module_init(my_vmalloc_init);
module_exit(my_vmalloc_exit

Working with I/O memory to talk with hardware

  • Apart from performing data RAM-oriented operations, you can perform I/O memory
    transactions to talk with the hardware.

  • When it comes to the access device's register, the kernel offers two possibilities depending on the system architecture:
    • Port Mapped I/O:
      • struct resource *request_region(unsigned long start, unsigned long len, char *name); 
      • void release_region(unsigned long start, unsigned long len);
      • /proc/ioports
    • Memory-mapped I/O:
      • struct resource* request_mem_region(unsigned long start, unsigned long len, char *name)
      • void release_mem_region(unsigned long start, unsigned long len)
      • /proc/iomem

Reference Source :


source:

Comments

Popular posts from this blog

Cryptography and Encryption Basics - I

Overview of ISO/SAE 21434 Standard

UDS Protocol Interview Question