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