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