1/*
2 * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2002-2009, Axel D��rfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
5 *
6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
7 * Distributed under the terms of the NewOS License.
8 */
9#ifndef _KERNEL_VM_VM_AREA_H
10#define _KERNEL_VM_VM_AREA_H
11
12
13#include <vm_defs.h>
14
15#include <lock.h>
16#include <util/DoublyLinkedList.h>
17#include <util/SinglyLinkedList.h>
18#include <util/AVLTree.h>
19#include <vm/vm_types.h>
20
21
22struct VMAddressSpace;
23struct VMCache;
24struct VMKernelAddressSpace;
25struct VMUserAddressSpace;
26
27
28struct VMAreaUnwiredWaiter
29	: public DoublyLinkedListLinkImpl<VMAreaUnwiredWaiter> {
30	VMArea*					area;
31	addr_t					base;
32	size_t					size;
33	ConditionVariable		condition;
34	ConditionVariableEntry	waitEntry;
35};
36
37typedef DoublyLinkedList<VMAreaUnwiredWaiter> VMAreaUnwiredWaiterList;
38
39
40struct VMAreaWiredRange : SinglyLinkedListLinkImpl<VMAreaWiredRange> {
41	VMArea*					area;
42	addr_t					base;
43	size_t					size;
44	bool					writable;
45	bool					implicit;	// range created automatically
46	VMAreaUnwiredWaiterList	waiters;
47
48	VMAreaWiredRange()
49	{
50	}
51
52	VMAreaWiredRange(addr_t base, size_t size, bool writable, bool implicit)
53		:
54		area(NULL),
55		base(base),
56		size(size),
57		writable(writable),
58		implicit(implicit)
59	{
60	}
61
62	void SetTo(addr_t base, size_t size, bool writable, bool implicit)
63	{
64		this->area = NULL;
65		this->base = base;
66		this->size = size;
67		this->writable = writable;
68		this->implicit = implicit;
69	}
70
71	bool IntersectsWith(addr_t base, size_t size) const
72	{
73		return this->base + this->size - 1 >= base
74			&& base + size - 1 >= this->base;
75	}
76};
77
78typedef SinglyLinkedList<VMAreaWiredRange> VMAreaWiredRangeList;
79
80
81struct VMPageWiringInfo {
82	VMAreaWiredRange	range;
83	phys_addr_t			physicalAddress;
84							// the actual physical address corresponding to
85							// the virtual address passed to vm_wire_page()
86							// (i.e. with in-page offset)
87	vm_page*			page;
88};
89
90
91struct VMAreasTreeNode {
92	AVLTreeNode tree_node;
93};
94
95
96struct VMArea : private VMAreasTreeNode {
97public:
98	enum {
99		// AddWaiterIfWired() flags
100		IGNORE_WRITE_WIRED_RANGES	= 0x01,	// ignore existing ranges that
101											// wire for writing
102	};
103
104public:
105	area_id					id;
106	char					name[B_OS_NAME_LENGTH];
107	uint32					protection;
108	uint32					protection_max;
109	uint16					wiring;
110
111private:
112	uint16					memory_type;	// >> shifted by MEMORY_TYPE_SHIFT
113
114public:
115	VMCache*				cache;
116	vint32					no_cache_change;
117	off_t					cache_offset;
118	uint32					cache_type;
119	VMAreaMappings			mappings;
120	uint8*					page_protections;
121
122	struct VMAddressSpace*	address_space;
123	struct VMArea*			cache_next;
124	struct VMArea*			cache_prev;
125
126			addr_t				Base() const	{ return fBase; }
127			size_t				Size() const	{ return fSize; }
128
129	inline	uint32				MemoryType() const;
130	inline	void				SetMemoryType(uint32 memoryType);
131
132			bool				ContainsAddress(addr_t address) const
133									{ return address >= fBase
134										&& address <= fBase + (fSize - 1); }
135
136			bool				IsWired() const
137									{ return !fWiredRanges.IsEmpty(); }
138			bool				IsWired(addr_t base, size_t size) const;
139
140			void				Wire(VMAreaWiredRange* range);
141			void				Unwire(VMAreaWiredRange* range);
142			VMAreaWiredRange*	Unwire(addr_t base, size_t size, bool writable);
143
144			bool				AddWaiterIfWired(VMAreaUnwiredWaiter* waiter);
145			bool				AddWaiterIfWired(VMAreaUnwiredWaiter* waiter,
146									addr_t base, size_t size, uint32 flags = 0);
147
148protected:
149								VMArea(VMAddressSpace* addressSpace,
150									uint32 wiring, uint32 protection);
151								~VMArea();
152
153			status_t			Init(const char* name, uint32 allocationFlags);
154
155protected:
156			friend struct VMAreasTreeDefinition;
157			friend struct VMKernelAddressSpace;
158			friend struct VMUserAddressSpace;
159
160protected:
161			void				SetBase(addr_t base)	{ fBase = base; }
162			void				SetSize(size_t size)	{ fSize = size; }
163
164protected:
165			addr_t				fBase;
166			size_t				fSize;
167			VMAreaWiredRangeList fWiredRanges;
168};
169
170
171struct VMAreasTreeDefinition {
172	typedef area_id		Key;
173	typedef VMArea		Value;
174
175	AVLTreeNode* GetAVLTreeNode(VMArea* value) const
176	{
177		return &value->tree_node;
178	}
179
180	VMArea* GetValue(AVLTreeNode* node) const
181	{
182		const addr_t vmTreeNodeAddr = (addr_t)node
183			- offsetof(VMAreasTreeNode, tree_node);
184		VMAreasTreeNode* vmTreeNode =
185			reinterpret_cast<VMAreasTreeNode*>(vmTreeNodeAddr);
186		return static_cast<VMArea*>(vmTreeNode);
187	}
188
189	int Compare(area_id key, const VMArea* value) const
190	{
191		const area_id valueId = value->id;
192		if (valueId == key)
193			return 0;
194		return key < valueId ? -1 : 1;
195	}
196
197	int Compare(const VMArea* a, const VMArea* b) const
198	{
199		return Compare(a->id, b);
200	}
201};
202
203typedef AVLTree<VMAreasTreeDefinition> VMAreasTree;
204
205
206struct VMAreas {
207	static	status_t			Init();
208
209	static	status_t			ReadLock()
210									{ return rw_lock_read_lock(&sLock); }
211	static	void				ReadUnlock()
212									{ rw_lock_read_unlock(&sLock); }
213	static	status_t			WriteLock()
214									{ return rw_lock_write_lock(&sLock); }
215	static	void				WriteUnlock()
216									{ rw_lock_write_unlock(&sLock); }
217
218	static	VMArea*				LookupLocked(area_id id)
219									{ return sTree.Find(id); }
220	static	VMArea*				Lookup(area_id id);
221	static	area_id				Find(const char* name);
222	static	void				Insert(VMArea* area);
223	static	void				Remove(VMArea* area);
224
225	static	VMAreasTree::Iterator GetIterator()
226									{ return sTree.GetIterator(); }
227
228private:
229	static	rw_lock				sLock;
230	static	VMAreasTree			sTree;
231};
232
233
234uint32
235VMArea::MemoryType() const
236{
237	return (uint32)memory_type << MEMORY_TYPE_SHIFT;
238}
239
240
241void
242VMArea::SetMemoryType(uint32 memoryType)
243{
244	memory_type = memoryType >> MEMORY_TYPE_SHIFT;
245}
246
247
248#endif	// _KERNEL_VM_VM_AREA_H
249