Exemple #1
0
/**
 * Initiate a filedisk hot-swap to another file.
 *
 * @v filedisk          The filedisk to be hot-swapped.
 * @v file              The ANSI filename for swapping to.
 */
VOID STDCALL WvFilediskHotSwap(IN WV_SP_FILEDISK_T filedisk, IN PCHAR file) {
    static WVL_S_THREAD thread = {
        /* Main */
        {
            /* Link */
            {0},
            /* Func */
            WvFilediskHotSwapThread_,
          },
        /* State */
        WvlThreadStateNotStarted,
      };
    WV_SP_FILEDISK_HOT_SWAPPER_ hot_swapper;
    ANSI_STRING file_ansi;
    NTSTATUS status;

    hot_swapper = wv_malloc(sizeof *hot_swapper);
    if (!hot_swapper) {
        DBG("Non-critical: Couldn't allocate work item.\n");
        return;
      }
    /* Build the Unicode string. */
    RtlInitAnsiString(&file_ansi, file);
    hot_swapper->filename->Buffer = NULL;
    status = RtlAnsiStringToUnicodeString(
        hot_swapper->filename,
        &file_ansi,
        TRUE
      );
    if (!NT_SUCCESS(status)) {
        DBG("Non-critical: Couldn't allocate unicode string.\n");
        wv_free(hot_swapper);
        return;
      }
    /* Build the rest of the work item. */
    hot_swapper->item->Func = WvFilediskHotSwapThread_;
    hot_swapper->filedisk = filedisk;
    /* Start the thread.  If it's already been started, no matter. */
    WvlThreadStart(&thread);
    /* Add the hot-swapper work item. */
    if (!WvlThreadAddItem(&thread, hot_swapper->item)) {
        DBG("Non-critical: Couldn't add work item.\n");
        RtlFreeUnicodeString(hot_swapper->filename);
        wv_free(hot_swapper);
      }
    /* The thread is responsible for freeing the work item and file path. */
    return;
  }
Exemple #2
0
/* Filedisk PnP ID query-response routine. */
static NTSTATUS STDCALL WvFilediskPnpQueryId_(
    IN PDEVICE_OBJECT dev_obj,
    IN PIRP irp,
    IN WVL_SP_DISK_T disk
  ) {
    static const WCHAR * hw_ids[WvlDiskMediaTypes] = {
        WVL_M_WLIT L"\\FileFloppyDisk",
        WVL_M_WLIT L"\\FileHardDisk",
        WVL_M_WLIT L"\\FileOpticalDisc"
      };
    WCHAR (*buf)[512];
    NTSTATUS status;
    WV_SP_FILEDISK_T filedisk = CONTAINING_RECORD(disk, WV_S_FILEDISK_T, disk);
    BUS_QUERY_ID_TYPE query_type;

    /* Allocate a buffer. */
    buf = wv_mallocz(sizeof *buf);
    if (!buf) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto err_buf;
      }

    /* Populate the buffer with IDs. */
    query_type = IoGetCurrentIrpStackLocation(irp)->Parameters.QueryId.IdType;
    switch (query_type) {
        case BusQueryDeviceID:
          swprintf(*buf, hw_ids[disk->Media]);
          break;

        case BusQueryInstanceID:
          /* "Location". */
          swprintf(*buf, L"Hash_%08X", filedisk->hash);
          break;

        case BusQueryHardwareIDs:
          swprintf(
              *buf + swprintf(*buf, hw_ids[disk->Media]) + 1,
              WvlDiskCompatIds[disk->Media]
            );
          break;

        case BusQueryCompatibleIDs:
          swprintf(*buf, WvlDiskCompatIds[disk->Media]);

        default:
          DBG("Unknown query type %d for %p!\n", query_type, filedisk);
          status = STATUS_INVALID_PARAMETER;
          goto err_query_type;
      }

    DBG("IRP_MN_QUERY_ID for file-backed disk %p.\n", filedisk);
    return WvlIrpComplete(irp, (ULONG_PTR) buf, STATUS_SUCCESS);

    err_query_type:

    wv_free(buf);
    err_buf:

    return WvlIrpComplete(irp, 0, status);
  }
Exemple #3
0
/**
 * Check if a disk might be the matching backing disk for
 * a GRUB4DOS sector-mapped disk by checking for some ISO9660
 * filesystem magic (in the first volume descriptor).
 *
 * @v file              HANDLE to an open disk.
 * @v filedisk          Points to the filedisk to match against.
 */
