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