• Suraj Jitindar Singh's avatar
    KVM: PPC: Book3S HV: Introduce rmap to track nested guest mappings · 8cf531ed
    Suraj Jitindar Singh authored
    When a host (L0) page which is mapped into a (L1) guest is in turn
    mapped through to a nested (L2) guest we keep a reverse mapping (rmap)
    so that these mappings can be retrieved later.
    
    Whenever we create an entry in a shadow_pgtable for a nested guest we
    create a corresponding rmap entry and add it to the list for the
    L1 guest memslot at the index of the L1 guest page it maps. This means
    at the L1 guest memslot we end up with lists of rmaps.
    
    When we are notified of a host page being invalidated which has been
    mapped through to a (L1) guest, we can then walk the rmap list for that
    guest page, and find and invalidate all of the corresponding
    shadow_pgtable entries.
    
    In order to reduce memory consumption, we compress the information for
    each rmap entry down to 52 bits -- 12 bits for the LPID and 40 bits
    for the guest real page frame number -- which will fit in a single
    unsigned long.  To avoid a scenario where a guest can trigger
    unbounded memory allocations, we scan the list when adding an entry to
    see if there is already an entry with the contents we need.  This can
    occur, because we don't ever remove entries from the middle of a list.
    
    A struct nested guest rmap is a list pointer and an rmap entry;
    ----------------
    | next pointer |
    ----------------
    | rmap entry   |
    ----------------
    
    Thus the rmap pointer for each guest frame number in the memslot can be
    either NULL, a single entry, or a pointer to a list of nested rmap entries.
    
    gfn	 memslot rmap array
     	-------------------------
     0	| NULL			|	(no rmap entry)
     	-------------------------
     1	| single rmap entry	|	(rmap entry with low bit set)
     	-------------------------
     2	| list head pointer	|	(list of rmap entries)
     	-------------------------
    
    The final entry always has the lowest bit set and is stored in the next
    pointer of the last list entry, or as a single rmap entry.
    With a list of rmap entries looking like;
    
    -----------------	-----------------	-------------------------
    | list head ptr	| ----> | next pointer	| ---->	| single rmap entry	|
    -----------------	-----------------	-------------------------
    			| rmap entry	|	| rmap entry		|
    			-----------------	-------------------------
    Signed-off-by: default avatarSuraj Jitindar Singh <sjitindarsingh@gmail.com>
    Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
    Reviewed-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
    8cf531ed
book3s_hv.c 136 KB