#ifndef _VDISK_H #define _VDISK_H /* * Copyright (C) 2012 Michael Brown . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * @file * * Virtual disk emulation * */ #include /** Number of cylinders */ #define VDISK_CYLINDERS 1024 /* Maximum possible */ /** Number of heads */ #define VDISK_HEADS 255 /** Number of sectors per track */ #define VDISK_SECTORS_PER_TRACK 63 /** Sector size (in bytes) */ #define VDISK_SECTOR_SIZE 512 /** Partition start LBA */ #define VDISK_PARTITION_LBA 128 /** Cluster size (in sectors) */ #define VDISK_CLUSTER_COUNT 64 /** Cluster size (in bytes) */ #define VDISK_CLUSTER_SIZE ( VDISK_CLUSTER_COUNT * VDISK_SECTOR_SIZE ) /** Number of clusters */ #define VDISK_CLUSTERS 0x03ffc000ULL /* Fill 2TB disk */ /** Maximum number of virtual files * * The total number of files must be strictly less than the number of * sectors per cluster. */ #define VDISK_MAX_FILES ( VDISK_CLUSTER_COUNT - 1 ) /** Maximum file size (in sectors) */ #define VDISK_FILE_COUNT 0x800000UL /* max for 32-bit address space */ /** Maximum file size (in clusters) */ #define VDISK_FILE_CLUSTERS ( VDISK_FILE_COUNT / VDISK_CLUSTER_COUNT ) /** File starting LBA */ #define VDISK_FILE_LBA( idx ) ( ( (idx) + 1 ) * VDISK_FILE_COUNT ) /** File index from LBA */ #define VDISK_FILE_IDX( lba ) ( ( (lba) / VDISK_FILE_COUNT ) - 1 ) /** File offset (in bytes) from LBA */ #define VDISK_FILE_OFFSET( lba ) \ ( ( (lba) % VDISK_FILE_COUNT ) * VDISK_SECTOR_SIZE ) /** File index from directory entry LBA */ #define VDISK_FILE_DIRENT_IDX( lba ) ( ( (lba) - 1 ) % VDISK_CLUSTER_COUNT ) /** Number of sectors allocated for FAT */ #define VDISK_SECTORS_PER_FAT \ ( ( ( VDISK_CLUSTERS * sizeof ( uint32_t ) + \ VDISK_CLUSTER_SIZE - 1 ) / VDISK_CLUSTER_SIZE ) \ * VDISK_CLUSTER_COUNT ) /** Number of reserved sectors */ #define VDISK_RESERVED_COUNT VDISK_CLUSTER_COUNT /** Starting cluster number for file */ #define VDISK_FILE_CLUSTER( idx ) \ ( ( ( ( VDISK_FILE_COUNT - VDISK_PARTITION_LBA - \ VDISK_RESERVED_COUNT - VDISK_SECTORS_PER_FAT ) / \ VDISK_CLUSTER_COUNT ) + 2 ) + \ ( (idx) * VDISK_FILE_CLUSTERS ) ) /** Total number of sectors within partition */ #define VDISK_PARTITION_COUNT \ ( VDISK_RESERVED_COUNT + VDISK_SECTORS_PER_FAT + \ ( VDISK_CLUSTERS * VDISK_CLUSTER_COUNT ) ) /** Number of sectors */ #define VDISK_COUNT ( VDISK_PARTITION_LBA + VDISK_PARTITION_COUNT ) /** Calculate sector from cluster */ #define VDISK_CLUSTER_SECTOR( cluster ) \ ( ( ( (cluster) - 2 ) * VDISK_CLUSTER_COUNT ) + \ VDISK_RESERVED_COUNT + VDISK_SECTORS_PER_FAT ) /***************************************************************************** * * Master Boot Record * ***************************************************************************** */ /** Master Boot Record LBA */ #define VDISK_MBR_LBA 0x00000000 /** Master Boot Record sector count */ #define VDISK_MBR_COUNT 1 /** Partition table entry */ struct vdisk_partition { /** Bootable flag */ uint8_t bootable; /** C/H/S start address */ uint8_t chs_start[3]; /** System indicator (partition type) */ uint8_t type; /** C/H/S end address */ uint8_t chs_end[3]; /** Linear start address */ uint32_t start; /** Linear length */ uint32_t length; } __attribute__ (( packed )); /** Master Boot Record */ struct vdisk_mbr { /** Code area */ uint8_t code[440]; /** Disk signature */ uint32_t signature; /** Padding */ uint8_t pad[2]; /** Partition table */ struct vdisk_partition partitions[4]; /** 0x55aa signature */ uint16_t magic; } __attribute__ (( packed )); /** MBR boot partition indiciator */ #define VDISK_MBR_BOOTABLE 0x80 /** MBR type indicator for FAT32 */ #define VDISK_MBR_TYPE_FAT32 0x0c /** MBR signature */ #define VDISK_MBR_SIGNATURE 0xc0ffeeee /** MBR magic */ #define VDISK_MBR_MAGIC 0xaa55 /***************************************************************************** * * Volume Boot Record * ***************************************************************************** */ /** Volume Boot Record LBA */ #define VDISK_VBR_LBA VDISK_PARTITION_LBA /** Volume Boot Record sector count */ #define VDISK_VBR_COUNT 1 /** Volume Boot Record */ struct vdisk_vbr { /** Jump instruction */ uint8_t jump[3]; /** OEM identifier */ char oemid[8]; /** Number of bytes per sector */ uint16_t bytes_per_sector; /** Number of sectors per cluster */ uint8_t sectors_per_cluster; /** Number of reserved sectors */ uint16_t reserved_sectors; /** Number of FATs */ uint8_t fats; /** Number of root directory entries (FAT12/FAT16 only) */ uint16_t root_directory_entries; /** Total number of sectors (0 if more than 65535) */ uint16_t sectors_short; /** Media descriptor type */ uint8_t media; /** Number of sectors per FAT (FAT12/FAT16 only) */ uint16_t sectors_per_fat_short; /** Number of sectors per track */ uint16_t sectors_per_track; /** Number of heads */ uint16_t heads; /** Number of hidden sectors (i.e. LBA of start of partition) */ uint32_t hidden_sectors; /** Total number of sectors */ uint32_t sectors; /* FAT32-specific fields */ /** Sectors per FAT */ uint32_t sectors_per_fat; /** Flags */ uint16_t flags; /** FAT version number */ uint16_t version; /** Root directory cluster */ uint32_t root; /** FSInfo sector */ uint16_t fsinfo; /** Backup boot sector */ uint16_t backup; /** Reserved */ uint8_t reserved[12]; /** Drive number */ uint8_t drive; /** Windows NT flags */ uint8_t nt_flags; /** Signature */ uint8_t signature; /** Volume ID serial */ uint32_t serial; /** Label (space-padded) */ char label[11]; /** System identifier */ char system[8]; /** Boot code */ uint8_t code[420]; /** 0x55aa signature */ uint16_t magic; } __attribute__ (( packed )); /** VBR jump instruction * * bootmgr.exe will actually fail unless this is present. Someone * must read specification documents without bothering to understand * what's really happening. */ #define VDISK_VBR_JUMP_WTF_MS 0xe9 /** VBR OEM ID */ #define VDISK_VBR_OEMID "wimboot\0" /** VBR media type */ #define VDISK_VBR_MEDIA 0xf8 /** VBR signature */ #define VDISK_VBR_SIGNATURE 0x29 /** VBR serial number */ #define VDISK_VBR_SERIAL 0xf00df00d /** VBR label */ #define VDISK_VBR_LABEL "wimboot " /** VBR system identifier */ #define VDISK_VBR_SYSTEM "FAT32 " /** VBR magic */ #define VDISK_VBR_MAGIC 0xaa55 /***************************************************************************** * * FSInfo * ***************************************************************************** */ /** FSInfo sector */ #define VDISK_FSINFO_SECTOR 0x00000001 /** FSInfo LBA */ #define VDISK_FSINFO_LBA ( VDISK_VBR_LBA + VDISK_FSINFO_SECTOR ) /** FSInfo sector count */ #define VDISK_FSINFO_COUNT 1 /** FSInfo */ struct vdisk_fsinfo { /** First signature */ uint32_t magic1; /** Reserved */ uint8_t reserved_1[480]; /** Second signature */ uint32_t magic2; /** Free cluster count */ uint32_t free_count; /** Next free cluster */ uint32_t next_free; /** Reserved */ uint8_t reserved_2[12]; /** Third signature */ uint32_t magic3; } __attribute__ (( packed )); /** FSInfo first signature */ #define VDISK_FSINFO_MAGIC1 0x41615252 /** FSInfo second signature */ #define VDISK_FSINFO_MAGIC2 0x61417272 /** FSInfo next free cluster */ #define VDISK_FSINFO_NEXT_FREE 0xffffffff /* No free clusters */ /** FSInfo third signature */ #define VDISK_FSINFO_MAGIC3 0xaa550000 /***************************************************************************** * * Backup Volume Boot Record * ***************************************************************************** */ /** Backup Volume Boot Record sector */ #define VDISK_BACKUP_VBR_SECTOR 0x00000006 /** Backup Volume Boot Record LBA */ #define VDISK_BACKUP_VBR_LBA ( VDISK_VBR_LBA + VDISK_BACKUP_VBR_SECTOR ) /** Backup Volume Boot Record sector count */ #define VDISK_BACKUP_VBR_COUNT 1 /***************************************************************************** * * File Allocation Table * ***************************************************************************** */ /** FAT sector */ #define VDISK_FAT_SECTOR VDISK_RESERVED_COUNT /** FAT LBA */ #define VDISK_FAT_LBA ( VDISK_VBR_LBA + VDISK_FAT_SECTOR ) /** FAT sector count */ #define VDISK_FAT_COUNT VDISK_SECTORS_PER_FAT /** FAT end marker */ #define VDISK_FAT_END_MARKER 0x0ffffff8 /***************************************************************************** * * Directory entries * ***************************************************************************** */ /** An 8.3 filename record */ struct vdisk_short_filename { /** Filename */ union { /** Structured 8.3 base name and extension */ struct { /** Base name */ char base[8]; /** Extension */ char ext[3]; } __attribute__ (( packed )); /** Raw bytes */ uint8_t raw[11]; } filename; /** Attributes */ uint8_t attr; /** Reserved */ uint8_t reserved; /** Creation time in tenths of a second */ uint8_t created_deciseconds; /** Creation time (HMS packed) */ uint16_t created_time; /** Creation date (YMD packed) */ uint16_t created_date; /** Last accessed date (YMD packed) */ uint16_t accessed_date; /** High 16 bits of starting cluster number */ uint16_t cluster_high; /** Modification time (HMS packed) */ uint16_t modified_time; /** Modification date (YMD packed) */ uint16_t modified_date; /** Low 16 bits of starting cluster number */ uint16_t cluster_low; /** Size */ uint32_t size; } __attribute__ (( packed )); /** A long filename record */ struct vdisk_long_filename { /** Sequence number */ uint8_t sequence; /** Name characters */ uint16_t name_1[5]; /** Attributes */ uint8_t attr; /** Type */ uint8_t type; /** Checksum of 8.3 name */ uint8_t checksum; /** Name characters */ uint16_t name_2[6]; /** Reserved */ uint16_t reserved; /** Name characters */ uint16_t name_3[2]; } __attribute__ (( packed )); /** Directory entry attributes */ enum vdisk_directory_entry_attributes { VDISK_READ_ONLY = 0x01, VDISK_HIDDEN = 0x02, VDISK_SYSTEM = 0x04, VDISK_VOLUME_LABEL = 0x08, VDISK_DIRECTORY = 0x10, }; /** Long filename end-of-sequence marker */ #define VDISK_LFN_END 0x40 /** Long filename attributes */ #define VDISK_LFN_ATTR \ ( VDISK_READ_ONLY | VDISK_HIDDEN | VDISK_SYSTEM | VDISK_VOLUME_LABEL ) /** A directory entry */ union vdisk_directory_entry { /** Deleted file marker */ uint8_t deleted; /** 8.3 filename */ struct vdisk_short_filename dos; /** Long filename */ struct vdisk_long_filename lfn; } __attribute__ (( packed )); /** Magic marker for deleted files */ #define VDISK_DIRENT_DELETED 0xe5 /** Number of directory entries per sector */ #define VDISK_DIRENT_PER_SECTOR \ ( VDISK_SECTOR_SIZE / \ sizeof ( union vdisk_directory_entry ) ) /** A directory sector */ struct vdisk_directory { /** Entries */ union vdisk_directory_entry entry[VDISK_DIRENT_PER_SECTOR]; } __attribute__ (( packed )); /***************************************************************************** * * Root directory * ***************************************************************************** */ /** Root directory cluster */ #define VDISK_ROOT_CLUSTER 2 /** Root directory sector */ #define VDISK_ROOT_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_ROOT_CLUSTER ) /** Root directory LBA */ #define VDISK_ROOT_LBA ( VDISK_VBR_LBA + VDISK_ROOT_SECTOR ) /***************************************************************************** * * Boot directory * ***************************************************************************** */ /** Boot directory cluster */ #define VDISK_BOOT_CLUSTER 3 /** Boot directory sector */ #define VDISK_BOOT_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_BOOT_CLUSTER ) /** Boot directory LBA */ #define VDISK_BOOT_LBA ( VDISK_VBR_LBA + VDISK_BOOT_SECTOR ) /***************************************************************************** * * Sources directory * ***************************************************************************** */ /** Sources directory cluster */ #define VDISK_SOURCES_CLUSTER 4 /** Sources directory sector */ #define VDISK_SOURCES_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_SOURCES_CLUSTER ) /** Sources directory LBA */ #define VDISK_SOURCES_LBA ( VDISK_VBR_LBA + VDISK_SOURCES_SECTOR ) /***************************************************************************** * * Fonts directory * ***************************************************************************** */ /** Fonts directory cluster */ #define VDISK_FONTS_CLUSTER 5 /** Fonts directory sector */ #define VDISK_FONTS_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_FONTS_CLUSTER ) /** Fonts directory LBA */ #define VDISK_FONTS_LBA ( VDISK_VBR_LBA + VDISK_FONTS_SECTOR ) /***************************************************************************** * * Resources directory * ***************************************************************************** */ /** Resources directory cluster */ #define VDISK_RESOURCES_CLUSTER 6 /** Resources directory sector */ #define VDISK_RESOURCES_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_RESOURCES_CLUSTER ) /** Resources directory LBA */ #define VDISK_RESOURCES_LBA ( VDISK_VBR_LBA + VDISK_RESOURCES_SECTOR ) /***************************************************************************** * * EFI directory * ***************************************************************************** */ /** EFI directory cluster */ #define VDISK_EFI_CLUSTER 7 /** EFI directory sector */ #define VDISK_EFI_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_EFI_CLUSTER ) /** EFI directory LBA */ #define VDISK_EFI_LBA ( VDISK_VBR_LBA + VDISK_EFI_SECTOR ) /***************************************************************************** * * Microsoft directory * ***************************************************************************** */ /** Microsoft directory cluster */ #define VDISK_MICROSOFT_CLUSTER 8 /** Microsoft directory sector */ #define VDISK_MICROSOFT_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_MICROSOFT_CLUSTER ) /** Microsoft directory LBA */ #define VDISK_MICROSOFT_LBA ( VDISK_VBR_LBA + VDISK_MICROSOFT_SECTOR ) /***************************************************************************** * * Files * ***************************************************************************** */ /** Maximum virtual filename length (excluding NUL) */ #define VDISK_NAME_LEN 31 /** A virtual file */ struct vdisk_file { /** Filename */ char name[ VDISK_NAME_LEN + 1 /* NUL */ ]; /** Opaque token */ void *opaque; /** Length (excluding any zero-padding) */ size_t len; /** Length (including any zero-padding) */ size_t xlen; /** Read data * * @v file Virtual file * @v data Data buffer * @v offset Starting offset * @v len Length */ void ( * read ) ( struct vdisk_file *file, void *data, size_t offset, size_t len ); /** Patch data (optional) * * @v file Virtual file * @v data Data buffer * @v offset Starting offset * @v len Length */ void ( * patch ) ( struct vdisk_file *file, void *data, size_t offset, size_t len ); }; extern struct vdisk_file vdisk_files[VDISK_MAX_FILES]; extern void vdisk_read ( uint64_t lba, unsigned int count, void *data ); extern struct vdisk_file * vdisk_add_file ( const char *name, void *opaque, size_t len, void ( * read ) ( struct vdisk_file *file, void *data, size_t offset, size_t len ) ); extern void vdisk_patch_file ( struct vdisk_file *file, void ( * patch ) ( struct vdisk_file *file, void *data, size_t offset, size_t len ) ); #endif /* _VDISK_H */