19f532d00SPekka Enberg #include "kvm/disk-image.h" 29f532d00SPekka Enberg 39f532d00SPekka Enberg #include "kvm/util.h" 49f532d00SPekka Enberg 59f532d00SPekka Enberg #include <sys/types.h> 6*33d33901SPekka Enberg #include <inttypes.h> 79f532d00SPekka Enberg #include <sys/mman.h> 89f532d00SPekka Enberg #include <sys/stat.h> 99f532d00SPekka Enberg #include <stddef.h> 109f532d00SPekka Enberg #include <stdlib.h> 119f532d00SPekka Enberg #include <unistd.h> 129f532d00SPekka Enberg #include <fcntl.h> 139f532d00SPekka Enberg 149f532d00SPekka Enberg #define SECTOR_SHIFT 9 159f532d00SPekka Enberg #define SECTOR_SIZE (1UL << SECTOR_SHIFT) 169f532d00SPekka Enberg 17*33d33901SPekka Enberg static void setup_geometry(struct disk_image *self) 18*33d33901SPekka Enberg { 19*33d33901SPekka Enberg int cylinders, heads, sectors; 20*33d33901SPekka Enberg uint64_t total_sects; 21*33d33901SPekka Enberg 22*33d33901SPekka Enberg /* 23*33d33901SPekka Enberg * Set the standart disk geometry of the image. 24*33d33901SPekka Enberg * 25*33d33901SPekka Enberg * Real disk example: 26*33d33901SPekka Enberg * 27*33d33901SPekka Enberg * Disk /dev/sda: 500.1 GB, 500107862016 bytes 28*33d33901SPekka Enberg * 255 heads, 63 sectors/track, 60801 cylinders, total 976773168 sectors 29*33d33901SPekka Enberg */ 30*33d33901SPekka Enberg cylinders = (self->size >> SECTOR_SHIFT) / 16383; 31*33d33901SPekka Enberg if (cylinders > 16383) 32*33d33901SPekka Enberg cylinders = 16383; 33*33d33901SPekka Enberg else if (cylinders < 2) 34*33d33901SPekka Enberg cylinders = 2; 35*33d33901SPekka Enberg 36*33d33901SPekka Enberg heads = (self->size >> SECTOR_SHIFT) / cylinders; 37*33d33901SPekka Enberg if (heads > 255) 38*33d33901SPekka Enberg heads = 255; 39*33d33901SPekka Enberg else if (heads < 1) 40*33d33901SPekka Enberg heads = 1; 41*33d33901SPekka Enberg 42*33d33901SPekka Enberg sectors = (self->size >> SECTOR_SHIFT) / cylinders / heads; 43*33d33901SPekka Enberg if (sectors > 255) 44*33d33901SPekka Enberg sectors = 255; 45*33d33901SPekka Enberg else if (sectors < 1) 46*33d33901SPekka Enberg sectors = 1; 47*33d33901SPekka Enberg 48*33d33901SPekka Enberg self->sectors = sectors; 49*33d33901SPekka Enberg self->heads = heads; 50*33d33901SPekka Enberg self->cylinders = cylinders; 51*33d33901SPekka Enberg 52*33d33901SPekka Enberg total_sects = self->sectors * self->heads * self->cylinders; 53*33d33901SPekka Enberg 54*33d33901SPekka Enberg if (total_sects != self->size >> SECTOR_SHIFT) 55*33d33901SPekka Enberg warning("Geometry information advertises %" PRIu64 " total sectors but raw image size has %" PRIu64 " sectors", 56*33d33901SPekka Enberg total_sects, self->size >> SECTOR_SHIFT); 57*33d33901SPekka Enberg } 58*33d33901SPekka Enberg 599f532d00SPekka Enberg struct disk_image *disk_image__open(const char *filename) 609f532d00SPekka Enberg { 619f532d00SPekka Enberg struct disk_image *self; 629f532d00SPekka Enberg struct stat st; 639f532d00SPekka Enberg 649f532d00SPekka Enberg self = malloc(sizeof *self); 659f532d00SPekka Enberg if (!self) 669f532d00SPekka Enberg return NULL; 679f532d00SPekka Enberg 689f532d00SPekka Enberg self->fd = open(filename, O_RDONLY); 699f532d00SPekka Enberg if (self->fd < 0) 709f532d00SPekka Enberg goto failed_free; 719f532d00SPekka Enberg 729f532d00SPekka Enberg if (fstat(self->fd, &st) < 0) 739f532d00SPekka Enberg goto failed_close_fd; 749f532d00SPekka Enberg 759f532d00SPekka Enberg self->size = st.st_size; 769f532d00SPekka Enberg 779f532d00SPekka Enberg self->mmap = mmap(NULL, self->size, PROT_READ, MAP_PRIVATE, self->fd, 0); 789f532d00SPekka Enberg if (self->mmap == MAP_FAILED) 799f532d00SPekka Enberg goto failed_close_fd; 809f532d00SPekka Enberg 81*33d33901SPekka Enberg setup_geometry(self); 82ca7c891bSCyrill Gorcunov 83ca7c891bSCyrill Gorcunov info("block image geometry: sectors: %d heads: %d cylinders: %d", 84*33d33901SPekka Enberg self->sectors, self->heads, self->cylinders); 85ca7c891bSCyrill Gorcunov 869f532d00SPekka Enberg return self; 879f532d00SPekka Enberg 889f532d00SPekka Enberg failed_close_fd: 899f532d00SPekka Enberg close(self->fd); 909f532d00SPekka Enberg failed_free: 919f532d00SPekka Enberg free(self); 929f532d00SPekka Enberg 939f532d00SPekka Enberg return NULL; 949f532d00SPekka Enberg } 959f532d00SPekka Enberg 969f532d00SPekka Enberg void disk_image__close(struct disk_image *self) 979f532d00SPekka Enberg { 989f532d00SPekka Enberg if (munmap(self->mmap, self->size) < 0) 999f532d00SPekka Enberg warning("munmap() failed"); 1009f532d00SPekka Enberg 1019f532d00SPekka Enberg if (close(self->fd) < 0) 1029f532d00SPekka Enberg warning("close() failed"); 1039f532d00SPekka Enberg 1049f532d00SPekka Enberg free(self); 1059f532d00SPekka Enberg } 1069f532d00SPekka Enberg 1075a24a9f2SPekka Enberg int disk_image__read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) 1089f532d00SPekka Enberg { 1099f532d00SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 1109f532d00SPekka Enberg 1115a24a9f2SPekka Enberg if (offset + dst_len > self->size) 1129f532d00SPekka Enberg return -1; 1139f532d00SPekka Enberg 1145a24a9f2SPekka Enberg memcpy(dst, self->mmap + offset, dst_len); 1159f532d00SPekka Enberg 1169f532d00SPekka Enberg return 0; 1179f532d00SPekka Enberg } 118