]>
Commit | Line | Data |
---|---|---|
5ba3f43e A |
1 | /* |
2 | * Copyright (c) 2000-2007 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | #include <mach/mach_types.h> | |
29 | #include <mach/vm_attributes.h> | |
30 | #include <mach/vm_param.h> | |
31 | ||
32 | #include <vm/pmap.h> | |
33 | ||
34 | #include <mach/thread_status.h> | |
35 | #include <mach-o/loader.h> | |
36 | #include <mach/vm_region.h> | |
37 | #include <mach/vm_statistics.h> | |
38 | ||
39 | #include <vm/vm_kern.h> | |
40 | #include <vm/vm_object.h> | |
41 | #include <vm/vm_protos.h> | |
42 | #include <kdp/kdp_core.h> | |
43 | #include <kdp/kdp_udp.h> | |
44 | #include <kdp/kdp_internal.h> | |
45 | #include <arm/misc_protos.h> | |
46 | #include <arm/caches_internal.h> | |
47 | #include <arm/cpu_data_internal.h> | |
48 | ||
49 | pmap_t kdp_pmap = 0; | |
50 | boolean_t kdp_trans_off; | |
51 | boolean_t kdp_read_io = 0; | |
52 | ||
53 | pmap_paddr_t kdp_vtophys(pmap_t pmap, vm_offset_t va); | |
54 | ||
55 | /* | |
56 | * kdp_vtophys | |
57 | */ | |
58 | pmap_paddr_t | |
59 | kdp_vtophys( | |
60 | pmap_t pmap, | |
61 | vm_offset_t va) | |
62 | { | |
63 | pmap_paddr_t pa; | |
64 | ppnum_t pp; | |
65 | ||
66 | /* Ensure that the provided va resides within the provided pmap range. */ | |
67 | if(!pmap || ((pmap != kernel_pmap) && ((va < pmap->min) || (va >= pmap->max)))) | |
68 | { | |
69 | #ifdef KDP_VTOPHYS_DEBUG | |
70 | printf("kdp_vtophys(%08x, %016lx) not in range %08x .. %08x\n", (unsigned int) pmap, | |
71 | (unsigned long) va, | |
72 | (unsigned int) (pmap ? pmap->min : 0), | |
73 | (unsigned int) (pmap ? pmap->max : 0)); | |
74 | #endif | |
75 | return 0; /* Just return if no translation */ | |
76 | } | |
77 | ||
78 | pp = pmap_find_phys(pmap, va); /* Get the page number */ | |
79 | if (!pp) | |
80 | return 0; /* Just return if no translation */ | |
81 | ||
82 | pa = ((pmap_paddr_t) pp << PAGE_SHIFT) | (va & PAGE_MASK); /* Insert page offset */ | |
83 | return (pa); | |
84 | } | |
85 | ||
86 | ||
87 | /* | |
88 | * kdp_machine_vm_read | |
89 | * | |
90 | * Verify that src is valid, and physically copy len bytes from src to | |
91 | * dst, translating if necessary. If translation is enabled | |
92 | * (kdp_trans_off is 0), a non-zero kdp_pmap specifies the pmap to use | |
93 | * when translating src. | |
94 | */ | |
95 | ||
96 | mach_vm_size_t | |
97 | kdp_machine_vm_read( mach_vm_address_t src, caddr_t dst, mach_vm_size_t len) | |
98 | { | |
99 | addr64_t cur_virt_src, cur_virt_dst; | |
100 | addr64_t cur_phys_src, cur_phys_dst; | |
101 | mach_vm_size_t resid, cnt; | |
102 | pmap_t pmap; | |
103 | ||
104 | #ifdef KDP_VM_READ_DEBUG | |
105 | kprintf("kdp_machine_vm_read1: src %x dst %x len %x - %08X %08X\n", src, dst, len, ((unsigned long *) src)[0], ((unsigned long *) src)[1]); | |
106 | #endif | |
107 | ||
108 | cur_virt_src = (addr64_t) src; | |
109 | cur_virt_dst = (addr64_t) dst; | |
110 | ||
111 | if (kdp_trans_off) { | |
112 | kdp_readphysmem64_req_t rq; | |
113 | mach_vm_size_t ret; | |
114 | ||
115 | rq.address = src; | |
116 | rq.nbytes = (uint32_t)len; | |
117 | ret = kdp_machine_phys_read(&rq, dst, 0 /* unused */); | |
118 | return ret; | |
119 | } else { | |
120 | ||
121 | resid = len; | |
122 | ||
123 | if (kdp_pmap) | |
124 | pmap = kdp_pmap; /* If special pmap, use it */ | |
125 | else | |
126 | pmap = kernel_pmap; /* otherwise, use kernel's */ | |
127 | ||
128 | while (resid != 0) { | |
129 | /* | |
130 | * Always translate the destination using the | |
131 | * kernel_pmap. | |
132 | */ | |
133 | if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0) | |
134 | goto exit; | |
135 | ||
136 | if ((cur_phys_src = kdp_vtophys(pmap, cur_virt_src)) == 0) | |
137 | goto exit; | |
138 | ||
139 | /* Attempt to ensure that there are valid translations for src and dst. */ | |
140 | if (!kdp_read_io && ((!pmap_valid_address(cur_phys_dst)) || (!pmap_valid_address(cur_phys_src)))) | |
141 | goto exit; | |
142 | ||
143 | cnt = ARM_PGBYTES - (cur_virt_src & PAGE_MASK); /* Get length left on | |
144 | * page */ | |
145 | if (cnt > (ARM_PGBYTES - (cur_virt_dst & PAGE_MASK))) | |
146 | cnt = ARM_PGBYTES - (cur_virt_dst & PAGE_MASK); | |
147 | ||
148 | if (cnt > resid) | |
149 | cnt = resid; | |
150 | ||
151 | #ifdef KDP_VM_READ_DEBUG | |
152 | kprintf("kdp_machine_vm_read2: pmap %08X, virt %016LLX, phys %016LLX\n", | |
153 | pmap, cur_virt_src, cur_phys_src); | |
154 | #endif | |
155 | bcopy_phys(cur_phys_src, cur_phys_dst, cnt); | |
156 | ||
157 | cur_virt_src += cnt; | |
158 | cur_virt_dst += cnt; | |
159 | resid -= cnt; | |
160 | } | |
161 | } | |
162 | exit: | |
163 | #ifdef KDP_VM_READ_DEBUG | |
164 | kprintf("kdp_machine_vm_read: ret %08X\n", len - resid); | |
165 | #endif | |
166 | return (len - resid); | |
167 | } | |
168 | ||
169 | mach_vm_size_t | |
170 | kdp_machine_phys_read(kdp_readphysmem64_req_t *rq, caddr_t dst, uint16_t lcpu __unused) | |
171 | { | |
172 | mach_vm_address_t src = rq->address; | |
173 | mach_vm_size_t len = rq->nbytes; | |
174 | ||
175 | addr64_t cur_virt_dst; | |
176 | addr64_t cur_phys_src, cur_phys_dst; | |
177 | mach_vm_size_t resid = len; | |
178 | mach_vm_size_t cnt = 0, cnt_src, cnt_dst; | |
179 | ||
180 | #ifdef KDP_VM_READ_DEBUG | |
181 | kprintf("kdp_phys_read src %x dst %p len %x\n", src, dst, len); | |
182 | #endif | |
183 | ||
184 | cur_virt_dst = (addr64_t) dst; | |
185 | cur_phys_src = (addr64_t) src; | |
186 | ||
187 | while (resid != 0) { | |
188 | ||
189 | if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0) | |
190 | goto exit; | |
191 | ||
192 | /* Get length left on page */ | |
193 | ||
194 | cnt_src = ARM_PGBYTES - (cur_phys_src & PAGE_MASK); | |
195 | cnt_dst = ARM_PGBYTES - (cur_phys_dst & PAGE_MASK); | |
196 | if (cnt_src > cnt_dst) | |
197 | cnt = cnt_dst; | |
198 | else | |
199 | cnt = cnt_src; | |
200 | if (cnt > resid) | |
201 | cnt = resid; | |
202 | ||
203 | bcopy_phys(cur_phys_src, cur_phys_dst, cnt); /* Copy stuff over */ | |
204 | cur_phys_src += cnt; | |
205 | cur_virt_dst += cnt; | |
206 | resid -= cnt; | |
207 | } | |
208 | ||
209 | exit: | |
210 | return (len - resid); | |
211 | } | |
212 | ||
213 | /* | |
214 | * kdp_vm_write | |
215 | */ | |
216 | mach_vm_size_t | |
217 | kdp_machine_vm_write( caddr_t src, mach_vm_address_t dst, mach_vm_size_t len) | |
218 | { | |
219 | addr64_t cur_virt_src, cur_virt_dst; | |
220 | addr64_t cur_phys_src, cur_phys_dst; | |
221 | mach_vm_size_t resid, cnt, cnt_src, cnt_dst; | |
222 | ||
223 | #ifdef KDP_VM_WRITE_DEBUG | |
224 | printf("kdp_vm_write: src %x dst %x len %x - %08X %08X\n", src, dst, len, ((unsigned long *) src)[0], ((unsigned long *) src)[1]); | |
225 | #endif | |
226 | ||
227 | cur_virt_src = (addr64_t) src; | |
228 | cur_virt_dst = (addr64_t) dst; | |
229 | ||
230 | resid = len; | |
231 | ||
232 | while (resid != 0) { | |
233 | if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0) | |
234 | goto exit; | |
235 | ||
236 | if ((cur_phys_src = kdp_vtophys(kernel_pmap, cur_virt_src)) == 0) | |
237 | goto exit; | |
238 | ||
239 | /* Attempt to ensure that there are valid translations for src and dst. */ | |
240 | /* No support for enabling writes for an invalid translation at the moment. */ | |
241 | if ((!pmap_valid_address(cur_phys_dst)) || (!pmap_valid_address(cur_phys_src))) | |
242 | goto exit; | |
243 | ||
244 | cnt_src = ((cur_phys_src + ARM_PGBYTES) & (-ARM_PGBYTES)) - cur_phys_src; | |
245 | cnt_dst = ((cur_phys_dst + ARM_PGBYTES) & (-ARM_PGBYTES)) - cur_phys_dst; | |
246 | ||
247 | if (cnt_src > cnt_dst) | |
248 | cnt = cnt_dst; | |
249 | else | |
250 | cnt = cnt_src; | |
251 | if (cnt > resid) | |
252 | cnt = resid; | |
253 | ||
254 | #ifdef KDP_VM_WRITE_DEBUG | |
255 | printf("kdp_vm_write: cur_phys_src %x cur_phys_src %x len %x - %08X %08X\n", src, dst, cnt); | |
256 | #endif | |
257 | bcopy_phys(cur_phys_src, cur_phys_dst, cnt); /* Copy stuff over */ | |
258 | flush_dcache64(cur_phys_dst, (unsigned int)cnt, TRUE); | |
259 | invalidate_icache64(cur_phys_dst, (unsigned int)cnt, TRUE); | |
260 | ||
261 | cur_virt_src += cnt; | |
262 | cur_virt_dst += cnt; | |
263 | resid -= cnt; | |
264 | } | |
265 | exit: | |
266 | return (len - resid); | |
267 | } | |
268 | ||
269 | mach_vm_size_t | |
270 | kdp_machine_phys_write(kdp_writephysmem64_req_t *rq __unused, caddr_t src __unused, | |
271 | uint16_t lcpu __unused) | |
272 | { | |
273 | return 0; /* unimplemented */ | |
274 | } | |
275 | ||
276 | void | |
277 | kern_collectth_state_size(uint64_t * tstate_count, uint64_t * tstate_size) | |
278 | { | |
279 | uint64_t count = ml_get_max_cpu_number() + 1; | |
280 | ||
281 | *tstate_count = count; | |
282 | *tstate_size = sizeof(struct thread_command) | |
283 | + (sizeof(arm_state_hdr_t) | |
284 | #if defined(__arm64__) | |
285 | + ARM_THREAD_STATE64_COUNT * sizeof(uint32_t)); | |
286 | #else | |
287 | + ARM_THREAD_STATE32_COUNT * sizeof(uint32_t)); | |
288 | #endif | |
289 | } | |
290 | ||
291 | void | |
292 | kern_collectth_state(thread_t thread __unused, void *buffer, uint64_t size, void ** iter) | |
293 | { | |
294 | cpu_data_entry_t *cpuentryp = *iter; | |
295 | if (cpuentryp == NULL) | |
296 | cpuentryp = &CpuDataEntries[0]; | |
297 | ||
298 | if (cpuentryp == &CpuDataEntries[ml_get_max_cpu_number()]) | |
299 | *iter = NULL; | |
300 | else | |
301 | *iter = cpuentryp + 1; | |
302 | ||
303 | struct cpu_data *cpudatap = cpuentryp->cpu_data_vaddr; | |
304 | ||
305 | struct thread_command *tc = (struct thread_command *)buffer; | |
306 | arm_state_hdr_t *hdr = (arm_state_hdr_t *)(void *)(tc + 1); | |
307 | #if defined(__arm64__) | |
308 | hdr->flavor = ARM_THREAD_STATE64; | |
309 | hdr->count = ARM_THREAD_STATE64_COUNT; | |
310 | arm_thread_state64_t *state = (arm_thread_state64_t *)(void *)(hdr + 1); | |
311 | #else | |
312 | hdr->flavor = ARM_THREAD_STATE; | |
313 | hdr->count = ARM_THREAD_STATE_COUNT; | |
314 | arm_thread_state_t *state = (arm_thread_state_t *)(void *)(hdr + 1); | |
315 | #endif | |
316 | ||
317 | tc->cmd = LC_THREAD; | |
318 | tc->cmdsize = (uint32_t) size; | |
319 | ||
320 | if ((cpudatap != NULL) && (cpudatap->halt_status == CPU_HALTED_WITH_STATE)) { | |
321 | *state = cpudatap->halt_state; | |
322 | return; | |
323 | } | |
324 | ||
325 | if ((cpudatap == NULL) || (cpudatap->cpu_processor == NULL) || (cpudatap->cpu_processor->active_thread == NULL)) { | |
326 | bzero(state, hdr->count * sizeof(uint32_t)); | |
327 | return; | |
328 | } | |
329 | ||
330 | vm_offset_t kstackptr = (vm_offset_t) cpudatap->cpu_processor->active_thread->machine.kstackptr; | |
331 | arm_saved_state_t *saved_state = (arm_saved_state_t *) kstackptr; | |
332 | ||
333 | #if defined(__arm64__) | |
334 | ||
335 | state->fp = saved_state->ss_64.fp; | |
336 | state->lr = saved_state->ss_64.lr; | |
337 | state->sp = saved_state->ss_64.sp; | |
338 | state->pc = saved_state->ss_64.pc; | |
339 | state->cpsr = saved_state->ss_64.cpsr; | |
340 | bcopy(&saved_state->ss_64.x[0], &state->x[0], sizeof(state->x)); | |
341 | ||
342 | #else /* __arm64__ */ | |
343 | ||
344 | state->lr = saved_state->lr; | |
345 | state->sp = saved_state->sp; | |
346 | state->pc = saved_state->pc; | |
347 | state->cpsr = saved_state->cpsr; | |
348 | bcopy(&saved_state->r[0], &state->r[0], sizeof(state->r)); | |
349 | ||
350 | #endif /* !__arm64__ */ | |
351 | ||
352 | ||
353 | } | |
354 | ||
355 |