~cypheon/xos

xos/ide.c -rw-r--r-- 1.8 KiB
567db604 — Johann Rudloff Implement scanning and allocation of physical memory. 7 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <sys/io.h>
#include <sys/memory.h>
#include <sys/types.h>

#include <dev/ide.h>

#define PIO_READ 0x20

int ide_bdev_read(void *priv, void *dst, size_t lba, size_t num_blocks) {
  return ide_read((ide_dev_t *)priv, dst, lba, num_blocks);
};

struct blockdev *ide_create_dev(int channel, int drive) {
  ide_dev_t *ide_dev = kmalloc(sizeof(ide_dev_t));
  ide_dev->ioport_base = 0x1f0;
  ide_dev->slave_bit = drive;
  ide_dev->first_block = 0;

  struct blockdev *bdev = kmalloc(sizeof(struct blockdev));
  bdev->priv = ide_dev;
  bdev->read_blocks = ide_bdev_read;
  return bdev;
}

struct blockdev *ide_create_partition(int channel, int drive, int partnum) {
  ide_dev_t *ide_dev = kmalloc(sizeof(ide_dev_t));
  ide_dev->ioport_base = 0x1f0;
  ide_dev->slave_bit = drive;
  ide_dev->first_block = 10;

  struct blockdev *bdev = kmalloc(sizeof(struct blockdev));
  bdev->priv = ide_dev;
  bdev->read_blocks = ide_bdev_read;
  return bdev;
}

int ide_read(ide_dev_t *dev, void *dst, size_t lba, size_t num_blocks) {
  uint16_t ioport_base = dev->ioport_base;

  lba += dev->first_block;

  if (num_blocks > 256) {
    return -1;
  }

  for(int i=0; i<4; i++) {
    inb(ioport_base + 7);
  }
  outb(ioport_base + 6, 0xe0 | (dev->slave_bit << 4));
  for(int i=0; i<4; i++) {
    inb(ioport_base + 7);
  }
  outb(ioport_base + 6, 0xe0 | (dev->slave_bit << 4) | (lba >> 24 & 0x0f));
  outb(ioport_base + 2, (num_blocks & 0xff));

  outb(ioport_base + 3, lba >> 0 & 0xff);
  outb(ioport_base + 4, lba >> 8 & 0xff);
  outb(ioport_base + 5, lba >> 16 & 0xff);

  outb(ioport_base + 7, PIO_READ);

  // read 512 byte blocks as 128 x 4 bytes
  uint32_t *p = dst;
  for (uint32_t b = 0; b < num_blocks; b++) {
    while (inb(ioport_base + 7) & 0x80) {};
    for (uint32_t i = 0; i < 128; i++) {
      *p++ = ind(ioport_base);
    }
  }

  return 0;
}