1/**
2 * \file
3 */
4
5/*
6 * Copyright (c) 2009, ETH Zurich.
7 * All rights reserved.
8 *
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
12 */
13
14#include "vmkitmon.h"
15#include "hdd.h"
16#include <stdlib.h>
17#include <string.h>
18
19#define BLOCK_SIZE 512
20
21static void
22calc_chs (struct hdd *hdd)
23{
24    // assure there is disk with at least 516096 bytes space (16H, 63S, 1C)
25    assert(hdd->disk_image != NULL && hdd->disk_image_size >= 516096);
26
27    /* Here we use a predefined sceme to calculate the CHS of the disk. If the
28     * disk is bigger then 8MiB we use 255 heads, if it is smaller we use 16
29     * heads. This conforms (at least for 8MiB and bigger disks) with the Linux
30     * fdisk tools and their undestanding of the geometry of non physical disks.
31     * Secotors are always 63 per track wich leaves the cylinder value to be the
32     * only one which really needs to be calculated.
33     * Personally I have no idea how wide spread this understanding is!. */
34
35    // set the heads
36    if (hdd->disk_image_size >= 0x800000) {
37        hdd->heads = 255;
38    } else {
39        hdd->heads = 16;
40    }
41
42    // set the sectors per track
43    hdd->sectors = 63;
44
45    // calculate the size
46    hdd->track_size = hdd->sectors * BLOCK_SIZE;
47    hdd->cylinder_size = hdd->heads * hdd->track_size;
48    // the disk has to be a multiple of the cylinder size, so we round the real
49    // disk size down the nearest multiple of cylinder size
50    size_t real_disk_size = hdd->disk_image_size -
51                            (hdd->disk_image_size % hdd->cylinder_size);
52    assert(real_disk_size >= 516096);
53    // now we may safely calculate the cylinders count
54    hdd->cylinders = real_disk_size / hdd->cylinder_size;
55}
56
57struct hdd *
58hdd_new_from_memory (void *disk_image, size_t disk_image_size)
59{
60    struct hdd *ret = calloc(1, sizeof(struct hdd));
61
62    ret->disk_image = disk_image;
63    ret->disk_image_size = disk_image_size;
64
65    calc_chs(ret);
66
67    return ret;
68}
69
70void
71hdd_reset (struct hdd *hdd)
72{
73}
74
75int
76hdd_get_geometry_chs (struct hdd *hdd, uint16_t *cylinders, uint8_t *heads,
77                      uint8_t *sectors)
78{
79    *cylinders = hdd->cylinders;
80    *heads = hdd->heads;
81    *sectors = hdd->sectors;
82
83    return 0;
84}
85
86size_t
87hdd_get_blocks_count (struct hdd *hdd)
88{
89    return hdd->disk_image_size / BLOCK_SIZE;
90}
91
92int
93hdd_read_blocks (struct hdd *hdd, size_t start_block, size_t *count,
94                 uintptr_t buffer)
95{
96    if (((start_block + *count) * BLOCK_SIZE) > hdd->disk_image_size) {
97        *count = hdd->disk_image_size/BLOCK_SIZE - start_block;
98    }
99
100    memcpy((void *)buffer, (void *)(hdd->disk_image + start_block*BLOCK_SIZE),
101           *count * BLOCK_SIZE);
102
103    return HANDLER_ERR_OK;
104}
105