Start work on partition support.
[pintos-anon] / src / devices / partition.c
1 #include "devices/partition.h"
2 #include <stdio.h>
3 #include "threads/malloc.h"
4
5 struct partition
6   {
7     struct disk *disk;
8     disk_sector_t first_sector;
9     disk_sector_t sector_cnt;
10   };
11
12 struct partition partitions[PARTITION_CNT];
13
14 static void scan_partition_table (struct disk *, disk_sector_t);
15
16 void
17 partition_init (void)
18 {
19   int chan, dev;
20
21   for (chan = 0; chan < 2; chan++)
22     for (dev = 0; dev < 2; dev++)
23       {
24         struct disk *disk = disk_get (chan, dev);
25         if (disk != NULL)
26           scan_partition_table (disk, 0);
27       }
28
29 }
30
31 struct partition *
32 partition_get (enum partition_type type)
33 {
34   ASSERT (type < PARTITION_CNT);
35
36   return &partitions[type];
37 }
38
39 disk_sector_t
40 partition_size (struct partition *p)
41 {
42   ASSERT (p != NULL);
43
44   return p->sector_cnt;
45 }
46
47 void
48 partition_read (struct partition *p, disk_sector_t sector, void *buffer)
49 {
50   ASSERT (p != NULL);
51   ASSERT (sector < p->sector_cnt);
52   ASSERT (buffer != NULL);
53
54   disk_read (p->disk, p->first_sector + sector, buffer);
55 }
56
57 void
58 partition_write (struct partition *p, disk_sector_t sector, const void *buffer)
59 {
60   ASSERT (p != NULL);
61   ASSERT (sector < p->sector_cnt);
62   ASSERT (buffer != NULL);
63
64   disk_write (p->disk, p->first_sector + sector, buffer);
65 }
66 \f
67 #define PARTITION_CNT 4
68 #define PARTITION_TABLE_SIGNATURE 0xaa55
69
70 struct partition_table_entry
71   {
72     uint8_t bootable;
73     uint8_t start_chs[3];
74     uint8_t type;
75     uint8_t end_chs[3];
76     uint32_t first_sector;
77     uint32_t sector_cnt;
78   };
79
80 struct partition_table
81   {
82     uint8_t boot_loader[446];
83     struct partition_table_entry partitions[PARTITION_CNT];
84     uint16_t signature;
85   };
86
87 static void register_partition (struct disk *,
88                                 const struct partition_table_entry *,
89                                 enum partition_type);
90
91 static void
92 scan_partition_table (struct disk *disk, disk_sector_t sector)
93 {
94   struct partition_table *pt;
95
96   ASSERT (sizeof *pt == DISK_SECTOR_SIZE);
97   pt = xmalloc (sizeof *pt);
98   disk_read (disk, sector, pt);
99
100   if (pt->signature == PARTITION_TABLE_SIGNATURE)
101     {
102       size_t i;
103
104       for (i = 0; i < PARTITION_CNT; i++)
105         {
106           struct partition_table_entry *pte = &pt->partitions[i];
107
108           switch (pte->type)
109             {
110             case 0x05: /* DOS extended partition. */
111             case 0x0f: /* Windows 95 extented partition. */
112             case 0x85: /* Linux extended partition. */
113             case 0xc5: /* DRDOS "secured" extended partition. */
114               scan_partition_table (disk, pte->first_sector);
115               break;
116
117             case 0x20: /* Pintos boot partition. */
118               register_partition (disk, pte, PARTITION_BOOT);
119               break;
120
121             case 0x21: /* Pintos file system partition. */
122               register_partition (disk, pte, PARTITION_FILESYS);
123               break;
124
125             case 0x22: /* Pintos scratch partition. */
126               register_partition (disk, pte, PARTITION_SCRATCH);
127               break;
128
129             case 0x23: /* Pintos swap partition. */
130               register_partition (disk, pte, PARTITION_SWAP);
131               break;
132
133             default:
134               /* We don't know anything about this kind of
135                  partition.  Ignore it. */
136               break;
137             }
138
139         }
140     }
141
142   free (pt);
143 }
144
145 static void
146 register_partition (struct disk *disk, const struct partition_table_entry *pte,
147                     enum partition_type type)
148 {
149   static const char *partition_names[] =
150     {"boot", "file system", "scratch", "swap"};
151   struct partition *p;
152
153   ASSERT (type < PARTITION_CNT);
154
155   printf ("%s: Found %"PRDSNu" sector (", disk_name (disk), pte->sector_cnt);
156   print_human_readable_size ((uint64_t) pte->sector_cnt * DISK_SECTOR_SIZE);
157   printf (") %s partition starting at sector %"PRDSNu"\n",
158           partition_names[pte->type], pte->first_sector);
159
160   p = &partitions[type];
161   if (p->disk != NULL)
162     PANIC ("Can't handle multiple %s partitions", partition_names[pte->type]);
163   p->disk = disk;
164   p->first_sector = pte->first_sector;
165   p->sector_cnt = pte->sector_cnt;
166 }