150baef55SAxel Dörfler/*
23cd20943SIngo Weinhold * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
39b912c69SAxel Dörfler * Copyright 2002-2009, Axel D��rfler, axeld@pinc-software.de.
44eaf08abSAxel Dörfler * Distributed under the terms of the MIT License.
54eaf08abSAxel Dörfler *
64eaf08abSAxel Dörfler * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
74eaf08abSAxel Dörfler * Distributed under the terms of the NewOS License.
84eaf08abSAxel Dörfler */
9e50cf876SIngo Weinhold#ifndef _KERNEL_VM_VM_TYPES_H
10e50cf876SIngo Weinhold#define _KERNEL_VM_VM_TYPES_H
11085320eaSAxel Dörfler
12841093cfSAxel Dörfler
13b9447668SIngo Weinhold#include <new>
14b9447668SIngo Weinhold
1590c6930eSMichael Lotz#include <AllocationTracking.h>
167c0a9357SAxel Dörfler#include <arch/vm_types.h>
17393fceb5SAxel Dörfler#include <condition_variable.h>
18393fceb5SAxel Dörfler#include <kernel.h>
195c99d639SIngo Weinhold#include <lock.h>
205800e8a4SIngo Weinhold#include <util/DoublyLinkedList.h>
21ca954b78SAxel Dörfler#include <util/DoublyLinkedQueue.h>
229b912c69SAxel Dörfler#include <util/SplayTree.h>
23ca954b78SAxel Dörfler
24ca954b78SAxel Dörfler#include <sys/uio.h>
25ca954b78SAxel Dörfler
26e43cb37bSIngo Weinhold#include "kernel_debug_config.h"
27ca954b78SAxel Dörfler
28c53e844aSIngo Weinhold
2990c6930eSMichael Lotz#define VM_PAGE_ALLOCATION_TRACKING_AVAILABLE \
3090c6930eSMichael Lotz	(VM_PAGE_ALLOCATION_TRACKING && PAGE_ALLOCATION_TRACING != 0 \
3190c6930eSMichael Lotz		&& PAGE_ALLOCATION_TRACING_STACK_TRACE > 0)
3290c6930eSMichael Lotz
3390c6930eSMichael Lotz
342a79a768SIngo Weinholdclass AsyncIOCallback;
35ca954b78SAxel Dörflerstruct vm_page_mapping;
365c99d639SIngo Weinholdstruct VMCache;
376379e53eSIngo Weinholdstruct VMCacheRef;
38ca954b78SAxel Dörflertypedef DoublyLinkedListLink<vm_page_mapping> vm_page_mapping_link;
39ca954b78SAxel Dörfler
409b912c69SAxel Dörfler
41a8ad734fSIngo Weinholdstruct virtual_address_restrictions {
42a8ad734fSIngo Weinhold	void*	address;
43a8ad734fSIngo Weinhold				// base or exact address, depending on address_specification
44a8ad734fSIngo Weinhold	uint32	address_specification;
45a8ad734fSIngo Weinhold				// address specification as passed to create_area()
46a8ad734fSIngo Weinhold	size_t	alignment;
47a8ad734fSIngo Weinhold				// address alignment; overridden when
48a8ad734fSIngo Weinhold				// address_specification == B_ANY_KERNEL_BLOCK_ADDRESS
49a8ad734fSIngo Weinhold};
50a8ad734fSIngo Weinhold
51a8ad734fSIngo Weinholdstruct physical_address_restrictions {
52a8ad734fSIngo Weinhold	phys_addr_t	low_address;
53a8ad734fSIngo Weinhold					// lowest acceptable address
54a8ad734fSIngo Weinhold	phys_addr_t	high_address;
55a8ad734fSIngo Weinhold					// lowest no longer acceptable address; for ranges: the
56a8ad734fSIngo Weinhold					// highest acceptable non-inclusive end address
57a8ad734fSIngo Weinhold	phys_size_t	alignment;
58a8ad734fSIngo Weinhold					// address alignment
59a8ad734fSIngo Weinhold	phys_size_t	boundary;
60a8ad734fSIngo Weinhold					// multiples of which may not be crossed by the address
61a8ad734fSIngo Weinhold					// range
62a8ad734fSIngo Weinhold};
63a8ad734fSIngo Weinhold
64a8ad734fSIngo Weinhold
65ca954b78SAxel Dörflertypedef struct vm_page_mapping {
66ca954b78SAxel Dörfler	vm_page_mapping_link page_link;
67ca954b78SAxel Dörfler	vm_page_mapping_link area_link;
68ca954b78SAxel Dörfler	struct vm_page *page;
69a99eb6b5SIngo Weinhold	struct VMArea *area;
70ca954b78SAxel Dörfler} vm_page_mapping;
71ca954b78SAxel Dörfler
72ca954b78SAxel Dörflerclass DoublyLinkedPageLink {
73ca954b78SAxel Dörfler	public:
74ca954b78SAxel Dörfler		inline vm_page_mapping_link *operator()(vm_page_mapping *element) const
75ca954b78SAxel Dörfler		{
76ca954b78SAxel Dörfler			return &element->page_link;
77ca954b78SAxel Dörfler		}
78ca954b78SAxel Dörfler
799b912c69SAxel Dörfler		inline const vm_page_mapping_link *operator()(
809b912c69SAxel Dörfler			const vm_page_mapping *element) const
81ca954b78SAxel Dörfler		{
82ca954b78SAxel Dörfler			return &element->page_link;
83ca954b78SAxel Dörfler		}
84ca954b78SAxel Dörfler};
8552a38012Sejakowatz
86ca954b78SAxel Dörflerclass DoublyLinkedAreaLink {
87ca954b78SAxel Dörfler	public:
88ca954b78SAxel Dörfler		inline vm_page_mapping_link *operator()(vm_page_mapping *element) const
89ca954b78SAxel Dörfler		{
90ca954b78SAxel Dörfler			return &element->area_link;
91ca954b78SAxel Dörfler		}
92ca954b78SAxel Dörfler
939b912c69SAxel Dörfler		inline const vm_page_mapping_link *operator()(
949b912c69SAxel Dörfler			const vm_page_mapping *element) const
95ca954b78SAxel Dörfler		{
96ca954b78SAxel Dörfler			return &element->area_link;
97ca954b78SAxel Dörfler		}
98ca954b78SAxel Dörfler};
99ca954b78SAxel Dörfler
1009b912c69SAxel Dörflertypedef class DoublyLinkedQueue<vm_page_mapping, DoublyLinkedPageLink>
1019b912c69SAxel Dörfler	vm_page_mappings;
1029b912c69SAxel Dörflertypedef class DoublyLinkedQueue<vm_page_mapping, DoublyLinkedAreaLink>
103a99eb6b5SIngo Weinhold	VMAreaMappings;
104841093cfSAxel Dörfler
105147133b7SIngo Weinholdtypedef phys_addr_t page_num_t;
106e1b630c5SIngo Weinhold
1076379e53eSIngo Weinhold
1086379e53eSIngo Weinholdstruct VMCacheRef {
1096379e53eSIngo Weinhold			VMCache*			cache;
1106379e53eSIngo Weinhold			int32				ref_count;
1116379e53eSIngo Weinhold
1126379e53eSIngo Weinhold								VMCacheRef(VMCache* cache);
1136379e53eSIngo Weinhold};
1146379e53eSIngo Weinhold
1156379e53eSIngo Weinhold
116e6dc7903SAxel Dörflerstruct vm_page {
1175800e8a4SIngo Weinhold	DoublyLinkedListLink<vm_page> queue_link;
11852a38012Sejakowatz
119147133b7SIngo Weinhold	page_num_t				physical_page_number;
12052a38012Sejakowatz
1216379e53eSIngo Weinholdprivate:
1226379e53eSIngo Weinhold	VMCacheRef*				cache_ref;
1236379e53eSIngo Weinholdpublic:
1249b912c69SAxel Dörfler	page_num_t				cache_offset;
1259b912c69SAxel Dörfler								// in page size units
126147133b7SIngo Weinhold								// TODO: Only 32 bit on 32 bit platforms!
127147133b7SIngo Weinhold								// Introduce a new 64 bit type page_off_t!
12852a38012Sejakowatz
129e1b630c5SIngo Weinhold	SplayTreeLink<vm_page>	cache_link;
1309b912c69SAxel Dörfler	vm_page*				cache_next;
13152a38012Sejakowatz
1329b912c69SAxel Dörfler	vm_page_mappings		mappings;
133ca954b78SAxel Dörfler
13459dbd26fSIngo Weinhold#if DEBUG_PAGE_QUEUE
1359b912c69SAxel Dörfler	void*					queue;
136d2056c99SIngo Weinhold#endif
13727d37d4dSIngo Weinhold
1383cd20943SIngo Weinhold#if DEBUG_PAGE_ACCESS
13973ad2473SPawel Dziepak	int32					accessing_thread;
1403cd20943SIngo Weinhold#endif
1413cd20943SIngo Weinhold
14290c6930eSMichael Lotz#if VM_PAGE_ALLOCATION_TRACKING_AVAILABLE
14390c6930eSMichael Lotz	AllocationTrackingInfo	allocation_tracking_info;
14490c6930eSMichael Lotz#endif
14590c6930eSMichael Lotz
146bd7645a1SIngo Weinholdprivate:
1479b912c69SAxel Dörfler	uint8					state : 3;
148bd7645a1SIngo Weinholdpublic:
14972382fa6SIngo Weinhold	bool					busy : 1;
1503b8c056dSIngo Weinhold	bool					busy_writing : 1;
151ed436195SIngo Weinhold		// used in VMAnonymousCache::Merge()
152f082f7f0SIngo Weinhold	bool					accessed : 1;
1533b8c056dSIngo Weinhold	bool					modified : 1;
154f082f7f0SIngo Weinhold	uint8					unused : 1;
15552a38012Sejakowatz
15640bb9481SIngo Weinhold	uint8					usage_count;
157b9447668SIngo Weinhold
158b9447668SIngo Weinhold	inline void Init(page_num_t pageNumber);
1596379e53eSIngo Weinhold
1606379e53eSIngo Weinhold	VMCacheRef* CacheRef() const			{ return cache_ref; }
1616379e53eSIngo Weinhold	void SetCacheRef(VMCacheRef* cacheRef)	{ this->cache_ref = cacheRef; }
1626379e53eSIngo Weinhold
1636379e53eSIngo Weinhold	VMCache* Cache() const
1646379e53eSIngo Weinhold		{ return cache_ref != NULL ? cache_ref->cache : NULL; }
165d36b9aefSIngo Weinhold
166d36b9aefSIngo Weinhold	bool IsMapped() const
167b9447668SIngo Weinhold		{ return fWiredCount > 0 || !mappings.IsEmpty(); }
168bd7645a1SIngo Weinhold
169bd7645a1SIngo Weinhold	uint8 State() const				{ return state; }
170bd7645a1SIngo Weinhold	void InitState(uint8 newState);
171bd7645a1SIngo Weinhold	void SetState(uint8 newState);
172b9447668SIngo Weinhold
173b9447668SIngo Weinhold	inline uint16 WiredCount() const	{ return fWiredCount; }
174b9447668SIngo Weinhold	inline void IncrementWiredCount();
175b9447668SIngo Weinhold	inline void DecrementWiredCount();
176b9447668SIngo Weinhold		// both implemented in VMCache.h to avoid inclusion here
177b9447668SIngo Weinhold
178b9447668SIngo Weinholdprivate:
179b9447668SIngo Weinhold	uint16					fWiredCount;
180e6dc7903SAxel Dörfler};
18152a38012Sejakowatz
18252a38012Sejakowatz
18352a38012Sejakowatzenum {
18452a38012Sejakowatz	PAGE_STATE_ACTIVE = 0,
18552a38012Sejakowatz	PAGE_STATE_INACTIVE,
18652a38012Sejakowatz	PAGE_STATE_MODIFIED,
187e65c4002SIngo Weinhold	PAGE_STATE_CACHED,
18852a38012Sejakowatz	PAGE_STATE_FREE,
18952a38012Sejakowatz	PAGE_STATE_CLEAR,
19052a38012Sejakowatz	PAGE_STATE_WIRED,
191e65c4002SIngo Weinhold	PAGE_STATE_UNUSED,
192e65c4002SIngo Weinhold
193e65c4002SIngo Weinhold	PAGE_STATE_COUNT,
194e65c4002SIngo Weinhold
195e65c4002SIngo Weinhold	PAGE_STATE_FIRST_UNQUEUED = PAGE_STATE_WIRED
19652a38012Sejakowatz};
19752a38012Sejakowatz
1985c99d639SIngo Weinhold
199e65c4002SIngo Weinhold#define VM_PAGE_ALLOC_STATE	0x00000007
200e65c4002SIngo Weinhold#define VM_PAGE_ALLOC_CLEAR	0x00000010
201e65c4002SIngo Weinhold#define VM_PAGE_ALLOC_BUSY	0x00000020
202e65c4002SIngo Weinhold
203e65c4002SIngo Weinhold
204b9447668SIngo Weinholdinline void
205b9447668SIngo Weinholdvm_page::Init(page_num_t pageNumber)
206b9447668SIngo Weinhold{
207b9447668SIngo Weinhold	physical_page_number = pageNumber;
208b9447668SIngo Weinhold	InitState(PAGE_STATE_FREE);
209b9447668SIngo Weinhold	new(&mappings) vm_page_mappings();
210b9447668SIngo Weinhold	fWiredCount = 0;
211b9447668SIngo Weinhold	usage_count = 0;
212b9447668SIngo Weinhold	busy_writing = false;
213b9447668SIngo Weinhold	SetCacheRef(NULL);
214b9447668SIngo Weinhold	#if DEBUG_PAGE_QUEUE
215b9447668SIngo Weinhold		queue = NULL;
216b9447668SIngo Weinhold	#endif
217b9447668SIngo Weinhold	#if DEBUG_PAGE_ACCESS
218b9447668SIngo Weinhold		accessing_thread = -1;
219b9447668SIngo Weinhold	#endif
220b9447668SIngo Weinhold}
221b9447668SIngo Weinhold
222b9447668SIngo Weinhold
2233cd20943SIngo Weinhold#if DEBUG_PAGE_ACCESS
2243cd20943SIngo Weinhold#	include <thread.h>
2253cd20943SIngo Weinhold
2263cd20943SIngo Weinholdstatic inline void
2273cd20943SIngo Weinholdvm_page_debug_access_start(vm_page* page)
2283cd20943SIngo Weinhold{
2293cd20943SIngo Weinhold	thread_id threadID = thread_get_current_thread_id();
2303cd20943SIngo Weinhold	thread_id previousThread = atomic_test_and_set(&page->accessing_thread,
2313cd20943SIngo Weinhold		threadID, -1);
2323cd20943SIngo Weinhold	if (previousThread != -1) {
2333cd20943SIngo Weinhold		panic("Invalid concurrent access to page %p (start), currently "
234fe0963a8SIngo Weinhold			"accessed by: %" B_PRId32
235fe0963a8SIngo Weinhold			"@! page -m %p; sc %" B_PRId32 "; cache _cache", page,
236fe0963a8SIngo Weinhold			previousThread, page, previousThread);
2373cd20943SIngo Weinhold	}
2383cd20943SIngo Weinhold}
2393cd20943SIngo Weinhold
2403cd20943SIngo Weinhold
2413cd20943SIngo Weinholdstatic inline void
2423cd20943SIngo Weinholdvm_page_debug_access_end(vm_page* page)
2433cd20943SIngo Weinhold{
2443cd20943SIngo Weinhold	thread_id threadID = thread_get_current_thread_id();
2453cd20943SIngo Weinhold	thread_id previousThread = atomic_test_and_set(&page->accessing_thread, -1,
2463cd20943SIngo Weinhold		threadID);
2473cd20943SIngo Weinhold	if (previousThread != threadID) {
2483cd20943SIngo Weinhold		panic("Invalid concurrent access to page %p (end) by current thread, "
249fe0963a8SIngo Weinhold			"current accessor is: %" B_PRId32
250fe0963a8SIngo Weinhold			"@! page -m %p; sc %" B_PRId32 "; cache _cache", page,
251fe0963a8SIngo Weinhold			previousThread, page, previousThread);
2523cd20943SIngo Weinhold	}
2533cd20943SIngo Weinhold}
2543cd20943SIngo Weinhold
2553cd20943SIngo Weinhold
2563cd20943SIngo Weinholdstatic inline void
2573cd20943SIngo Weinholdvm_page_debug_access_check(vm_page* page)
2583cd20943SIngo Weinhold{
2593cd20943SIngo Weinhold	thread_id thread = page->accessing_thread;
2603cd20943SIngo Weinhold	if (thread != thread_get_current_thread_id()) {
2613cd20943SIngo Weinhold		panic("Invalid concurrent access to page %p (check), currently "
262fe0963a8SIngo Weinhold			"accessed by: %" B_PRId32
263fe0963a8SIngo Weinhold			"@! page -m %p; sc %" B_PRId32 "; cache _cache", page, thread, page,
264fe0963a8SIngo Weinhold			thread);
2653cd20943SIngo Weinhold	}
2663cd20943SIngo Weinhold}
2673cd20943SIngo Weinhold
2683cd20943SIngo Weinhold
2693cd20943SIngo Weinholdstatic inline void
2703cd20943SIngo Weinholdvm_page_debug_access_transfer(vm_page* page, thread_id expectedPreviousThread)
2713cd20943SIngo Weinhold{
2723cd20943SIngo Weinhold	thread_id threadID = thread_get_current_thread_id();
2733cd20943SIngo Weinhold	thread_id previousThread = atomic_test_and_set(&page->accessing_thread,
2743cd20943SIngo Weinhold		threadID, expectedPreviousThread);
2753cd20943SIngo Weinhold	if (previousThread != expectedPreviousThread) {
2763cd20943SIngo Weinhold		panic("Invalid access transfer for page %p, currently accessed by: "
2773cd20943SIngo Weinhold			"%" B_PRId32 ", expected: %" B_PRId32, page, previousThread,
2783cd20943SIngo Weinhold			expectedPreviousThread);
2793cd20943SIngo Weinhold	}
2803cd20943SIngo Weinhold}
2813cd20943SIngo Weinhold
2823cd20943SIngo Weinhold#	define DEBUG_PAGE_ACCESS_START(page)	vm_page_debug_access_start(page)
2833cd20943SIngo Weinhold#	define DEBUG_PAGE_ACCESS_END(page)		vm_page_debug_access_end(page)
2843cd20943SIngo Weinhold#	define DEBUG_PAGE_ACCESS_CHECK(page)	vm_page_debug_access_check(page)
2853cd20943SIngo Weinhold#	define DEBUG_PAGE_ACCESS_TRANSFER(page, thread)	\
2863cd20943SIngo Weinhold		vm_page_debug_access_transfer(page, thread)
2873cd20943SIngo Weinhold#else
2883cd20943SIngo Weinhold#	define DEBUG_PAGE_ACCESS_START(page)			do {} while (false)
2893cd20943SIngo Weinhold#	define DEBUG_PAGE_ACCESS_END(page)				do {} while (false)
2903cd20943SIngo Weinhold#	define DEBUG_PAGE_ACCESS_CHECK(page)			do {} while (false)
2913cd20943SIngo Weinhold#	define DEBUG_PAGE_ACCESS_TRANSFER(page, thread)	do {} while (false)
2923cd20943SIngo Weinhold#endif
2933cd20943SIngo Weinhold
2943cd20943SIngo Weinhold
295e50cf876SIngo Weinhold#endif	// _KERNEL_VM_VM_TYPES_H
296