blob: 7c0f684ce1105ead01cb7d276c3b17bb65457141 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2014 Travis Geiselbrecht
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_VM_INCLUDE_VM_PAGE_H_
#define ZIRCON_KERNEL_VM_INCLUDE_VM_PAGE_H_
#include <stdint.h>
#include <sys/types.h>
#include <zircon/compiler.h>
#include <zircon/listnode.h>
#include <vm/page_state.h>
// core per page structure allocated at pmm arena creation time
typedef struct vm_page {
struct list_node queue_node;
paddr_t paddr_priv; // use paddr() accessor
// offset 0x18
union {
struct {
// This is an optional back pointer to the vm object this page is currently contained in. It
// is implicitly valid when the page is in the pager_backed page queue, and not valid
// otherwise. Consequently, to prevent data races, this should not be modified (except under
// the page queue lock) whilst a page is in a page queue.
// Field should be modified by the setters and getters to allow for future encoding changes.
void* object_priv;
// When object is valid, this is the offset in the vmo that contains this page.
// Field should be modified by the setters and getters to allow for future encoding changes.
uint64_t page_offset_priv;
void* get_object() { return object_priv; }
void set_object(void* object) { object_priv = object; }
uint64_t get_page_offset() { return page_offset_priv; }
void set_page_offset(uint64_t page_offset) { page_offset_priv = page_offset; }
#define VM_PAGE_OBJECT_PIN_COUNT_BITS 5
#define VM_PAGE_OBJECT_MAX_PIN_COUNT ((1ul << VM_PAGE_OBJECT_PIN_COUNT_BITS) - 1)
uint8_t pin_count : VM_PAGE_OBJECT_PIN_COUNT_BITS;
// Bits used by VmObjectPaged implementation of COW clones.
//
// Pages of VmObjectPaged have two "split" bits. These bits are used to track which
// pages in children of hidden VMOs have diverged from their parent. There are two
// bits, left and right, one for each child. In a hidden parent, a 1 split bit means
// that page in the child has diverged from the parent and the parent's page is
// no longer accessible to that child.
//
// It should never be the case that both split bits are set, as the page should
// be moved into the child instead of setting the second bit.
uint8_t cow_left_split : 1;
uint8_t cow_right_split : 1;
// This struct has no type name and exists inside an unpacked parent and so it really doesn't
// need to have any padding. By making it packed we allow the next outer variables, to use
// space we would have otherwise wasted in padding, without breaking alignment rules.
} __PACKED object; // attached to a vm object
};
// offset 0x29
struct {
uint8_t flags;
// logically private; use |state()| and |set_state()|
uint8_t state_priv : VM_PAGE_STATE_BITS;
};
// offset 0x2b
// five bytes of padding would be inserted here to make sizeof(vm_page) a multiple of 8
// explicit padding is added to validate all commented offsets were indeed correct.
char padding[5];
// helper routines
bool is_free() const { return state_priv == VM_PAGE_STATE_FREE; }
void dump() const;
// return the physical address
// future plan to store in a compressed form
paddr_t paddr() const { return paddr_priv; }
vm_page_state state() const { return vm_page_state(state_priv); }
void set_state(vm_page_state new_state);
// Return the approximate number of pages in state |state|.
//
// When called concurrently with |set_state|, the count may be off by a small amount.
static uint64_t get_count(vm_page_state state);
// Add |n| to the count of pages in state |state|.
//
// Should be used when first constructing pages.
static void add_to_initial_count(vm_page_state state, uint64_t n);
} vm_page_t;
// assert that the page structure isn't growing uncontrollably
static_assert(sizeof(vm_page) == 0x30, "");
// helpers
const char* page_state_to_string(unsigned int state);
#endif // ZIRCON_KERNEL_VM_INCLUDE_VM_PAGE_H_