]>
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; | |
0a7de745 | 51 | boolean_t kdp_read_io = 0; |
5ba3f43e A |
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( | |
0a7de745 A |
60 | pmap_t pmap, |
61 | vm_offset_t va) | |
5ba3f43e A |
62 | { |
63 | pmap_paddr_t pa; | |
64 | ppnum_t pp; | |
65 | ||
66 | /* Ensure that the provided va resides within the provided pmap range. */ | |
0a7de745 | 67 | if (!pmap || ((pmap != kernel_pmap) && ((va < pmap->min) || (va >= pmap->max)))) { |
5ba3f43e A |
68 | #ifdef KDP_VTOPHYS_DEBUG |
69 | printf("kdp_vtophys(%08x, %016lx) not in range %08x .. %08x\n", (unsigned int) pmap, | |
0a7de745 A |
70 | (unsigned long) va, |
71 | (unsigned int) (pmap ? pmap->min : 0), | |
72 | (unsigned int) (pmap ? pmap->max : 0)); | |
5ba3f43e | 73 | #endif |
0a7de745 | 74 | return 0; /* Just return if no translation */ |
5ba3f43e A |
75 | } |
76 | ||
0a7de745 A |
77 | pp = pmap_find_phys(pmap, va); /* Get the page number */ |
78 | if (!pp) { | |
79 | return 0; /* Just return if no translation */ | |
80 | } | |
81 | pa = ((pmap_paddr_t) pp << PAGE_SHIFT) | (va & PAGE_MASK); /* Insert page offset */ | |
82 | return pa; | |
5ba3f43e A |
83 | } |
84 | ||
85 | ||
86 | /* | |
87 | * kdp_machine_vm_read | |
88 | * | |
89 | * Verify that src is valid, and physically copy len bytes from src to | |
90 | * dst, translating if necessary. If translation is enabled | |
91 | * (kdp_trans_off is 0), a non-zero kdp_pmap specifies the pmap to use | |
92 | * when translating src. | |
93 | */ | |
94 | ||
95 | mach_vm_size_t | |
96 | kdp_machine_vm_read( mach_vm_address_t src, caddr_t dst, mach_vm_size_t len) | |
97 | { | |
98 | addr64_t cur_virt_src, cur_virt_dst; | |
99 | addr64_t cur_phys_src, cur_phys_dst; | |
0a7de745 | 100 | mach_vm_size_t resid, cnt; |
5ba3f43e A |
101 | pmap_t pmap; |
102 | ||
103 | #ifdef KDP_VM_READ_DEBUG | |
104 | 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]); | |
105 | #endif | |
106 | ||
107 | cur_virt_src = (addr64_t) src; | |
108 | cur_virt_dst = (addr64_t) dst; | |
109 | ||
110 | if (kdp_trans_off) { | |
111 | kdp_readphysmem64_req_t rq; | |
112 | mach_vm_size_t ret; | |
113 | ||
114 | rq.address = src; | |
115 | rq.nbytes = (uint32_t)len; | |
116 | ret = kdp_machine_phys_read(&rq, dst, 0 /* unused */); | |
117 | return ret; | |
118 | } else { | |
5ba3f43e A |
119 | resid = len; |
120 | ||
0a7de745 A |
121 | if (kdp_pmap) { |
122 | pmap = kdp_pmap; /* If special pmap, use it */ | |
123 | } else { | |
124 | pmap = kernel_pmap; /* otherwise, use kernel's */ | |
125 | } | |
5ba3f43e A |
126 | while (resid != 0) { |
127 | /* | |
128 | * Always translate the destination using the | |
129 | * kernel_pmap. | |
130 | */ | |
0a7de745 | 131 | if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0) { |
5ba3f43e | 132 | goto exit; |
0a7de745 | 133 | } |
5ba3f43e | 134 | |
0a7de745 | 135 | if ((cur_phys_src = kdp_vtophys(pmap, cur_virt_src)) == 0) { |
5ba3f43e | 136 | goto exit; |
0a7de745 | 137 | } |
5ba3f43e A |
138 | |
139 | /* Attempt to ensure that there are valid translations for src and dst. */ | |
0a7de745 | 140 | if (!kdp_read_io && ((!pmap_valid_address(cur_phys_dst)) || (!pmap_valid_address(cur_phys_src)))) { |
5ba3f43e | 141 | goto exit; |
0a7de745 | 142 | } |
5ba3f43e | 143 | |
0a7de745 A |
144 | cnt = ARM_PGBYTES - (cur_virt_src & PAGE_MASK); /* Get length left on |
145 | * page */ | |
146 | if (cnt > (ARM_PGBYTES - (cur_virt_dst & PAGE_MASK))) { | |
5ba3f43e | 147 | cnt = ARM_PGBYTES - (cur_virt_dst & PAGE_MASK); |
0a7de745 | 148 | } |
5ba3f43e | 149 | |
0a7de745 | 150 | if (cnt > resid) { |
5ba3f43e | 151 | cnt = resid; |
0a7de745 | 152 | } |
5ba3f43e A |
153 | |
154 | #ifdef KDP_VM_READ_DEBUG | |
155 | kprintf("kdp_machine_vm_read2: pmap %08X, virt %016LLX, phys %016LLX\n", | |
0a7de745 | 156 | pmap, cur_virt_src, cur_phys_src); |
5ba3f43e A |
157 | #endif |
158 | bcopy_phys(cur_phys_src, cur_phys_dst, cnt); | |
159 | ||
160 | cur_virt_src += cnt; | |
161 | cur_virt_dst += cnt; | |
162 | resid -= cnt; | |
163 | } | |
164 | } | |
165 | exit: | |
166 | #ifdef KDP_VM_READ_DEBUG | |
167 | kprintf("kdp_machine_vm_read: ret %08X\n", len - resid); | |
168 | #endif | |
0a7de745 | 169 | return len - resid; |
5ba3f43e A |
170 | } |
171 | ||
172 | mach_vm_size_t | |
173 | kdp_machine_phys_read(kdp_readphysmem64_req_t *rq, caddr_t dst, uint16_t lcpu __unused) | |
174 | { | |
175 | mach_vm_address_t src = rq->address; | |
176 | mach_vm_size_t len = rq->nbytes; | |
0a7de745 | 177 | |
5ba3f43e A |
178 | addr64_t cur_virt_dst; |
179 | addr64_t cur_phys_src, cur_phys_dst; | |
180 | mach_vm_size_t resid = len; | |
181 | mach_vm_size_t cnt = 0, cnt_src, cnt_dst; | |
182 | ||
183 | #ifdef KDP_VM_READ_DEBUG | |
184 | kprintf("kdp_phys_read src %x dst %p len %x\n", src, dst, len); | |
185 | #endif | |
186 | ||
187 | cur_virt_dst = (addr64_t) dst; | |
188 | cur_phys_src = (addr64_t) src; | |
189 | ||
190 | while (resid != 0) { | |
0a7de745 | 191 | if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0) { |
5ba3f43e | 192 | goto exit; |
0a7de745 | 193 | } |
5ba3f43e A |
194 | |
195 | /* Get length left on page */ | |
0a7de745 | 196 | |
5ba3f43e A |
197 | cnt_src = ARM_PGBYTES - (cur_phys_src & PAGE_MASK); |
198 | cnt_dst = ARM_PGBYTES - (cur_phys_dst & PAGE_MASK); | |
0a7de745 | 199 | if (cnt_src > cnt_dst) { |
5ba3f43e | 200 | cnt = cnt_dst; |
0a7de745 | 201 | } else { |
5ba3f43e | 202 | cnt = cnt_src; |
0a7de745 A |
203 | } |
204 | if (cnt > resid) { | |
5ba3f43e | 205 | cnt = resid; |
0a7de745 A |
206 | } |
207 | ||
208 | bcopy_phys(cur_phys_src, cur_phys_dst, cnt); /* Copy stuff over */ | |
5ba3f43e A |
209 | cur_phys_src += cnt; |
210 | cur_virt_dst += cnt; | |
211 | resid -= cnt; | |
212 | } | |
213 | ||
214 | exit: | |
0a7de745 | 215 | return len - resid; |
5ba3f43e A |
216 | } |
217 | ||
218 | /* | |
219 | * kdp_vm_write | |
220 | */ | |
221 | mach_vm_size_t | |
222 | kdp_machine_vm_write( caddr_t src, mach_vm_address_t dst, mach_vm_size_t len) | |
223 | { | |
224 | addr64_t cur_virt_src, cur_virt_dst; | |
225 | addr64_t cur_phys_src, cur_phys_dst; | |
226 | mach_vm_size_t resid, cnt, cnt_src, cnt_dst; | |
227 | ||
228 | #ifdef KDP_VM_WRITE_DEBUG | |
229 | printf("kdp_vm_write: src %x dst %x len %x - %08X %08X\n", src, dst, len, ((unsigned long *) src)[0], ((unsigned long *) src)[1]); | |
230 | #endif | |
231 | ||
232 | cur_virt_src = (addr64_t) src; | |
233 | cur_virt_dst = (addr64_t) dst; | |
234 | ||
235 | resid = len; | |
236 | ||
237 | while (resid != 0) { | |
0a7de745 | 238 | if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0) { |
5ba3f43e | 239 | goto exit; |
0a7de745 | 240 | } |
5ba3f43e | 241 | |
0a7de745 | 242 | if ((cur_phys_src = kdp_vtophys(kernel_pmap, cur_virt_src)) == 0) { |
5ba3f43e | 243 | goto exit; |
0a7de745 | 244 | } |
5ba3f43e A |
245 | |
246 | /* Attempt to ensure that there are valid translations for src and dst. */ | |
247 | /* No support for enabling writes for an invalid translation at the moment. */ | |
0a7de745 | 248 | if ((!pmap_valid_address(cur_phys_dst)) || (!pmap_valid_address(cur_phys_src))) { |
5ba3f43e | 249 | goto exit; |
0a7de745 | 250 | } |
5ba3f43e A |
251 | |
252 | cnt_src = ((cur_phys_src + ARM_PGBYTES) & (-ARM_PGBYTES)) - cur_phys_src; | |
253 | cnt_dst = ((cur_phys_dst + ARM_PGBYTES) & (-ARM_PGBYTES)) - cur_phys_dst; | |
254 | ||
0a7de745 | 255 | if (cnt_src > cnt_dst) { |
5ba3f43e | 256 | cnt = cnt_dst; |
0a7de745 | 257 | } else { |
5ba3f43e | 258 | cnt = cnt_src; |
0a7de745 A |
259 | } |
260 | if (cnt > resid) { | |
5ba3f43e | 261 | cnt = resid; |
0a7de745 | 262 | } |
5ba3f43e A |
263 | |
264 | #ifdef KDP_VM_WRITE_DEBUG | |
265 | printf("kdp_vm_write: cur_phys_src %x cur_phys_src %x len %x - %08X %08X\n", src, dst, cnt); | |
266 | #endif | |
0a7de745 | 267 | bcopy_phys(cur_phys_src, cur_phys_dst, cnt); /* Copy stuff over */ |
5ba3f43e A |
268 | flush_dcache64(cur_phys_dst, (unsigned int)cnt, TRUE); |
269 | invalidate_icache64(cur_phys_dst, (unsigned int)cnt, TRUE); | |
270 | ||
271 | cur_virt_src += cnt; | |
272 | cur_virt_dst += cnt; | |
273 | resid -= cnt; | |
274 | } | |
275 | exit: | |
0a7de745 | 276 | return len - resid; |
5ba3f43e A |
277 | } |
278 | ||
279 | mach_vm_size_t | |
280 | kdp_machine_phys_write(kdp_writephysmem64_req_t *rq __unused, caddr_t src __unused, | |
0a7de745 | 281 | uint16_t lcpu __unused) |
5ba3f43e | 282 | { |
0a7de745 | 283 | return 0; /* unimplemented */ |
5ba3f43e A |
284 | } |
285 | ||
286 | void | |
287 | kern_collectth_state_size(uint64_t * tstate_count, uint64_t * tstate_size) | |
288 | { | |
0a7de745 | 289 | uint64_t count = ml_get_max_cpu_number() + 1; |
5ba3f43e | 290 | |
0a7de745 A |
291 | *tstate_count = count; |
292 | *tstate_size = sizeof(struct thread_command) | |
293 | + (sizeof(arm_state_hdr_t) | |
5ba3f43e | 294 | #if defined(__arm64__) |
0a7de745 | 295 | + ARM_THREAD_STATE64_COUNT * sizeof(uint32_t)); |
5ba3f43e | 296 | #else |
0a7de745 | 297 | + ARM_THREAD_STATE32_COUNT * sizeof(uint32_t)); |
5ba3f43e A |
298 | #endif |
299 | } | |
300 | ||
301 | void | |
302 | kern_collectth_state(thread_t thread __unused, void *buffer, uint64_t size, void ** iter) | |
303 | { | |
0a7de745 A |
304 | cpu_data_entry_t *cpuentryp = *iter; |
305 | if (cpuentryp == NULL) { | |
306 | cpuentryp = &CpuDataEntries[0]; | |
307 | } | |
5ba3f43e | 308 | |
0a7de745 A |
309 | if (cpuentryp == &CpuDataEntries[ml_get_max_cpu_number()]) { |
310 | *iter = NULL; | |
311 | } else { | |
312 | *iter = cpuentryp + 1; | |
313 | } | |
5ba3f43e | 314 | |
0a7de745 | 315 | struct cpu_data *cpudatap = cpuentryp->cpu_data_vaddr; |
5ba3f43e | 316 | |
0a7de745 A |
317 | struct thread_command *tc = (struct thread_command *)buffer; |
318 | arm_state_hdr_t *hdr = (arm_state_hdr_t *)(void *)(tc + 1); | |
5ba3f43e | 319 | #if defined(__arm64__) |
0a7de745 A |
320 | hdr->flavor = ARM_THREAD_STATE64; |
321 | hdr->count = ARM_THREAD_STATE64_COUNT; | |
322 | arm_thread_state64_t *state = (arm_thread_state64_t *)(void *)(hdr + 1); | |
5ba3f43e | 323 | #else |
0a7de745 A |
324 | hdr->flavor = ARM_THREAD_STATE; |
325 | hdr->count = ARM_THREAD_STATE_COUNT; | |
326 | arm_thread_state_t *state = (arm_thread_state_t *)(void *)(hdr + 1); | |
5ba3f43e A |
327 | #endif |
328 | ||
0a7de745 A |
329 | tc->cmd = LC_THREAD; |
330 | tc->cmdsize = (uint32_t) size; | |
5ba3f43e | 331 | |
0a7de745 A |
332 | if ((cpudatap != NULL) && (cpudatap->halt_status == CPU_HALTED_WITH_STATE)) { |
333 | *state = cpudatap->halt_state; | |
334 | return; | |
335 | } | |
5ba3f43e | 336 | |
0a7de745 A |
337 | if ((cpudatap == NULL) || (cpudatap->cpu_processor == NULL) || (cpudatap->cpu_processor->active_thread == NULL)) { |
338 | bzero(state, hdr->count * sizeof(uint32_t)); | |
339 | return; | |
340 | } | |
5ba3f43e | 341 | |
0a7de745 A |
342 | vm_offset_t kstackptr = (vm_offset_t) cpudatap->cpu_processor->active_thread->machine.kstackptr; |
343 | arm_saved_state_t *saved_state = (arm_saved_state_t *) kstackptr; | |
5ba3f43e A |
344 | |
345 | #if defined(__arm64__) | |
346 | ||
0a7de745 A |
347 | state->fp = saved_state->ss_64.fp; |
348 | state->lr = saved_state->ss_64.lr; | |
349 | state->sp = saved_state->ss_64.sp; | |
350 | state->pc = saved_state->ss_64.pc; | |
351 | state->cpsr = saved_state->ss_64.cpsr; | |
352 | bcopy(&saved_state->ss_64.x[0], &state->x[0], sizeof(state->x)); | |
5ba3f43e A |
353 | |
354 | #else /* __arm64__ */ | |
355 | ||
0a7de745 A |
356 | state->lr = saved_state->lr; |
357 | state->sp = saved_state->sp; | |
358 | state->pc = saved_state->pc; | |
359 | state->cpsr = saved_state->cpsr; | |
360 | bcopy(&saved_state->r[0], &state->r[0], sizeof(state->r)); | |
5ba3f43e A |
361 | |
362 | #endif /* !__arm64__ */ | |
5ba3f43e | 363 | } |