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