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