Start work on partition support.
[pintos-anon] / src / devices / partition.c
diff --git a/src/devices/partition.c b/src/devices/partition.c
new file mode 100644 (file)
index 0000000..796e816
--- /dev/null
@@ -0,0 +1,166 @@
+#include "devices/partition.h"
+#include <stdio.h>
+#include "threads/malloc.h"
+
+struct partition
+  {
+    struct disk *disk;
+    disk_sector_t first_sector;
+    disk_sector_t sector_cnt;
+  };
+
+struct partition partitions[PARTITION_CNT];
+
+static void scan_partition_table (struct disk *, disk_sector_t);
+
+void
+partition_init (void)
+{
+  int chan, dev;
+
+  for (chan = 0; chan < 2; chan++)
+    for (dev = 0; dev < 2; dev++)
+      {
+        struct disk *disk = disk_get (chan, dev);
+        if (disk != NULL)
+          scan_partition_table (disk, 0);
+      }
+
+}
+
+struct partition *
+partition_get (enum partition_type type)
+{
+  ASSERT (type < PARTITION_CNT);
+
+  return &partitions[type];
+}
+
+disk_sector_t
+partition_size (struct partition *p)
+{
+  ASSERT (p != NULL);
+
+  return p->sector_cnt;
+}
+
+void
+partition_read (struct partition *p, disk_sector_t sector, void *buffer)
+{
+  ASSERT (p != NULL);
+  ASSERT (sector < p->sector_cnt);
+  ASSERT (buffer != NULL);
+
+  disk_read (p->disk, p->first_sector + sector, buffer);
+}
+
+void
+partition_write (struct partition *p, disk_sector_t sector, const void *buffer)
+{
+  ASSERT (p != NULL);
+  ASSERT (sector < p->sector_cnt);
+  ASSERT (buffer != NULL);
+
+  disk_write (p->disk, p->first_sector + sector, buffer);
+}
+\f
+#define PARTITION_CNT 4
+#define PARTITION_TABLE_SIGNATURE 0xaa55
+
+struct partition_table_entry
+  {
+    uint8_t bootable;
+    uint8_t start_chs[3];
+    uint8_t type;
+    uint8_t end_chs[3];
+    uint32_t first_sector;
+    uint32_t sector_cnt;
+  };
+
+struct partition_table
+  {
+    uint8_t boot_loader[446];
+    struct partition_table_entry partitions[PARTITION_CNT];
+    uint16_t signature;
+  };
+
+static void register_partition (struct disk *,
+                                const struct partition_table_entry *,
+                                enum partition_type);
+
+static void
+scan_partition_table (struct disk *disk, disk_sector_t sector)
+{
+  struct partition_table *pt;
+
+  ASSERT (sizeof *pt == DISK_SECTOR_SIZE);
+  pt = xmalloc (sizeof *pt);
+  disk_read (disk, sector, pt);
+
+  if (pt->signature == PARTITION_TABLE_SIGNATURE)
+    {
+      size_t i;
+
+      for (i = 0; i < PARTITION_CNT; i++)
+        {
+          struct partition_table_entry *pte = &pt->partitions[i];
+
+          switch (pte->type)
+            {
+            case 0x05: /* DOS extended partition. */
+            case 0x0f: /* Windows 95 extented partition. */
+            case 0x85: /* Linux extended partition. */
+            case 0xc5: /* DRDOS "secured" extended partition. */
+              scan_partition_table (disk, pte->first_sector);
+              break;
+
+            case 0x20: /* Pintos boot partition. */
+              register_partition (disk, pte, PARTITION_BOOT);
+              break;
+
+            case 0x21: /* Pintos file system partition. */
+              register_partition (disk, pte, PARTITION_FILESYS);
+              break;
+
+            case 0x22: /* Pintos scratch partition. */
+              register_partition (disk, pte, PARTITION_SCRATCH);
+              break;
+
+            case 0x23: /* Pintos swap partition. */
+              register_partition (disk, pte, PARTITION_SWAP);
+              break;
+
+            default:
+              /* We don't know anything about this kind of
+                 partition.  Ignore it. */
+              break;
+            }
+
+        }
+    }
+
+  free (pt);
+}
+
+static void
+register_partition (struct disk *disk, const struct partition_table_entry *pte,
+                    enum partition_type type)
+{
+  static const char *partition_names[] =
+    {"boot", "file system", "scratch", "swap"};
+  struct partition *p;
+
+  ASSERT (type < PARTITION_CNT);
+
+  printf ("%s: Found %"PRDSNu" sector (", disk_name (disk), pte->sector_cnt);
+  print_human_readable_size ((uint64_t) pte->sector_cnt * DISK_SECTOR_SIZE);
+  printf (") %s partition starting at sector %"PRDSNu"\n",
+          partition_names[pte->type], pte->first_sector);
+
+  p = &partitions[type];
+  if (p->disk != NULL)
+    PANIC ("Can't handle multiple %s partitions", partition_names[pte->type]);
+  p->disk = disk;
+  p->first_sector = pte->first_sector;
+  p->sector_cnt = pte->sector_cnt;
+}