+
+errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
+ struct vnode *srcVp,
+ vfs_context_t srcCtx,
+ char *tmpBuf, uint64_t tmpBufSize,
+ uint64_t srcOffset,
+ const char *dstFname,
+ uint64_t numBytes,
+ uint32_t crc)
+{
+ struct vnode *vp = NULL;
+ vfs_context_t ctx = vfs_context_create(vfs_context_current());
+ struct vnode_attr va;
+ errno_t error = EIO;
+ uint64_t bytesToRead, bytesToWrite;
+ uint64_t readFileOffset, writeFileOffset, srcDataOffset;
+ uint32_t newcrc = 0;
+
+ if (vnode_open(dstFname, (O_CREAT | FWRITE | O_NOFOLLOW),
+ S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
+ {
+ DLOG("Failed to open the file %s\n", dstFname);
+ goto exit;
+ }
+ VATTR_INIT(&va);
+ VATTR_WANTED(&va, va_nlink);
+ /* Don't dump to non-regular files or files with links. */
+ if (vp->v_type != VREG ||
+ vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
+ DLOG("Bailing as this is not a regular file\n");
+ goto exit;
+ }
+ VATTR_INIT(&va);
+ VATTR_SET(&va, va_data_size, 0);
+ vnode_setattr(vp, &va, ctx);
+
+ writeFileOffset = 0;
+ while(numBytes) {
+ bytesToRead = (round_page(numBytes) > tmpBufSize) ? tmpBufSize : round_page(numBytes);
+ readFileOffset = trunc_page(srcOffset);
+
+ DLOG("Read file (numBytes:0x%llx)\n", bytesToRead);
+ error = vn_rdwr(UIO_READ, srcVp, tmpBuf, bytesToRead, readFileOffset,
+ UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
+ vfs_context_ucred(srcCtx), (int *) 0,
+ vfs_context_proc(srcCtx));
+ if (error) {
+ DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead);
+ break;
+ }
+
+ srcDataOffset = (uint64_t)tmpBuf + (srcOffset - readFileOffset);
+ bytesToWrite = bytesToRead - (srcOffset - readFileOffset);
+ if (bytesToWrite > numBytes) bytesToWrite = numBytes;
+
+ if (crc) {
+ newcrc = crc32(newcrc, (void *)srcDataOffset, bytesToWrite);
+ }
+ error = vn_rdwr(UIO_WRITE, vp, (char *)srcDataOffset, bytesToWrite, writeFileOffset,
+ UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
+ vfs_context_ucred(ctx), (int *) 0,
+ vfs_context_proc(ctx));
+ if (error) {
+ DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite);
+ break;
+ }
+
+ writeFileOffset += bytesToWrite;
+ numBytes -= bytesToWrite;
+ srcOffset += bytesToWrite;
+
+ }
+ if (crc != newcrc) {
+ swd_stackshot_hdr *shdr = (swd_stackshot_hdr *)tmpBuf;;
+
+ /* Set statckshot size to 0 if crc doesn't match */
+ shdr->magic = SWD_STACKSHOTHDR_MAGIC;
+ shdr->size = 0;
+
+ assert(tmpBufSize > sizeof(swd_stackshot_hdr));
+ bytesToWrite = round_page(sizeof(swd_stackshot_hdr));
+ vn_rdwr(UIO_WRITE, vp, (char *)tmpBuf, bytesToWrite, 0,
+ UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
+ vfs_context_ucred(ctx), (int *) 0,
+ vfs_context_proc(ctx));
+
+ DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc, newcrc);
+ error = EFAULT;
+ }
+exit:
+ if (vp) {
+ error = vnode_close(vp, FWRITE, ctx);
+ DLOG("vnode_close returned 0x%x\n", error);
+ }
+ if (ctx) vfs_context_rele(ctx);
+
+ return error;
+
+
+
+}
+
+void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
+{
+
+ int rc;
+ char hibernateFilename[MAXPATHLEN+1];
+ char PMStatusCode[100];
+ void *tmpBuf;
+ swd_hdr *hdr = NULL;
+ uint32_t stacksSize, logSize;
+ uint64_t tmpBufSize;
+ uint64_t hdrOffset, stacksOffset, logOffset;
+ errno_t error = EIO;
+ OSObject *obj = NULL;
+ OSString *str = NULL;
+ OSNumber *failStat = NULL;
+ struct vnode *vp = NULL;
+ vfs_context_t ctx = NULL;
+
+ struct vnode_attr va;
+ IOBufferMemoryDescriptor *tmpBufDesc = NULL;
+ IOHibernateImageHeader *imageHdr;
+
+ DLOG("sleepWakeDebugDumpFromFile\n");
+ if ((swd_flags & SWD_LOGS_IN_FILE) == 0)
+ return;
+
+ if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
+ return;
+
+
+ hibernateFilename[0] = 0;
+ if ((obj = copyProperty(kIOHibernateFileKey)))
+ {
+ if ((str = OSDynamicCast(OSString, obj)))
+ strlcpy(hibernateFilename, str->getCStringNoCopy(),
+ sizeof(hibernateFilename));
+ obj->release();
+ }
+ if (!hibernateFilename[0]) {
+ DMSG("sleepWakeDebugDumpFromFile: Failed to hib file name\n");
+ goto exit;
+ }
+ DLOG("sleepWakeDebugDumpFromFile: Hib file name %s\n", hibernateFilename);
+
+ /* Allocate a temp buffer to copy data between files */
+ tmpBufSize = 2*4096;
+ tmpBufDesc = IOBufferMemoryDescriptor::
+ inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryMapperNone,
+ tmpBufSize, PAGE_SIZE);
+
+ if (!tmpBufDesc) {
+ DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
+ goto exit;
+ }
+
+ tmpBuf = tmpBufDesc->getBytesNoCopy();
+
+ ctx = vfs_context_create(vfs_context_current());
+ if (vnode_open(hibernateFilename, (FREAD | O_NOFOLLOW), 0,
+ VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
+ {
+ DMSG("sleepWakeDebugDumpFromFile: Failed to open the hibernate file %s\n", hibernateFilename);
+ goto exit;
+ }
+ VATTR_INIT(&va);
+ VATTR_WANTED(&va, va_nlink);
+ VATTR_WANTED(&va, va_data_alloc);
+ if (vp->v_type != VREG ||
+ vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
+ DMSG("sleepWakeDebugDumpFromFile: Bailing as this is not a regular file\n");
+ goto exit;
+ }
+
+ /* Read the sleepimage file header */
+ rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(IOHibernateImageHeader)), 0,
+ UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
+ vfs_context_ucred(ctx), (int *) 0,
+ vfs_context_proc(ctx));
+ if (rc != 0) {
+ DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d)\n", round_page(sizeof(IOHibernateImageHeader)), rc);
+ goto exit;
+ }
+
+ imageHdr = ((IOHibernateImageHeader *)tmpBuf);
+ if (imageHdr->signature != kIOHibernateHeaderDebugDataSignature) {
+ DMSG("sleepWakeDebugDumpFromFile: File header has unexpected value 0x%x\n", imageHdr->signature);
+ goto exit;
+ }
+
+ /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
+ hdrOffset = imageHdr->deviceBlockSize;
+ if (hdrOffset + sizeof(swd_hdr) >= va.va_data_alloc) {
+ DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx)\n", va.va_data_alloc);
+ goto exit;
+ }
+
+ DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr)), trunc_page(hdrOffset));
+ /* Read the sleep/wake debug header(swd_hdr) */
+ rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(swd_hdr)), trunc_page(hdrOffset),
+ UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
+ vfs_context_ucred(ctx), (int *) 0,
+ vfs_context_proc(ctx));
+ if (rc != 0) {
+ DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
+ round_page(sizeof(swd_hdr)), rc);
+ goto exit;
+ }
+
+ hdr = (swd_hdr *)((char *)tmpBuf + (hdrOffset - trunc_page(hdrOffset)));
+ if ((hdr->signature != SWD_HDR_SIGNATURE) || (hdr->alloc_size > SWD_BUF_SIZE) ||
+ (hdr->spindump_offset > SWD_BUF_SIZE) || (hdr->spindump_size > SWD_BUF_SIZE)) {
+ DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
+ hdr->signature, hdr->alloc_size, hdr->spindump_offset, hdr->spindump_size);
+ goto exit;
+ }
+ stacksSize = hdr->spindump_size;
+
+ /* Get stacks & log offsets in the image file */
+ stacksOffset = hdrOffset + hdr->spindump_offset;
+ logOffset = hdrOffset + offsetof(swd_hdr, UUID);
+ logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
+
+ error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, stacksOffset,
+ getDumpStackFilename(hdr), stacksSize, hdr->crc);
+ if (error == EFAULT) {
+ DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
+ goto exit;
+ }
+ error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, logOffset,
+ getDumpLogFilename(hdr), logSize, 0);
+ if (error) {
+ DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error);
+ goto exit;
+ }
+exit:
+ if (error) {
+ // Write just the SleepWakeLog.dump with failure code
+ uint64_t fcode = 0;
+ const char *fname;
+ if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
+ failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
+ fcode = failStat->unsigned64BitValue();
+ fname = kSleepWakeLogFilename;
+ }
+ else {
+ fname = kAppleOSXWatchdogLogFilename;
+ }
+ memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
+ PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
+ snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
+ sleepWakeDebugSaveFile(fname, PMStatusCode, sizeof(PMStatusCode));
+ }
+ gRootDomain->swd_lock = 0;
+
+ if (vp) vnode_close(vp, FREAD, ctx);
+ if (ctx) vfs_context_rele(ctx);
+ if (tmpBufDesc) tmpBufDesc->release();
+
+}
+
+void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *logBufMap)