static BOOLEAN STDCALL WvFilediskG4dCheckDiskMatchIsoSig_(
    IN HANDLE file,
    IN WV_SP_FILEDISK_T filedisk
  ) {
    #ifdef _MSC_VER
    #  pragma pack(1)
    #endif
    struct vol_desc {
        UCHAR type;
        UCHAR id[5];
    } __attribute__((__packed__));
    #ifdef _MSC_VER
    #  pragma pack()
    #endif
    enum { first_vol_desc_byte_offset = 32768 };
    static CHAR iso_magic[] = "CD001";
    BOOLEAN ok = FALSE;
    struct vol_desc * buf;
    LARGE_INTEGER start;
    NTSTATUS status;
    IO_STATUS_BLOCK io_status;

    /* Allocate a buffer for testing for some ISO9660 magic. */
    buf = wv_malloc(filedisk->disk->SectorSize);
    if (buf == NULL) {
        goto err_alloc;
      }

    /* Calculate where a volume descriptor might be. */
    start.QuadPart = filedisk->offset.QuadPart + first_vol_desc_byte_offset;

    /* Read a potential ISO9660 volume descriptor. */
    status = ZwReadFile(
        file,
        NULL,
        NULL,
        NULL,
        &io_status,
        buf,
        filedisk->disk->SectorSize,
        &start,
        NULL
      );
    if (!NT_SUCCESS(status))
      goto err_read;

    /* Check for the ISO9660 magic. */
    if (wv_memcmpeq(buf->id, iso_magic, sizeof iso_magic - 1))
      ok = TRUE;

    err_read:

    wv_free(buf);
    err_alloc:

    return ok;
  }
