xref: /haiku/src/system/kernel/arch/generic/generic_vm_physical_page_ops.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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 
14 status_t
15 generic_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 
41 status_t
42 generic_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 
81 status_t
82 generic_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 */
124 void
125 generic_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