1/*
2 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2002-2007, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
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
10
11#include "paging/32bit/ARMPagingStructures32Bit.h"
12
13#include <stdlib.h>
14
15#include <heap.h>
16#include <util/AutoLock.h>
17
18
19// Accessor class to reuse the SinglyLinkedListLink of DeferredDeletable for
20// ARMPagingStructures32Bit.
21struct PagingStructuresGetLink {
22private:
23	typedef SinglyLinkedListLink<ARMPagingStructures32Bit> Link;
24
25public:
26	inline Link* operator()(ARMPagingStructures32Bit* element) const
27	{
28		return (Link*)element->GetSinglyLinkedListLink();
29	}
30
31	inline const Link* operator()(
32		const ARMPagingStructures32Bit* element) const
33	{
34		return (const Link*)element->GetSinglyLinkedListLink();
35	}
36};
37
38
39typedef SinglyLinkedList<ARMPagingStructures32Bit, PagingStructuresGetLink>
40	PagingStructuresList;
41
42
43static PagingStructuresList sPagingStructuresList;
44static spinlock sPagingStructuresListLock;
45
46
47ARMPagingStructures32Bit::ARMPagingStructures32Bit()
48	:
49	pgdir_virt(NULL)
50{
51}
52
53
54ARMPagingStructures32Bit::~ARMPagingStructures32Bit()
55{
56	// free the page dir
57	free(pgdir_virt);
58}
59
60
61void
62ARMPagingStructures32Bit::Init(page_directory_entry* virtualPageDir,
63	phys_addr_t physicalPageDir, page_directory_entry* kernelPageDir)
64{
65	pgdir_virt = virtualPageDir;
66	pgdir_phys = physicalPageDir;
67
68	// zero out the bottom portion of the new pgdir
69	memset(pgdir_virt + FIRST_USER_PGDIR_ENT, 0,
70		NUM_USER_PGDIR_ENTS * sizeof(page_directory_entry));
71
72	// insert this new map into the map list
73	{
74		int state = disable_interrupts();
75		acquire_spinlock(&sPagingStructuresListLock);
76
77		// copy the top portion of the page dir from the kernel page dir
78		if (kernelPageDir != NULL) {
79			memcpy(pgdir_virt + FIRST_KERNEL_PGDIR_ENT,
80				kernelPageDir + FIRST_KERNEL_PGDIR_ENT,
81				NUM_KERNEL_PGDIR_ENTS * sizeof(page_directory_entry));
82		}
83
84		sPagingStructuresList.Add(this);
85
86		release_spinlock(&sPagingStructuresListLock);
87		restore_interrupts(state);
88	}
89}
90
91
92void
93ARMPagingStructures32Bit::Delete()
94{
95	// remove from global list
96	InterruptsSpinLocker locker(sPagingStructuresListLock);
97	sPagingStructuresList.Remove(this);
98	locker.Unlock();
99
100#if 0
101	// this sanity check can be enabled when corruption due to
102	// overwriting an active page directory is suspected
103	uint32 activePageDirectory = x86_read_cr3();
104	if (activePageDirectory == pgdir_phys)
105		panic("deleting a still active page directory\n");
106#endif
107
108	if (are_interrupts_enabled())
109		delete this;
110	else
111		deferred_delete(this);
112}
113
114
115/*static*/ void
116ARMPagingStructures32Bit::StaticInit()
117{
118	B_INITIALIZE_SPINLOCK(&sPagingStructuresListLock);
119	new (&sPagingStructuresList) PagingStructuresList;
120}
121
122
123/*static*/ void
124ARMPagingStructures32Bit::UpdateAllPageDirs(int index,
125	page_directory_entry entry)
126{
127	InterruptsSpinLocker locker(sPagingStructuresListLock);
128
129	PagingStructuresList::Iterator it = sPagingStructuresList.GetIterator();
130	while (ARMPagingStructures32Bit* info = it.Next())
131		info->pgdir_virt[index] = entry;
132}
133