]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kdp/ml/ppc/kdp_vm.c
xnu-1228.tar.gz
[apple/xnu.git] / osfmk / kdp / ml / ppc / kdp_vm.c
1 /*
2 * Copyright (c) 2000-2006 Apple Computer, 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 <ppc/proc_reg.h>
35 #include <ppc/machparam.h>
36 #include <ppc/mem.h>
37 #include <ppc/pmap.h>
38 #include <ppc/mappings.h>
39 #include <ppc/cpu_data.h>
40 #include <ppc/misc_protos.h>
41
42 #include <mach/thread_status.h>
43 #include <mach-o/loader.h>
44 #include <mach/vm_region.h>
45 #include <mach/vm_statistics.h>
46
47 #include <vm/vm_kern.h>
48 #include <vm/vm_object.h>
49 #include <vm/vm_protos.h>
50 #include <kdp/kdp_core.h>
51 #include <kdp/kdp_udp.h>
52 #include <kdp/kdp_internal.h>
53
54 #include <ppc/misc_protos.h>
55 #include <mach/vm_map.h>
56
57
58 pmap_t kdp_pmap;
59 boolean_t kdp_trans_off;
60 boolean_t kdp_read_io;
61 uint32_t kdp_src_high32;
62
63 unsigned kdp_vm_read( caddr_t, caddr_t, unsigned);
64 unsigned kdp_vm_write( caddr_t, caddr_t, unsigned);
65
66 extern vm_offset_t sectTEXTB, sectDATAB, sectLINKB, sectPRELINKB;
67 extern int sectSizeTEXT, sectSizeDATA, sectSizeLINK, sectSizePRELINK;
68
69 static addr64_t kdp_vtophys(pmap_t pmap, addr64_t va);
70 int kern_dump(void);
71
72 typedef struct {
73 int flavor; /* the number for this flavor */
74 mach_msg_type_number_t count; /* count of ints in this flavor */
75 } mythread_state_flavor_t;
76
77 static mythread_state_flavor_t thread_flavor_array[] = {
78 {PPC_THREAD_STATE , PPC_THREAD_STATE_COUNT},
79 };
80
81 static int kdp_mynum_flavors = 1;
82 static int MAX_TSTATE_FLAVORS = 1;
83
84 typedef struct {
85 vm_offset_t header;
86 int hoffset;
87 mythread_state_flavor_t *flavors;
88 int tstate_size;
89 } tir_t;
90
91 unsigned int not_in_kdp = 1; /* Cleared when we begin to access vm functions in kdp */
92
93 char command_buffer[512];
94
95 /*
96 *
97 */
98 static addr64_t
99 kdp_vtophys(
100 pmap_t pmap,
101 addr64_t va)
102 {
103 addr64_t pa;
104 ppnum_t pp;
105
106 pp = pmap_find_phys(pmap, va); /* Get the page number */
107 if(!pp) return 0; /* Just return if no translation */
108
109 pa = ((addr64_t)pp << 12) | (va & 0x0000000000000FFFULL); /* Shove in the page offset */
110 return(pa);
111 }
112 /* Verify that src is valid, and physically copy len bytes from src to
113 * dst, translating if necessary. If translation is enabled
114 * (kdp_trans_off is 0), a non-zero kdp_pmap specifies the pmap to use
115 * when translating src.
116 */
117
118 unsigned kdp_vm_read(
119 caddr_t src,
120 caddr_t dst,
121 unsigned len)
122 {
123 addr64_t cur_virt_src, cur_virt_dst;
124 addr64_t cur_phys_src, cur_phys_dst;
125 unsigned resid, cnt;
126 unsigned int dummy;
127 pmap_t pmap;
128
129 #ifdef KDP_VM_READ_DEBUG
130 kprintf("kdp_vm_read1: src %x dst %x len %x - %08X %08X\n", src, dst, len, ((unsigned long *)src)[0], ((unsigned long *)src)[1]);
131 #endif
132
133 cur_virt_src = (addr64_t)((unsigned int)src | (((uint64_t)kdp_src_high32) << 32));
134 cur_virt_dst = (addr64_t)((unsigned int)dst);
135
136 if (kdp_trans_off) {
137 resid = len; /* Get the length to copy */
138
139 while (resid != 0) {
140
141 if((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0)
142 goto exit;
143
144 if(kdp_read_io == 0)
145 if(!mapping_phys_lookup((ppnum_t)(cur_virt_src >> 12), &dummy)) return 0; /* Can't read where there's not any memory */
146
147 cnt = 4096 - (cur_virt_src & 0xFFF); /* Get length left on page */
148 if (cnt > (4096 - (cur_virt_dst & 0xFFF)))
149 cnt = 4096 - (cur_virt_dst & 0xFFF);
150
151 if (cnt > resid) cnt = resid;
152
153 bcopy_phys(cur_virt_src, cur_phys_dst, cnt); /* Copy stuff over */
154
155 cur_virt_src += cnt;
156 cur_virt_dst += cnt;
157 resid -= cnt;
158 }
159
160 } else {
161
162 resid = len;
163
164 if(kdp_pmap) pmap = kdp_pmap; /* If special pmap, use it */
165 else pmap = kernel_pmap; /* otherwise, use kernel's */
166
167 while (resid != 0) {
168 /* Always translate the destination using the kernel_pmap. */
169 if((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0)
170 goto exit;
171
172 if((cur_phys_src = kdp_vtophys(pmap, cur_virt_src)) == 0)
173 goto exit;
174
175 if(kdp_read_io == 0)
176 if(!mapping_phys_lookup((ppnum_t)(cur_phys_src >> 12), &dummy)) goto exit; /* Can't read where there's not any memory */
177
178 cnt = 4096 - (cur_virt_src & 0xFFF); /* Get length left on page */
179 if (cnt > (4096 - (cur_virt_dst & 0xFFF)))
180 cnt = 4096 - (cur_virt_dst & 0xFFF);
181
182 if (cnt > resid) cnt = resid;
183
184 #ifdef KDP_VM_READ_DEBUG
185 kprintf("kdp_vm_read2: pmap %08X, virt %016LLX, phys %016LLX\n",
186 pmap, cur_virt_src, cur_phys_src);
187 #endif
188
189 bcopy_phys(cur_phys_src, cur_phys_dst, cnt); /* Copy stuff over */
190
191 cur_virt_src +=cnt;
192 cur_virt_dst +=cnt;
193 resid -= cnt;
194 }
195 }
196 exit:
197 #ifdef KDP_VM_READ_DEBUG
198 kprintf("kdp_vm_read: ret %08X\n", len-resid);
199 #endif
200 return (len - resid);
201 }
202
203 /*
204 *
205 */
206 unsigned kdp_vm_write(
207 caddr_t src,
208 caddr_t dst,
209 unsigned len)
210 {
211 addr64_t cur_virt_src, cur_virt_dst;
212 addr64_t cur_phys_src, cur_phys_dst;
213 unsigned resid, cnt, cnt_src, cnt_dst;
214
215 #ifdef KDP_VM_WRITE_DEBUG
216 printf("kdp_vm_write: src %x dst %x len %x - %08X %08X\n", src, dst, len, ((unsigned long *)src)[0], ((unsigned long *)src)[1]);
217 #endif
218
219 cur_virt_src = (addr64_t)((unsigned int)src);
220 cur_virt_dst = (addr64_t)((unsigned int)dst);
221
222 resid = len;
223
224 while (resid != 0) {
225 if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0)
226 goto exit;
227
228 if ((cur_phys_src = kdp_vtophys(kernel_pmap, cur_virt_src)) == 0)
229 goto exit;
230
231 cnt_src = ((cur_phys_src + NBPG) & (-NBPG)) - cur_phys_src;
232 cnt_dst = ((cur_phys_dst + NBPG) & (-NBPG)) - cur_phys_dst;
233
234 if (cnt_src > cnt_dst)
235 cnt = cnt_dst;
236 else
237 cnt = cnt_src;
238 if (cnt > resid)
239 cnt = resid;
240
241 bcopy_phys(cur_phys_src, cur_phys_dst, cnt); /* Copy stuff over */
242 sync_cache64(cur_phys_dst, cnt); /* Sync caches */
243
244 cur_virt_src +=cnt;
245 cur_virt_dst +=cnt;
246 resid -= cnt;
247 }
248 exit:
249 return (len - resid);
250 }
251
252
253 static void
254 kern_collectth_state(thread_t thread, tir_t *t)
255 {
256 vm_offset_t header;
257 int hoffset, i ;
258 mythread_state_flavor_t *flavors;
259 struct thread_command *tc;
260 /*
261 * Fill in thread command structure.
262 */
263 header = t->header;
264 hoffset = t->hoffset;
265 flavors = t->flavors;
266
267 tc = (struct thread_command *) (header + hoffset);
268 tc->cmd = LC_THREAD;
269 tc->cmdsize = sizeof(struct thread_command)
270 + t->tstate_size;
271 hoffset += sizeof(struct thread_command);
272 /*
273 * Follow with a struct thread_state_flavor and
274 * the appropriate thread state struct for each
275 * thread state flavor.
276 */
277 for (i = 0; i < kdp_mynum_flavors; i++) {
278 *(mythread_state_flavor_t *)(header+hoffset) =
279 flavors[i];
280 hoffset += sizeof(mythread_state_flavor_t);
281
282 if (machine_thread_get_kern_state(thread, flavors[i].flavor,
283 (thread_state_t) (header+hoffset),
284 &flavors[i].count) != KERN_SUCCESS)
285 printf ("Failure in machine_thread_get_kern_state()\n");
286 hoffset += flavors[i].count*sizeof(int);
287 }
288
289 t->hoffset = hoffset;
290 }
291
292 int
293 kdp_dump_trap(
294 int type,
295 __unused struct savearea *regs)
296 {
297 printf ("An unexpected trap (type %d) occurred during the kernel dump, terminating.\n", type);
298 kdp_send_crashdump_pkt(KDP_EOF, NULL, 0, ((void *) 0));
299 abort_panic_transfer();
300 kdp_flag &= ~KDP_PANIC_DUMP_ENABLED;
301 kdp_flag &= ~PANIC_CORE_ON_NMI;
302 kdp_flag &= ~PANIC_LOG_DUMP;
303
304 kdp_reset();
305
306 kdp_raise_exception(EXC_BAD_ACCESS, 0, 0, kdp.saved_state);
307 return( 0 );
308 }
309
310 /*
311 * Kernel dump (limited to currently executing 32 bit mach_kernel only)
312 */
313 int
314 kern_dump(void)
315 {
316 int error = 0;
317 vm_map_t map;
318 unsigned int thread_count, segment_count;
319 unsigned int command_size = 0, header_size = 0, tstate_size = 0;
320 unsigned int hoffset = 0, foffset = 0, nfoffset = 0, vmoffset = 0;
321 unsigned int max_header_size = 0;
322 vm_offset_t header;
323 struct mach_header *mh;
324 struct segment_command *sc;
325 vm_size_t size;
326 vm_prot_t prot = 0;
327 vm_prot_t maxprot = 0;
328 vm_inherit_t inherit = 0;
329 int error1 = 0;
330 mythread_state_flavor_t flavors[MAX_TSTATE_FLAVORS];
331 vm_size_t nflavors;
332 vm_size_t i;
333 uint32_t nesting_depth = 0;
334 kern_return_t kret = 0;
335 struct vm_region_submap_info_64 vbr;
336 mach_msg_type_number_t vbrcount = 0;
337 tir_t tir1;
338
339 int panic_error = 0;
340 unsigned int txstart = 0;
341 unsigned int mach_section_count = 4;
342 unsigned int num_sects_txed = 0;
343
344 map = kernel_map;
345 not_in_kdp = 0; /* Tell vm functions not to acquire locks */
346
347 thread_count = 1;
348 segment_count = get_vmmap_entries(map);
349
350 printf("Kernel map has %d entries\n", segment_count);
351
352 nflavors = kdp_mynum_flavors;
353 bcopy((char *)thread_flavor_array,(char *) flavors,sizeof(thread_flavor_array));
354
355 for (i = 0; i < nflavors; i++)
356 tstate_size += sizeof(mythread_state_flavor_t) +
357 (flavors[i].count * sizeof(int));
358
359 command_size = (segment_count + mach_section_count) *
360 sizeof(struct segment_command) +
361 thread_count*sizeof(struct thread_command) +
362 tstate_size*thread_count;
363
364 header_size = command_size + sizeof(struct mach_header);
365 header = (vm_offset_t) command_buffer;
366
367 /*
368 * Set up Mach-O header for currently executing 32 bit kernel.
369 */
370 printf ("Generated Mach-O header size was %d\n", header_size);
371
372 mh = (struct mach_header *) header;
373 mh->magic = MH_MAGIC;
374 mh->cputype = cpu_type();
375 mh->cpusubtype = cpu_subtype(); /* XXX incorrect; should match kernel */
376 mh->filetype = MH_CORE;
377 mh->ncmds = segment_count + thread_count + mach_section_count;
378 mh->sizeofcmds = command_size;
379 mh->flags = 0;
380
381 hoffset = sizeof(struct mach_header); /* offset into header */
382 foffset = round_page_32(header_size); /* offset into file */
383 /* Padding.. */
384 if ((foffset - header_size) < (4*sizeof(struct segment_command))) {
385 /* Hack */
386 foffset += ((4*sizeof(struct segment_command)) - (foffset-header_size));
387 }
388
389 max_header_size = foffset;
390
391 vmoffset = VM_MIN_ADDRESS; /* offset into VM */
392
393 /* Transmit the Mach-O MH_CORE header, and seek forward past the
394 * area reserved for the segment and thread commands
395 * to begin data transmission
396 */
397
398 if ((panic_error = kdp_send_crashdump_pkt(KDP_SEEK, NULL, sizeof(nfoffset) , &nfoffset)) < 0) {
399 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
400 return -1;
401 }
402
403 if ((panic_error = kdp_send_crashdump_data(KDP_DATA, NULL, sizeof(struct mach_header), (caddr_t) mh) < 0)) {
404 printf ("kdp_send_crashdump_data failed with error %d\n", panic_error);
405 return -1 ;
406 }
407
408 if ((panic_error = kdp_send_crashdump_pkt(KDP_SEEK, NULL, sizeof(foffset) , &foffset) < 0)) {
409 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
410 return (-1);
411 }
412 printf ("Transmitting kernel state, please wait: ");
413
414 while ((segment_count > 0) || (kret == KERN_SUCCESS)){
415 /* Check if we've transmitted all the kernel sections */
416 if (num_sects_txed == mach_section_count) {
417
418 while (1) {
419
420 /*
421 * Get region information for next region.
422 */
423
424 vbrcount = VM_REGION_SUBMAP_INFO_COUNT_64;
425 if((kret = vm_region_recurse_64(map,
426 &vmoffset, &size, &nesting_depth,
427 (vm_region_recurse_info_t)&vbr,
428 &vbrcount)) != KERN_SUCCESS) {
429 break;
430 }
431
432 if(vbr.is_submap) {
433 nesting_depth++;
434 continue;
435 } else {
436 break;
437 }
438 }
439
440 if(kret != KERN_SUCCESS)
441 break;
442
443 prot = vbr.protection;
444 maxprot = vbr.max_protection;
445 inherit = vbr.inheritance;
446 }
447 else
448 {
449 switch (num_sects_txed) {
450 case 0:
451 {
452 /* Transmit the kernel text section */
453 vmoffset = sectTEXTB;
454 size = sectSizeTEXT;
455 }
456 break;
457 case 1:
458 {
459 vmoffset = sectDATAB;
460 size = sectSizeDATA;
461 }
462 break;
463 case 2:
464 {
465 vmoffset = sectPRELINKB;
466 size = sectSizePRELINK;
467 }
468 break;
469 case 3:
470 {
471 vmoffset = sectLINKB;
472 size = sectSizeLINK;
473 }
474 break;
475 /* TODO the lowmem vector area may be useful, but its transmission is
476 * disabled for now. The traceback table area should be transmitted
477 * as well - that's indirected from 0x5080.
478 */
479 }
480 num_sects_txed++;
481 }
482 /*
483 * Fill in segment command structure.
484 */
485
486 if (hoffset > max_header_size)
487 break;
488 sc = (struct segment_command *) (header);
489 sc->cmd = LC_SEGMENT;
490 sc->cmdsize = sizeof(struct segment_command);
491 sc->segname[0] = 0;
492 sc->vmaddr = vmoffset;
493 sc->vmsize = size;
494 sc->fileoff = foffset;
495 sc->filesize = size;
496 sc->maxprot = maxprot;
497 sc->initprot = prot;
498 sc->nsects = 0;
499
500 if ((panic_error = kdp_send_crashdump_pkt(KDP_SEEK, NULL, sizeof(hoffset) , &hoffset)) < 0) {
501 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
502 return -1;
503 }
504
505 if ((panic_error = kdp_send_crashdump_data(KDP_DATA, NULL, sizeof(struct segment_command) , (caddr_t) sc)) < 0) {
506 printf ("kdp_send_crashdump_data failed with error %d\n", panic_error);
507 return -1 ;
508 }
509
510 /* Do not transmit memory tagged VM_MEMORY_IOKIT - instead, seek past that
511 * region on the server - this creates a hole in the file
512 */
513
514 if ((vbr.user_tag != VM_MEMORY_IOKIT)) {
515
516 if ((panic_error = kdp_send_crashdump_pkt(KDP_SEEK, NULL, sizeof(foffset) , &foffset)) < 0) {
517 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
518 return (-1);
519 }
520
521 txstart = vmoffset;
522
523 if ((panic_error = kdp_send_crashdump_data(KDP_DATA, NULL, size, (caddr_t) txstart)) < 0) {
524 printf ("kdp_send_crashdump_data failed with error %d\n", panic_error);
525 return -1 ;
526 }
527 }
528
529 hoffset += sizeof(struct segment_command);
530 foffset += size;
531 vmoffset += size;
532 segment_count--;
533 }
534 tir1.header = header;
535 tir1.hoffset = 0;
536 tir1.flavors = flavors;
537 tir1.tstate_size = tstate_size;
538
539 /* Now send out the LC_THREAD load command, with the thread information
540 * for the current activation.
541 * Note that the corefile can contain LC_SEGMENT commands with file offsets
542 * that point past the edge of the corefile, in the event that the last N
543 * VM regions were all I/O mapped or otherwise non-transferable memory,
544 * not followed by a normal VM region; i.e. there will be no hole that
545 * reaches to the end of the core file.
546 */
547 kern_collectth_state (current_thread(), &tir1);
548
549 if ((panic_error = kdp_send_crashdump_pkt(KDP_SEEK, NULL, sizeof(hoffset) , &hoffset)) < 0) {
550 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
551 return -1;
552 }
553
554 if ((panic_error = kdp_send_crashdump_data(KDP_DATA, NULL, tir1.hoffset , (caddr_t) header)) < 0) {
555 printf ("kdp_send_crashdump_data failed with error %d\n", panic_error);
556 return -1 ;
557 }
558
559 /* last packet */
560 if ((panic_error = kdp_send_crashdump_pkt(KDP_EOF, NULL, 0, ((void *) 0))) < 0)
561 {
562 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
563 return (-1) ;
564 }
565
566 if (error == 0)
567 error = error1;
568 return (error);
569 }