1/*
2 * Copyright 2008-2010, Ingo Weinhold <ingo_weinhold@gmx.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6
7#include "generic_vm_physical_page_ops.h"
8
9#include <vm/vm.h>
10#include <util/AutoLock.h>
11#include <util/ThreadAutoLock.h>
12
13
14status_t
15generic_vm_memset_physical(phys_addr_t address, int value, phys_size_t length)
16{
17	ThreadCPUPinner _(thread_get_current_thread());
18
19	while (length > 0) {
20		phys_addr_t pageOffset = address % B_PAGE_SIZE;
21		addr_t virtualAddress;
22		void* handle;
23		status_t error = vm_get_physical_page_current_cpu(address - pageOffset,
24			&virtualAddress, &handle);
25		if (error != B_OK)
26			return error;
27
28		size_t toSet = min_c(length, B_PAGE_SIZE - pageOffset);
29		memset((void*)(virtualAddress + pageOffset), value, toSet);
30
31		vm_put_physical_page_current_cpu(virtualAddress, handle);
32
33		length -= toSet;
34		address += toSet;
35	}
36
37	return B_OK;
38}
39
40
41status_t
42generic_vm_memcpy_from_physical(void* _to, phys_addr_t from, size_t length,
43	bool user)
44{
45	uint8* to = (uint8*)_to;
46	phys_addr_t pageOffset = from % B_PAGE_SIZE;
47
48	ThreadCPUPinner _(thread_get_current_thread());
49
50	while (length > 0) {
51		size_t toCopy = min_c(length, B_PAGE_SIZE - pageOffset);
52
53		addr_t virtualAddress;
54		void* handle;
55		status_t error = vm_get_physical_page_current_cpu(from - pageOffset,
56			&virtualAddress, &handle);
57		if (error != B_OK)
58			return error;
59
60		if (user) {
61			error = user_memcpy(to, (void*)(virtualAddress + pageOffset),
62				toCopy);
63		} else
64			memcpy(to, (void*)(virtualAddress + pageOffset), toCopy);
65
66		vm_put_physical_page_current_cpu(virtualAddress, handle);
67
68		if (error != B_OK)
69			return error;
70
71		to += toCopy;
72		from += toCopy;
73		length -= toCopy;
74		pageOffset = 0;
75	}
76
77	return B_OK;
78}
79
80
81status_t
82generic_vm_memcpy_to_physical(phys_addr_t to, const void* _from, size_t length,
83	bool user)
84{
85	const uint8* from = (const uint8*)_from;
86	phys_addr_t pageOffset = to % B_PAGE_SIZE;
87
88	ThreadCPUPinner _(thread_get_current_thread());
89
90	while (length > 0) {
91		size_t toCopy = min_c(length, B_PAGE_SIZE - pageOffset);
92
93		addr_t virtualAddress;
94		void* handle;
95		status_t error = vm_get_physical_page_current_cpu(to - pageOffset,
96			&virtualAddress, &handle);
97		if (error != B_OK)
98			return error;
99
100		if (user) {
101			error = user_memcpy((void*)(virtualAddress + pageOffset), from,
102				toCopy);
103		} else
104			memcpy((void*)(virtualAddress + pageOffset), from, toCopy);
105
106		vm_put_physical_page_current_cpu(virtualAddress, handle);
107
108		if (error != B_OK)
109			return error;
110
111		to += toCopy;
112		from += toCopy;
113		length -= toCopy;
114		pageOffset = 0;
115	}
116
117	return B_OK;
118}
119
120
121/*!	NOTE: If this function is used, vm_get_physical_page_current_cpu() must not
122	be blocking, since we need to call it twice and could thus deadlock.
123*/
124void
125generic_vm_memcpy_physical_page(phys_addr_t to, phys_addr_t from)
126{
127	ThreadCPUPinner _(thread_get_current_thread());
128
129	// map source page
130	addr_t fromVirtual;
131	void* fromHandle;
132	status_t error = vm_get_physical_page_current_cpu(from, &fromVirtual,
133		&fromHandle);
134	if (error != B_OK) {
135		panic("generic_vm_memcpy_physical_page(): Failed to map source page!");
136		return;
137	}
138
139	// map destination page
140	addr_t toVirtual;
141	void* toHandle;
142	error = vm_get_physical_page_current_cpu(to, &toVirtual, &toHandle);
143	if (error == B_OK) {
144		// both pages are mapped -- copy
145		memcpy((void*)toVirtual, (const void*)fromVirtual, B_PAGE_SIZE);
146		vm_put_physical_page_current_cpu(toVirtual, toHandle);
147	} else {
148		panic("generic_vm_memcpy_physical_page(): Failed to map destination "
149			"page!");
150	}
151
152	vm_put_physical_page_current_cpu(fromVirtual, fromHandle);
153}
154