Exemple #4
0
NTSTATUS STDCALL WvDiskPnpQueryDevText(
    IN PDEVICE_OBJECT dev_obj,
    IN PIRP irp,
    IN WVL_SP_DISK_T disk
  ) {
    IN WV_SP_DEV_T dev = WvDevFromDevObj(dev_obj);
    WCHAR (*str)[512];
    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
    NTSTATUS status;
    UINT32 str_len;

    /* Allocate a string buffer. */
    str = wv_mallocz(sizeof *str);
    if (str == NULL) {
        DBG("wv_malloc IRP_MN_QUERY_DEVICE_TEXT\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto alloc_str;
      }
    /* Determine the query type. */
    switch (io_stack_loc->Parameters.QueryDeviceText.DeviceTextType) {
        case DeviceTextDescription:
          str_len = swprintf(*str, WVL_M_WLIT L" Disk") + 1;
          irp->IoStatus.Information =
            (ULONG_PTR) wv_palloc(str_len * sizeof *str);
          if (irp->IoStatus.Information == 0) {
              DBG("wv_palloc DeviceTextDescription\n");
              status = STATUS_INSUFFICIENT_RESOURCES;
              goto alloc_info;
            }
          RtlCopyMemory(
              (PWCHAR) irp->IoStatus.Information,
              str,
              str_len * sizeof *str
            );
          status = STATUS_SUCCESS;
          goto alloc_info;

        case DeviceTextLocationInformation:
          if (disk->disk_ops.PnpQueryId) {
              io_stack_loc->MinorFunction = IRP_MN_QUERY_ID;
              io_stack_loc->Parameters.QueryId.IdType = BusQueryInstanceID;
              return disk->disk_ops.PnpQueryId(dev_obj, irp, disk);
            }
          /* Else, fall through... */

        default:
          irp->IoStatus.Information = 0;
          status = STATUS_NOT_SUPPORTED;
      }
    /* irp->IoStatus.Information not freed. */
    alloc_info:

    wv_free(str);
    alloc_str:

    return WvlIrpComplete(irp, irp->IoStatus.Information, status);
  }
Exemple #5
0
/* The thread responsible for hot-swapping filedisks. */
static VOID STDCALL WvFilediskHotSwapThread_(IN OUT WVL_SP_THREAD_ITEM item) {
    LARGE_INTEGER timeout;
    WVL_SP_THREAD thread = CONTAINING_RECORD(item, WVL_S_THREAD, Main);
    WVL_SP_THREAD_ITEM work_item;
    WV_SP_FILEDISK_HOT_SWAPPER_ info;

    /* Wake up at least every 10 seconds. */
    timeout.QuadPart = -100000000LL;

    while (
        (thread->State == WvlThreadStateStarted) ||
        (thread->State == WvlThreadStateStopping)
      ) {
        /* Wait for the work signal or the timeout. */
        KeWaitForSingleObject(
            &thread->Signal,
            Executive,
            KernelMode,
            FALSE,
            &timeout
          );

        work_item = WvlThreadGetItem(thread);
        if (!work_item)
          continue;

        if (work_item->Func != WvFilediskHotSwapThread_) {
            DBG("Unknown work item.\n");
            continue;
          }
        info = CONTAINING_RECORD(
            work_item,
            WV_S_FILEDISK_HOT_SWAPPER_,
            item[0]
          );
        /* Attempt a hot swap. */
        if (WvFilediskHotSwap_(info->filedisk, info->filename)) {
            /* Success. */
            RtlFreeUnicodeString(info->filename);
            wv_free(info);
          } else {
            /* Re-enqueue. */
            WvlThreadAddItem(thread, info->item);
          }

        /* Reset the work signal. */
        KeResetEvent(&thread->Signal);
      } /* while thread is running. */
    return;
  }
Exemple #6
0
VOID STDCALL WvlDebugIrpEnd(IN PIRP Irp, IN NTSTATUS Status) {
    PDEBUG_IRPLIST Record;
    KIRQL Irql;
  
    if ((Record = Debug_IrpListRecord(Irp)) == NULL) {
        DBG(
            "Irp not found in Debug_Globals_IrpList!!"
              " (returned 0x%08x, Status)\n"
          );
        return;
      }
    /*
     * There is no race condition between getting the record and unlinking in
     * Debug_Globals_IrpList, unless WvlDebugIrpEnd is called more than once on
     * an irp (which itself is a bug, it should only be called one time).
     */
    KeAcquireSpinLock(&WvlDebugLock_, &Irql);
    if (Record->Previous == NULL) {
        Debug_Globals_IrpList = Record->Next;
      } else {
        Record->Previous->Next = Record->Next;
      }
    if (Record->Next != NULL) {
        Record->Next->Previous = Record->Previous;
      }
    KeReleaseSpinLock(&WvlDebugLock_, Irql);
  
    DBG(
        "IRP %d: %s -> 0x%08x\n",
        Record->Number,
        Record->DebugMessage,
        Status
      );
    wv_free(Record->DebugMessage);
    wv_free(Record);
  }
Exemple #7
0
/**
 * Check if a disk might be the matching backing disk for
 * a GRUB4DOS sector-mapped disk by checking for an MBR signature.
 *
 * @v file              HANDLE to an open disk.
 * @v filedisk          Points to the filedisk to match against.
 */
static BOOLEAN STDCALL WvFilediskG4dCheckDiskMatchMbrSig_(
    IN HANDLE file,
    IN WV_SP_FILEDISK_T filedisk
  ) {
    BOOLEAN ok = FALSE;
    WVL_SP_DISK_MBR buf;
    NTSTATUS status;
    IO_STATUS_BLOCK io_status;

    /* Allocate a buffer for testing for an MBR signature. */
    buf = wv_malloc(sizeof *buf);
    if (buf == NULL) {
        goto err_alloc;
      }

    /* Read a potential MBR. */
    status = ZwReadFile(
        file,
        NULL,
        NULL,
        NULL,
        &io_status,
        buf,
        sizeof *buf,
        &filedisk->offset,
        NULL
      );
    if (!NT_SUCCESS(status))
      goto err_read;

    /* Check for the MBR signature. */
    if (buf->mbr_sig == 0xAA55)
      ok = TRUE;

    err_read:

    wv_free(buf);
    err_alloc:

    return ok;
  }
Exemple #8
0
/**
 * Initiate a search for a GRUB4DOS backing disk.
 *
 * @v filedisk          The filedisk whose backing disk we need.
 */
static BOOLEAN STDCALL WvFilediskG4dFindBackingDisk(
    IN WV_SP_FILEDISK_T filedisk
  ) {
    SP_WV_FILEDISK_G4D_FIND_BACKING_DISK finder;
    KIRQL irql;

    finder = wv_malloc(sizeof *finder);
    if (!finder) {
        DBG("Couldn't allocate work item!\n");
        goto err_finder;
      }

    KeAcquireSpinLock(&WvFindDiskLock, &irql);
    ++WvFindDisk;
    KeReleaseSpinLock(&WvFindDiskLock, irql);

    finder->item->Func = WvFilediskG4dFindBackingDisk_;
    finder->filedisk = filedisk;
    /* Add the hot-swapper work item. */
    if (!WvlThreadAddItem(filedisk->Thread, finder->item)) {
        DBG("Couldn't add work item!\n");
        goto err_work_item;
      }

    /* The thread is responsible for freeing the work item. */
    return TRUE;

    err_work_item:

    KeAcquireSpinLock(&WvFindDiskLock, &irql);
    --WvFindDisk;
    KeReleaseSpinLock(&WvFindDiskLock, irql);

    wv_free(finder);
    err_finder:

    return FALSE;
  }
Exemple #9
0
static WV_S_DUMMY_IDS * WvSafeHookDummyIds(
    IN A_WV_SAFE_HOOK_VENDOR_STRING * vendor,
    IN S_X86_SEG16OFF16 * whence
  ) {
    UCHAR * ptr;
    WV_S_DUMMY_IDS * dummy_ids;
    WCHAR * dest;
    INT copied;
    A_WV_SAFE_HOOK_WIDE_VENDOR_STRING wide_vendor;

    /* Generate the safe hook vendor string */
    WvSafeHookVendorString(&wide_vendor, vendor);

    ptr = wv_malloc(CvWvSafeHookDummyIdsSize);
    if (!ptr)
      goto err_dummy_ids;

    /* Populate with defaults */
    dummy_ids = (VOID *) ptr;
    RtlCopyMemory(
        dummy_ids,
        WvSafeHookDefaultDummyIds,
        CvWvSafeHookDummyIdsSize
      );

    /* Generate the specific details */
    ptr += dummy_ids->Offset;

    /* The instance ID */
    dest = (VOID *) ptr;
    dest += dummy_ids->InstanceOffset;
    copied = swprintf(
        dest,
        M_WV_SAFE_HOOK_INSTANCE_ID,
        M_X86_SEG16OFF16_ADDR(whence)
      );
    if (copied <= 0)
      goto err_copied;

    /* The vendor ID */
    dest = (VOID *) ptr;
    dest += dummy_ids->HardwareOffset;
    copied = swprintf(dest, M_WV_SAFE_HOOK_VENDOR_ID, wide_vendor);
    if (copied <= 0)
      goto err_copied;

    /* The compatible IDs */
    dest = (VOID *) ptr;
    dest += dummy_ids->CompatOffset;
    copied = swprintf(dest, M_WV_SAFE_HOOK_VENDOR_ID, wide_vendor);
    if (copied <= 0)
      goto err_copied;

    return dummy_ids;

    err_copied:

    wv_free(dummy_ids);
    err_dummy_ids:

    return NULL;
  }
Exemple #10
0
WVL_M_LIB NTSTATUS STDCALL WvlCreateSafeHookDevice(
    IN S_X86_SEG16OFF16 * hook_addr,
    IN OUT DEVICE_OBJECT ** dev_obj
  ) {
    static const UCHAR sig[] = M_WV_SAFE_HOOK_SIGNATURE;
    UCHAR * phys_mem;
    NTSTATUS status;
    UINT32 hook_phys_addr;
    WV_S_PROBE_SAFE_MBR_HOOK * safe_mbr_hook;
    WV_S_DUMMY_IDS * dummy_ids;
    A_WV_SAFE_HOOK_VENDOR_STRING vendor;
    DEVICE_OBJECT * new_dev_obj;
    S_WVL_DUMMY_PDO * dummy;

    ASSERT(hook_addr);
    ASSERT(dev_obj);

    /* Map the first MiB of memory */
    phys_mem = WvlMapUnmapLowMemory(NULL);
    if (!phys_mem) {
        DBG("Could not map low memory\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto err_map;
      }

    /* Special-case the IVT entry for INT 0x13 */
    if (
        hook_addr->Segment == 0 &&
        hook_addr->Offset == (sizeof *hook_addr * 0x13)
      ) {
        hook_addr = (VOID *) (phys_mem + sizeof *hook_addr * 0x13);
      }

    hook_phys_addr = M_X86_SEG16OFF16_ADDR(hook_addr);
    DBG(
        "Probing for safe hook at %04X:%04X (0x%08X)...\n",
        hook_addr->Segment,
        hook_addr->Offset,
        hook_phys_addr
      );

    /* Check for the signature */
    safe_mbr_hook = (VOID *) (phys_mem + hook_phys_addr);
    if (!wv_memcmpeq(safe_mbr_hook->Signature, sig, sizeof sig - 1)) {
        DBG("Invalid safe INT 0x13 hook signature.  End of chain\n");
        status = STATUS_NOT_SUPPORTED;
        goto err_sig;
      }

    /* Found one */
    DBG("Found safe hook with vendor ID: %.8s\n", safe_mbr_hook->VendorId);

    /* Build the IDs */
    RtlCopyMemory(
        vendor,
        safe_mbr_hook->VendorId,
        sizeof safe_mbr_hook->VendorId
      );
    dummy_ids = WvSafeHookDummyIds(&vendor, hook_addr);
    if (!dummy_ids) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto err_dummy_ids;
      }

    new_dev_obj = NULL;
    status = WvDummyAdd(
        /* Mini-driver: Us */
        WvSafeHookMiniDriver,
        /* Dummy IDs */
        dummy_ids,
        /* Dummy IDs offset */
        CvWvSafeHookDummyIdsOffset,
        /* Extra data offset */
        CvWvSafeHookDummyIdsExtraDataOffset,
        /* Extra data size */
        sizeof *hook_addr,
        /* Device name: Not specified */
        NULL,
        /* Exclusive access? */
        FALSE,
        /* PDO pointer to populate */
        &new_dev_obj
      );
    if (!NT_SUCCESS(status))
      goto err_new_dev_obj;
    ASSERT(new_dev_obj);

    dummy = new_dev_obj->DeviceExtension;
    ASSERT(dummy);
    *((S_X86_SEG16OFF16 *) dummy->ExtraData) = *hook_addr;

    if (dev_obj)
      *dev_obj = new_dev_obj;

    status = STATUS_SUCCESS;
    goto out;

    WvlDeleteDevice(new_dev_obj);
    err_new_dev_obj:

    out:

    wv_free(dummy_ids);
    err_dummy_ids:

    err_sig:

    WvlMapUnmapLowMemory(phys_mem);
    err_map:

    return status;
  }
Exemple #11
0
static NTSTATUS STDCALL AoeBusPnpQueryDevText_(
    IN WVL_SP_BUS_T bus,
    IN PIRP irp
) {
    WCHAR (*str)[512];
    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
    NTSTATUS status;
    UINT32 str_len;

    /* Allocate a string buffer. */
    str = wv_mallocz(sizeof *str);
    if (str == NULL) {
        DBG("wv_malloc IRP_MN_QUERY_DEVICE_TEXT\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto alloc_str;
    }
    /* Determine the query type. */
    switch (io_stack_loc->Parameters.QueryDeviceText.DeviceTextType) {
    case DeviceTextDescription:
        str_len = swprintf(*str, L"AoE Bus") + 1;
        irp->IoStatus.Information =
            (ULONG_PTR) wv_palloc(str_len * sizeof **str);
        if (irp->IoStatus.Information == 0) {
            DBG("wv_palloc DeviceTextDescription\n");
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto alloc_info;
        }
        RtlCopyMemory(
            (PWCHAR) irp->IoStatus.Information,
            str,
            str_len * sizeof **str
        );
        status = STATUS_SUCCESS;
        goto alloc_info;

    case DeviceTextLocationInformation:
        str_len = AoeBusPnpId_(
                      NULL,
                      BusQueryInstanceID,
                      str
                  );
        irp->IoStatus.Information =
            (ULONG_PTR) wv_palloc(str_len * sizeof **str);
        if (irp->IoStatus.Information == 0) {
            DBG("wv_palloc DeviceTextLocationInformation\n");
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto alloc_info;
        }
        RtlCopyMemory(
            (PWCHAR) irp->IoStatus.Information,
            str,
            str_len * sizeof **str
        );
        status = STATUS_SUCCESS;
        goto alloc_info;

    default:
        irp->IoStatus.Information = 0;
        status = STATUS_NOT_SUPPORTED;
    }
    /* irp->IoStatus.Information not freed. */
alloc_info:

    wv_free(str);
alloc_str:

    return WvlIrpComplete(irp, irp->IoStatus.Information, status);
}
Exemple #12
0
/**
 * Default disk deletion operation.
 *
 * @v dev               Points to the disk device to delete.
 */
static VOID STDCALL WvDiskDevFree_(IN WV_SP_DEV_T dev) {
    WVL_SP_DISK_T disk = disk__get_ptr(dev);

    wv_free(disk);
  }
Exemple #13
0
/**
 * Stalls the arrival of a GRUB4DOS sector-mapped disk until
 * the backing disk is found, and stalls driver re-initialization.
 */
static VOID STDCALL WvFilediskG4dFindBackingDisk_(
    IN OUT WVL_SP_THREAD_ITEM item
  ) {
    static U_WV_LARGE_INT delay_time = {-10000000LL};
    SP_WV_FILEDISK_G4D_FIND_BACKING_DISK finder = CONTAINING_RECORD(
        item,
        S_WV_FILEDISK_G4D_FIND_BACKING_DISK,
        item[0]
      );
    WV_SP_FILEDISK_T filedisk_ptr;
    NTSTATUS status;
    GUID disk_guid = GUID_DEVINTERFACE_DISK;
    PWSTR sym_links;
    PWCHAR pos;
    HANDLE file;
    int count = 0;
    KIRQL irql;

    /* Establish pointer to the filedisk. */
    filedisk_ptr = finder->filedisk;

    /* Free the work item. */
    wv_free(item);

    do {
    /*
     * Find the backing disk and use it.  We walk a list
     * of unicode disk device names and check each one.
     */
    status = IoGetDeviceInterfaces(&disk_guid, NULL, 0, &sym_links);
    if (!NT_SUCCESS(status))
      goto retry;
    pos = sym_links;
    while (*pos != UNICODE_NULL) {
        UNICODE_STRING path;
        OBJECT_ATTRIBUTES obj_attrs;
        IO_STATUS_BLOCK io_status;

        RtlInitUnicodeString(&path, pos);
        InitializeObjectAttributes(
            &obj_attrs,
            &path,
            OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
            NULL,
            NULL
          );
        /* Try this disk. */
        file = 0;
        status = ZwCreateFile(
            &file,
            GENERIC_READ | GENERIC_WRITE,
            &obj_attrs,
            &io_status,
            NULL,
            FILE_ATTRIBUTE_NORMAL,
            FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
            FILE_OPEN,
            FILE_NON_DIRECTORY_FILE |
              FILE_RANDOM_ACCESS |
              FILE_SYNCHRONOUS_IO_NONALERT,
            NULL,
            0
          );
        /* If we could open it, check it out. */
        if (NT_SUCCESS(status)) {
            /* If we liked this disk as our backing disk, stop looking. */
            if (WvFilediskG4dCheckDiskMatch_(file, filedisk_ptr))
              break;
          }
        /* We could not open this disk or didn't like it.  Try the next one. */
        if (file)
          ZwClose(file);
        while (*pos != UNICODE_NULL)
          pos++;
        pos++;
      } /* while */
    wv_free(sym_links);
    /* If we did not find the backing disk, we are a dud. */
    if (!NT_SUCCESS(status))
      goto retry;
    /* Use the backing disk and report the sector-mapped disk. */
    filedisk_ptr->file = file;

    /* Release the driver re-initialization stall. */
    KeAcquireSpinLock(&WvFindDiskLock, &irql);
    --WvFindDisk;
    KeReleaseSpinLock(&WvFindDiskLock, irql);

    DBG("Found backing disk for filedisk %p\n", (PVOID) filedisk_ptr);
    return;

    retry:
    /* Sleep. */
    DBG("Sleeping...");
    KeDelayExecutionThread(KernelMode, FALSE, &delay_time.large_int);
    } while (count++ < 10);
  }
Exemple #14
0
/**
 * Check if a disk might be the matching backing disk for
 * a GRUB4DOS sector-mapped disk by checking for a .VHD footer.
 *
 * @v file              HANDLE to an open disk.
 * @v filedisk_ptr      Points to the filedisk to match against.
 */
static BOOLEAN STDCALL WvFilediskG4dCheckDiskMatchVHD_(
    IN HANDLE file,
    IN WV_SP_FILEDISK_T filedisk_ptr
  ) {
    BOOLEAN ok = FALSE;
    WV_SP_MSVHD_FOOTER buf;
    NTSTATUS status;
    LARGE_INTEGER end_part;
    IO_STATUS_BLOCK io_status;

    /* Allocate a buffer for testing for a MS .VHD footer. */
    buf = wv_malloc(sizeof *buf);
    if (buf == NULL) {
        goto err_alloc;
      }

    /*
     * Read in the buffer.  Note that we adjust for the .VHD footer (plus
     * prefixed padding for an .ISO) that we truncated from the reported disk
     * size earlier when the disk mapping was found.
     */
    end_part.QuadPart =
      filedisk_ptr->offset.QuadPart +
      (filedisk_ptr->disk->LBADiskSize * filedisk_ptr->disk->SectorSize) +
      filedisk_ptr->disk->SectorSize -
      sizeof *buf;
    status = ZwReadFile(
        file,
        NULL,
        NULL,
        NULL,
        &io_status,
        buf,
        sizeof *buf,
        &end_part,
        NULL
      );
    if (!NT_SUCCESS(status))
      goto err_read;

    /* Adjust the footer's byte ordering. */
    msvhd__footer_swap_endian(buf);

    /* Examine .VHD fields for validity. */
    if (!wv_memcmpeq(&buf->cookie, "conectix", sizeof buf->cookie))
      goto err_cookie;
    if (buf->file_ver.val != 0x10000)
      goto err_ver;
    if (buf->data_offset.val != 0xffffffff)
      goto err_data_offset;
    if (buf->orig_size.val != buf->cur_size.val)
      goto err_size;
    if (buf->type.val != 2)
      goto err_type;

    /* Match against our expected disk size. */
    if (
        (filedisk_ptr->disk->LBADiskSize * filedisk_ptr->disk->SectorSize ) !=
        buf->cur_size.val
      )
      goto err_real_size;

    /* Passed the tests.  We expect it to be our backing disk. */
    ok = TRUE;

    err_real_size:

    err_type:

    err_size:

    err_data_offset:

    err_ver:

    err_cookie:

    err_read:

    wv_free(buf);
    err_alloc:

    return ok;
  }
Exemple #15
0
/**
 * Find and hot-swap to a backing file.  Internal.
 *
 * We search all filesystems for a particular filename, then swap
 * to using it as the backing store.  This is currently useful for
 * sector-mapped disks which should really have a file-in-use lock
 * for the file they represent.  Once the backing file is established,
 * the work item is freed.  Otherwise, it is re-enqueued and the
 * thread will keep trying.
 */
static BOOLEAN STDCALL WvFilediskHotSwap_(
    IN WV_SP_FILEDISK_T filedisk,
    IN PUNICODE_STRING filename
  ) {
    NTSTATUS status;
    GUID vol_guid = GUID_DEVINTERFACE_VOLUME;
    PWSTR sym_links;
    PWCHAR pos;
    KIRQL irql;

    /* Do we currently have a backing disk?  If not, re-enqueue for later. */
    if (filedisk->file == NULL)
      return FALSE;
    /*
     * Find the backing volume and use it.  We walk a list
     * of unicode volume device names and check each one for the file.
     */
    status = IoGetDeviceInterfaces(&vol_guid, NULL, 0, &sym_links);
    if (!NT_SUCCESS(status))
      return FALSE;
    pos = sym_links;
    status = STATUS_UNSUCCESSFUL;
    while (*pos != UNICODE_NULL) {
        UNICODE_STRING path;
        PFILE_OBJECT vol_file_obj;
        PDEVICE_OBJECT vol_dev_obj;
        UNICODE_STRING vol_dos_name;
        UNICODE_STRING filepath;
        static const WCHAR obj_path_prefix[] = L"\\??\\";
        static const WCHAR path_sep = L'\\';
        OBJECT_ATTRIBUTES obj_attrs;
        HANDLE file = 0;
        IO_STATUS_BLOCK io_status;

        RtlInitUnicodeString(&path, pos);
        /* Get some object pointers for the volume. */
        status = IoGetDeviceObjectPointer(
            &path,
            FILE_READ_DATA,
            &vol_file_obj,
            &vol_dev_obj
          );
        if (!NT_SUCCESS(status))
          goto err_obj_ptrs;
        /* Get the DOS name. */
        vol_dos_name.Buffer = NULL;
        vol_dos_name.Length = vol_dos_name.MaximumLength = 0;
        status = RtlVolumeDeviceToDosName(
            vol_file_obj->DeviceObject,
            &vol_dos_name
          );
        if (!NT_SUCCESS(status))
          goto err_dos_name;
        /* Build the file path.  Ugh, what a mess. */
        filepath.Length = filepath.MaximumLength =
          sizeof obj_path_prefix -
          sizeof UNICODE_NULL +
          vol_dos_name.Length +
          sizeof path_sep +
          filename->Length;
        filepath.Buffer = wv_malloc(filepath.Length);
        if (filepath.Buffer == NULL) {
            status = STATUS_UNSUCCESSFUL;
            goto err_alloc_buf;
          }
        {   PCHAR buf = (PCHAR) filepath.Buffer;

            RtlCopyMemory(
                buf,
                obj_path_prefix,
                sizeof obj_path_prefix - sizeof UNICODE_NULL
              );
            buf += sizeof obj_path_prefix - sizeof UNICODE_NULL;
            RtlCopyMemory(buf, vol_dos_name.Buffer, vol_dos_name.Length);
            buf += vol_dos_name.Length;
            RtlCopyMemory(buf, &path_sep, sizeof path_sep);
            buf += sizeof path_sep;
            RtlCopyMemory(buf, filename->Buffer, filename->Length);
          } /* buf scope */
        InitializeObjectAttributes(
            &obj_attrs,
            &filepath,
            OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
            NULL,
            NULL
          );
        /* Look for the file on this volume. */
        status = ZwCreateFile(
            &file,
            GENERIC_READ | GENERIC_WRITE,
            &obj_attrs,
            &io_status,
            NULL,
            FILE_ATTRIBUTE_NORMAL,
            FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
            FILE_OPEN,
            FILE_NON_DIRECTORY_FILE |
              FILE_RANDOM_ACCESS |
              FILE_SYNCHRONOUS_IO_NONALERT,
            NULL,
            0
          );
        if (!NT_SUCCESS(status))
          goto err_open;
        /* We could open it.  Do the hot-swap. */
        {   HANDLE old = filedisk->file;
  
            filedisk->file = 0;
            filedisk->offset.QuadPart = 0;
            filedisk->file = file;
            ZwClose(old);
          } /* old scope */
  
        err_open:
  
        wv_free(filepath.Buffer);
        err_alloc_buf:
  
        wv_free(vol_dos_name.Buffer);
        err_dos_name:
  
        ObDereferenceObject(vol_file_obj);
        err_obj_ptrs:
        /* Walk to the next terminator. */
        while (*pos != UNICODE_NULL)
          pos++;
        /* If everything succeeded, stop.  Otherwise try the next volume. */
        if (!NT_SUCCESS(status))
          pos++;
      } /* while */
    wv_free(sym_links);
    /* Success? */
    if (NT_SUCCESS(status)) {
        DBG("Finished hot-swapping.\n");
        return TRUE;
      }
    return FALSE;
  }
Exemple #16
0
/**
 * IRP_MJ_PNP:IRP_MN_QUERY_DEVICE_RELATIONS handler
 *
 * IRQL == PASSIVE_LEVEL
 * Completed by PDO, must accumulate relations downwards (upwards optional)
 * BusRelations: system thread
 *   Yes: FDO
 *   Maybe: filter
 * TargetDeviceRelation: any thread
 *   Yes: PDO
 * RemovalRelations: system thread
 *   Maybe: FDO
 *   Maybe: filter
 * PowerRelations >= Windows 7: system thread
 *   Maybe: FDO
 *   Maybe: filter
 * EjectionRelations: system thread
 *   Maybe: PDO
 *
 * @param Parameters.QueryDeviceRelations.Type (I/O stack location)
 *
 * @param FileObject (I/O stack location)
 *
 * @return
 *   Success:
 *     Irp->IoStatus.Status == STATUS_SUCCESS
 *     Irp->IoStatus.Information populated from paged memory
 *   Error:
 *     Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES
 */
static NTSTATUS STDCALL WvMemdiskPnpQueryDeviceRelations(
    IN DEVICE_OBJECT * dev_obj,
    IN IRP * irp
  ) {
    S_WV_MEMDISK_BUS * bus;
    IO_STACK_LOCATION * io_stack_loc;
    NTSTATUS status;
    DEVICE_OBJECT * child;
    DEVICE_RELATIONS * dev_relations;
    DEVICE_RELATIONS * higher_dev_relations;
    DEVICE_RELATIONS * response;
    ULONG i;

    ASSERT(dev_obj);
    bus = dev_obj->DeviceExtension;
    ASSERT(bus);

    higher_dev_relations = (VOID *) irp->IoStatus.Information;

    ASSERT(irp);
    io_stack_loc = IoGetCurrentIrpStackLocation(irp);    

    switch (io_stack_loc->Parameters.QueryDeviceRelations.Type) {
        case BusRelations:

        /*
         * Have we already created PDOs for the previous
         * INT 0x13 handler and the MEMDISK disk?
         */
        switch (bus->BusRelations->Count) {
            case 0:
            /* Try to create the MEMDISK disk */
            child = NULL;
            status = WvMemdiskCreateDisk(bus->PhysicalDeviceObject, &child);
            if (child) {
                bus->BusRelations->Count = 1;
                bus->BusRelations->Objects[0] = child;
                /* TODO: Uncomment when RAM disks are mini-driver */
                if (0)
                if (!WvlAssignDeviceToBus(child, dev_obj)) {
                    DBG("Couldn't add MEMDISK disk PDO\n");
                    WvlDeleteDevice(child);
                    break;
                  }
              } else {
                break;
              }
            /* Fall through */

            case 1:
            /* Try to create the previous safe hook in the chain */
            child = NULL;
            status = WvlCreateSafeHookDevice(
                bus->PreviousInt13hHandler,
                &child
              );
            if (child) {
                bus->BusRelations->Count = 2;
                bus->BusRelations->Objects[1] = child;
                if (!WvlAssignDeviceToBus(child, dev_obj)) {
                    DBG("Couldn't add safe hook PDO\n");
                    WvlDeleteDevice(child);
                  }
              }
            break;

            case 2:
            /* All PDOs already produced */
            break;

            default:
            DBG("Unexpected count of BusRelations!\n");
            ASSERT(0);
          }

        dev_relations = bus->BusRelations;
        break;

        case TargetDeviceRelation:
        case RemovalRelations:
        case EjectionRelations:
        default:
        DBG("Unsupported device relations query\n");
        return WvlPassIrpDown(dev_obj, irp);
      }

    /* We need to include any higher driver's PDOs */
    higher_dev_relations = (VOID *) irp->IoStatus.Information;
    response = WvlMergeDeviceRelations(dev_relations, higher_dev_relations);
    if (!response) {
        /*
         * It's not clear whether or not we should do the following,
         * but it can't hurt...  Right?
         */
        if (higher_dev_relations) {
            for (i = 0; i < higher_dev_relations->Count; ++i)
              ObDereferenceObject(higher_dev_relations->Objects[i]);
            wv_free(higher_dev_relations);
          }

        irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES;
        irp->IoStatus.Information = 0;
        WvlPassIrpUp(dev_obj, irp, IO_NO_INCREMENT);
        return status;
      }

    /* Reference our PDOs */
    for (i = 0; i < dev_relations->Count; ++i)
      ObReferenceObject(dev_relations->Objects[i]);

    /* Send the IRP down */
    irp->IoStatus.Status = STATUS_SUCCESS;
    irp->IoStatus.Information = (ULONG_PTR) response;
    return WvlPassIrpDown(dev_obj, irp);
  }
Exemple #17
0
/* Produce a dummy PDO node on the main bus.  Internal */
static NTSTATUS STDCALL WvDummyAdd_(
    IN WV_SP_DUMMY_IDS DummyIds,
    IN PDEVICE_OBJECT * Pdo
  ) {
    NTSTATUS status;
    PDEVICE_OBJECT pdo = NULL;
    WV_SP_DEV_T dev;
    WV_SP_DUMMY_IDS new_dummy_ids;

    status = IoCreateDevice(
        WvDriverObj,
        sizeof (WV_S_DEV_EXT),
        NULL,
        DummyIds->DevType,
        DummyIds->DevCharacteristics,
        FALSE,
        &pdo
      );
    if (!NT_SUCCESS(status) || !pdo) {
        DBG("Couldn't create dummy device.\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto err_create_pdo;
      }

    dev = wv_malloc(sizeof *dev);
    if (!dev) {
        DBG("Couldn't allocate dummy device.\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto err_dev;
      }

    new_dummy_ids = wv_malloc(DummyIds->Len);
    if (!new_dummy_ids) {
        DBG("Couldn't allocate dummy IDs.\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto err_dummy_ids;
      }

    /* Copy the IDs' offsets and lengths. */
    RtlCopyMemory(new_dummy_ids, DummyIds, DummyIds->Len);

    /* Ok! */
    WvDevInit(dev);
    dev->ext = new_dummy_ids;   /* TODO: Implement a dummy free.  Leaking. */
    dev->Self = pdo;
    /* Optionally fill the caller's PDO pointer. */
    if (Pdo)
      *Pdo = pdo;
    WvDevForDevObj(pdo, dev);
    WvDevSetIrpHandler(pdo, WvDummyIrpDispatch);
    WvlBusInitNode(&dev->BusNode, pdo);
    /* Associate the parent bus. */
    dev->Parent = WvBus.Fdo;
    /* Add the new PDO device to the bus' list of children. */
    WvlBusAddNode(&WvBus, &dev->BusNode);
    pdo->Flags &= ~DO_DEVICE_INITIALIZING;

    return STATUS_SUCCESS;

    wv_free(new_dummy_ids);
    err_dummy_ids:

    wv_free(dev);
    err_dev:

    IoDeleteDevice(pdo);
    err_create_pdo:

    return status;
  }