]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kdp/ml/ppc/kdp_vm.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / osfmk / kdp / ml / ppc / kdp_vm.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
ff6e181a
A
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.
1c79356b 12 *
ff6e181a
A
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
1c79356b
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
ff6e181a
A
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.
1c79356b
A
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>
1c79356b 33#include <ppc/mappings.h>
91447636 34#include <ppc/cpu_data.h>
1c79356b 35
55e303ae
A
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>
91447636
A
42#include <vm/vm_object.h>
43#include <vm/vm_protos.h>
55e303ae
A
44#include <kdp/kdp_core.h>
45#include <kdp/kdp_udp.h>
46#include <kdp/kdp_internal.h>
47
91447636
A
48#include <ppc/misc_protos.h>
49#include <mach/vm_map.h>
50
55e303ae 51
1c79356b
A
52pmap_t kdp_pmap=0;
53boolean_t kdp_trans_off=0;
55e303ae 54boolean_t kdp_read_io =0;
1c79356b 55
1c79356b
A
56unsigned kdp_vm_read( caddr_t, caddr_t, unsigned);
57unsigned kdp_vm_write( caddr_t, caddr_t, unsigned);
58
91447636
A
59extern vm_offset_t sectTEXTB, sectDATAB, sectLINKB, sectPRELINKB;
60extern int sectSizeTEXT, sectSizeDATA, sectSizeLINK, sectSizePRELINK;
61
62/* XXX prototypes which should be in a commmon header file */
63addr64_t kdp_vtophys(pmap_t pmap, addr64_t va);
64int kern_dump(void);
65int 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 */
70extern int kdp_send_panic_packets(unsigned int request, char *corename,
71 unsigned int length, caddr_t txstart);
72
73
74
1c79356b 75
55e303ae
A
76typedef struct {
77 int flavor; /* the number for this flavor */
78 int count; /* count of ints in this flavor */
79} mythread_state_flavor_t;
de355530 80
55e303ae
A
81/* These will need to be uncommented and completed
82 *if we support other architectures
83 */
de355530 84
55e303ae
A
85/*
86#if defined (__ppc__)
87*/
88static mythread_state_flavor_t thread_flavor_array[] = {
89 {PPC_THREAD_STATE , PPC_THREAD_STATE_COUNT},
90};
91/*
92#elif defined (__i386__)
93mythread_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*/
100static int kdp_mynum_flavors = 1;
101static int MAX_TSTATE_FLAVORS = 1;
de355530 102
55e303ae
A
103typedef struct {
104 vm_offset_t header;
105 int hoffset;
106 mythread_state_flavor_t *flavors;
107 int tstate_size;
108} tir_t;
de355530 109
55e303ae 110unsigned int not_in_kdp = 1; /* Cleared when we begin to access vm functions in kdp */
de355530 111
55e303ae 112char command_buffer[512];
1c79356b 113
91447636 114// XXX static struct vm_object test_object;
1c79356b 115
de355530
A
116/*
117 *
118 */
91447636
A
119addr64_t
120kdp_vtophys(
55e303ae
A
121 pmap_t pmap,
122 addr64_t va)
de355530 123{
55e303ae
A
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);
de355530 132}
91447636
A
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.
1c79356b 137 */
91447636 138
1c79356b
A
139unsigned kdp_vm_read(
140 caddr_t src,
141 caddr_t dst,
142 unsigned len)
143{
55e303ae 144 addr64_t cur_virt_src, cur_virt_dst;
91447636 145 addr64_t cur_phys_src, cur_phys_dst;
1c79356b 146 unsigned resid, cnt;
55e303ae
A
147 unsigned int dummy;
148 pmap_t pmap;
1c79356b
A
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
55e303ae
A
153
154 cur_virt_src = (addr64_t)((unsigned int)src);
155 cur_virt_dst = (addr64_t)((unsigned int)dst);
156
1c79356b 157 if (kdp_trans_off) {
55e303ae
A
158
159
160 resid = len; /* Get the length to copy */
1c79356b
A
161
162 while (resid != 0) {
55e303ae 163
91447636
A
164 if((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0)
165 goto exit;
166
55e303ae
A
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 */
91447636
A
171 if (cnt > (4096 - (cur_virt_dst & 0xFFF)))
172 cnt = 4096 - (cur_virt_dst & 0xFFF);
55e303ae 173
1c79356b 174 if (cnt > resid) cnt = resid;
55e303ae 175
91447636 176 bcopy_phys(cur_virt_src, cur_phys_dst, cnt); /* Copy stuff over */
55e303ae
A
177
178 cur_virt_src += cnt;
179 cur_virt_dst += cnt;
1c79356b
A
180 resid -= cnt;
181 }
55e303ae 182
1c79356b 183 } else {
55e303ae 184
1c79356b
A
185 resid = len;
186
55e303ae
A
187 if(kdp_pmap) pmap = kdp_pmap; /* If special pmap, use it */
188 else pmap = kernel_pmap; /* otherwise, use kernel's */
189
1c79356b 190 while (resid != 0) {
91447636
A
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;
55e303ae 197
55e303ae
A
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 */
91447636
A
202 if (cnt > (4096 - (cur_virt_dst & 0xFFF)))
203 cnt = 4096 - (cur_virt_dst & 0xFFF);
204
1c79356b 205 if (cnt > resid) cnt = resid;
55e303ae 206
1c79356b 207#ifdef KDP_VM_READ_DEBUG
55e303ae
A
208 kprintf("kdp_vm_read2: pmap %08X, virt %016LLX, phys %016LLX\n",
209 pmap, cur_virt_src, cur_phys_src);
1c79356b 210#endif
55e303ae 211
91447636 212 bcopy_phys(cur_phys_src, cur_phys_dst, cnt); /* Copy stuff over */
55e303ae 213
1c79356b
A
214 cur_virt_src +=cnt;
215 cur_virt_dst +=cnt;
216 resid -= cnt;
217 }
218 }
219exit:
220#ifdef KDP_VM_READ_DEBUG
221 kprintf("kdp_vm_read: ret %08X\n", len-resid);
222#endif
55e303ae 223 return (len - resid);
1c79356b
A
224}
225
226/*
227 *
228 */
229unsigned kdp_vm_write(
230 caddr_t src,
231 caddr_t dst,
232 unsigned len)
233{
55e303ae
A
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;
1c79356b
A
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
55e303ae
A
242 cur_virt_src = (addr64_t)((unsigned int)src);
243 cur_virt_dst = (addr64_t)((unsigned int)dst);
244
1c79356b
A
245 resid = len;
246
247 while (resid != 0) {
248 if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0)
249 goto exit;
91447636 250
1c79356b
A
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
55e303ae
A
264 bcopy_phys(cur_phys_src, cur_phys_dst, cnt); /* Copy stuff over */
265 sync_cache64(cur_phys_dst, cnt); /* Sync caches */
1c79356b
A
266
267 cur_virt_src +=cnt;
268 cur_virt_dst +=cnt;
269 resid -= cnt;
270 }
271exit:
55e303ae
A
272 return (len - resid);
273}
274
275
276static void
91447636 277kern_collectth_state(thread_t thread, tir_t *t)
55e303ae
A
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
91447636 305 if (machine_thread_get_kern_state(thread, flavors[i].flavor,
55e303ae
A
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;
1c79356b
A
313}
314
55e303ae
A
315int
316kdp_dump_trap(
317 int type,
91447636 318 __unused struct savearea *regs)
55e303ae 319{
55e303ae
A
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);
91447636 330 return( 0 );
55e303ae
A
331}
332
91447636
A
333/*
334 * Kernel dump (limited to currently executing 32 bit mach_kernel only)
335 */
55e303ae 336int
91447636 337kern_dump(void)
55e303ae
A
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;
55e303ae
A
346 struct mach_header *mh;
347 struct segment_command *sc;
55e303ae
A
348 vm_size_t size;
349 vm_prot_t prot = 0;
350 vm_prot_t maxprot = 0;
351 vm_inherit_t inherit = 0;
91447636 352 int error1 = 0;
55e303ae
A
353 mythread_state_flavor_t flavors[MAX_TSTATE_FLAVORS];
354 vm_size_t nflavors;
91447636 355 vm_size_t i;
55e303ae 356 int nesting_depth = 0;
91447636 357 kern_return_t kret = 0;
55e303ae
A
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
55e303ae
A
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 /*
91447636 391 * Set up Mach-O header for currently executing 32 bit kernel.
55e303ae
A
392 */
393 printf ("Generated Mach-O header size was %d\n", header_size);
394
395 mh = (struct mach_header *) header;
55e303ae 396 mh->magic = MH_MAGIC;
91447636
A
397 mh->cputype = cpu_type();
398 mh->cpusubtype = cpu_subtype(); /* XXX incorrect; should match kernel */
55e303ae
A
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,
91447636
A
450 (vm_region_recurse_info_t)&vbr,
451 &vbrcount)) != KERN_SUCCESS) {
55e303ae
A
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 */
91447636 570 kern_collectth_state (current_thread(), &tir1);
55e303ae
A
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
55e303ae
A
589 if (error == 0)
590 error = error1;
591 return (error);
592}