19f532d00SPekka Enberg #include "kvm/disk-image.h" 29f532d00SPekka Enberg 39f532d00SPekka Enberg #include "kvm/util.h" 49f532d00SPekka Enberg 59f532d00SPekka Enberg #include <sys/types.h> 69f532d00SPekka Enberg #include <sys/mman.h> 79f532d00SPekka Enberg #include <sys/stat.h> 89f532d00SPekka Enberg #include <stddef.h> 99f532d00SPekka Enberg #include <stdlib.h> 109f532d00SPekka Enberg #include <unistd.h> 119f532d00SPekka Enberg #include <fcntl.h> 129f532d00SPekka Enberg 139f532d00SPekka Enberg #define SECTOR_SHIFT 9 149f532d00SPekka Enberg #define SECTOR_SIZE (1UL << SECTOR_SHIFT) 159f532d00SPekka Enberg 169f532d00SPekka Enberg struct disk_image *disk_image__open(const char *filename) 179f532d00SPekka Enberg { 189f532d00SPekka Enberg struct disk_image *self; 199f532d00SPekka Enberg struct stat st; 20*ca7c891bSCyrill Gorcunov int cylinders, heads, sectors; 219f532d00SPekka Enberg 229f532d00SPekka Enberg self = malloc(sizeof *self); 239f532d00SPekka Enberg if (!self) 249f532d00SPekka Enberg return NULL; 259f532d00SPekka Enberg 269f532d00SPekka Enberg self->fd = open(filename, O_RDONLY); 279f532d00SPekka Enberg if (self->fd < 0) 289f532d00SPekka Enberg goto failed_free; 299f532d00SPekka Enberg 309f532d00SPekka Enberg if (fstat(self->fd, &st) < 0) 319f532d00SPekka Enberg goto failed_close_fd; 329f532d00SPekka Enberg 339f532d00SPekka Enberg self->size = st.st_size; 349f532d00SPekka Enberg 359f532d00SPekka Enberg self->mmap = mmap(NULL, self->size, PROT_READ, MAP_PRIVATE, self->fd, 0); 369f532d00SPekka Enberg if (self->mmap == MAP_FAILED) 379f532d00SPekka Enberg goto failed_close_fd; 389f532d00SPekka Enberg 39*ca7c891bSCyrill Gorcunov /* 40*ca7c891bSCyrill Gorcunov * set the standart disk geometry of the image 41*ca7c891bSCyrill Gorcunov * 42*ca7c891bSCyrill Gorcunov * real disk example 43*ca7c891bSCyrill Gorcunov * Disk /dev/sda: 500.1 GB, 500107862016 bytes 44*ca7c891bSCyrill Gorcunov * 255 heads, 63 sectors/track, 60801 cylinders, total 976773168 sectors 45*ca7c891bSCyrill Gorcunov */ 46*ca7c891bSCyrill Gorcunov cylinders = (self->size >> SECTOR_SHIFT) / 16383; 47*ca7c891bSCyrill Gorcunov if (cylinders > 16383) 48*ca7c891bSCyrill Gorcunov cylinders = 16383; 49*ca7c891bSCyrill Gorcunov else if (cylinders < 2) 50*ca7c891bSCyrill Gorcunov cylinders = 2; 51*ca7c891bSCyrill Gorcunov heads = (self->size >> SECTOR_SHIFT) / cylinders; 52*ca7c891bSCyrill Gorcunov if (heads > 255) 53*ca7c891bSCyrill Gorcunov heads = 255; 54*ca7c891bSCyrill Gorcunov else if (heads < 1) 55*ca7c891bSCyrill Gorcunov heads = 1; 56*ca7c891bSCyrill Gorcunov sectors = (self->size >> SECTOR_SHIFT) / cylinders / heads; 57*ca7c891bSCyrill Gorcunov if (sectors > 255) 58*ca7c891bSCyrill Gorcunov sectors = 255; 59*ca7c891bSCyrill Gorcunov else if (sectors < 1) 60*ca7c891bSCyrill Gorcunov sectors = 1; 61*ca7c891bSCyrill Gorcunov 62*ca7c891bSCyrill Gorcunov self->sectors = sectors; 63*ca7c891bSCyrill Gorcunov self->heads = heads; 64*ca7c891bSCyrill Gorcunov self->cylinders = cylinders; 65*ca7c891bSCyrill Gorcunov 66*ca7c891bSCyrill Gorcunov info("block image geometry: sectors: %d heads: %d cylinders: %d", 67*ca7c891bSCyrill Gorcunov sectors, heads, cylinders); 68*ca7c891bSCyrill Gorcunov 699f532d00SPekka Enberg return self; 709f532d00SPekka Enberg 719f532d00SPekka Enberg failed_close_fd: 729f532d00SPekka Enberg close(self->fd); 739f532d00SPekka Enberg failed_free: 749f532d00SPekka Enberg free(self); 759f532d00SPekka Enberg 769f532d00SPekka Enberg return NULL; 779f532d00SPekka Enberg } 789f532d00SPekka Enberg 799f532d00SPekka Enberg void disk_image__close(struct disk_image *self) 809f532d00SPekka Enberg { 819f532d00SPekka Enberg if (munmap(self->mmap, self->size) < 0) 829f532d00SPekka Enberg warning("munmap() failed"); 839f532d00SPekka Enberg 849f532d00SPekka Enberg if (close(self->fd) < 0) 859f532d00SPekka Enberg warning("close() failed"); 869f532d00SPekka Enberg 879f532d00SPekka Enberg free(self); 889f532d00SPekka Enberg } 899f532d00SPekka Enberg 905a24a9f2SPekka Enberg int disk_image__read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) 919f532d00SPekka Enberg { 929f532d00SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 939f532d00SPekka Enberg 945a24a9f2SPekka Enberg if (offset + dst_len > self->size) 959f532d00SPekka Enberg return -1; 969f532d00SPekka Enberg 975a24a9f2SPekka Enberg memcpy(dst, self->mmap + offset, dst_len); 989f532d00SPekka Enberg 999f532d00SPekka Enberg return 0; 1009f532d00SPekka Enberg } 101