You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
2.5 KiB
C

/* Copyright (C) 2021 fef <owo@fef.moe>. All rights reserved. */
#pragma once
#include <arch/page.h>
#include <gay/cdefs.h>
#include <gay/systm.h>
#include <gay/types.h>
/**
* @brief Stores information about a single page in physical memory.
* There is exactly one of these for every physical page, no matter what that
* page is used for or whether it is usable at all.
*/
struct vm_page {
/** @brief Reference count (0 = unused) */
atom_t count;
/** @brief Various flags describing how and for what the page is used, see below */
u_int flags;
/** @brief Singly linked list, if the page is free */
patom_t next;
/**
* @brief Request this page to be freed if possible.
* This callback may be `nil` unless the `PG_FREEABLE` bit in `flags`
* is set. The presence of this bit does *not* guarantee that the page
* is actually reclaimable, it's merely a performance optimization to
* avoid having to call this function on pages that can never be
* reclaimed anyway.
*
* @param page Pointer to the page itself
* @return 0 if the page could be reclaimed and is now free
*/
int (*try_free)(struct vm_page *page);
/**
* @brief Optional extra data pointer, reserved for private use.
* The current owner of the page may use this to track the underlying
* object in memory (or pretty much anything else), for example the
* `struct slab` if this page is currently used by the slab allocator.
* Useful for implementing the `try_free()` callback.
*/
void *extra;
};
typedef struct vm_page *vm_page_t;
/* values for struct page::flags */
/** @brief Page must never be accessed */
#define PG_RESERVED (1 << 0)
/** @brief Page is in an atomic per-cpu cache */
#define PG_ATOMIC (1 << 1)
/** @brief Page is used by the slab allocator */
#define PG_SLAB (1 << 2)
/** @brief It **might** be possible to reclaim this page using `try_free()` */
#define PG_FREEABLE (1 << 3)
/** @brief Array of every single page in physical memory, indexed by page frame number. */
extern struct vm_page *const vm_page_array;
#ifdef DEBUG
extern vm_page_t _vm_page_array_end;
#endif
/** @brief Get the page frame number of a page. */
__pure2 static inline u_long pg2pfn(vm_page_t page)
{
KASSERT(page < _vm_page_array_end);
return page - vm_page_array;
}
__pure2 static inline u_long paddr2pfn(vm_paddr_t paddr)
{
KASSERT(&vm_page_array[paddr >> PAGE_SHIFT] < _vm_page_array_end);
return paddr >> PAGE_SHIFT;
}
__pure2 static inline vm_page_t paddr2pg(vm_paddr_t paddr)
{
vm_page_t page = vm_page_array + (paddr >> PAGE_SHIFT);
KASSERT(page < _vm_page_array_end);
return page;
}