xref: /kvmtool/disk/core.c (revision 33d3390123dddde69e7df6dc7e1ceee3280e17e1)
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