Modules/LVM - Added caching
[tpg/acess2.git] / KernelLand / Modules / Storage / LVM / mbr.c
1 /*
2  * Acess2 Logical Volume Manager
3  * - By John Hodge (thePowersGang)
4  * 
5  * mbr.c
6  * - MBR Parsing Code
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include "lvm.h"
11 #include "mbr.h"
12
13 // === PROTOTYPES ===
14  int    LVM_MBR_CountSubvolumes(tLVM_Vol *Volume, void *FirstSector);
15 void    LVM_MBR_PopulateSubvolumes(tLVM_Vol *Volume, void *FirstSector);
16 Uint64  LVM_MBR_int_ReadExt(tLVM_Vol *Volume, Uint64 Addr, Uint64 *Base, Uint64 *Length);
17
18 // === GLOBALS ===
19 tLVM_Format     gLVM_MBRType = {
20         .Name = "MBR",
21         .CountSubvolumes = LVM_MBR_CountSubvolumes,
22         .PopulateSubvolumes = LVM_MBR_PopulateSubvolumes
23 };
24
25 // === CODE ===
26 /**
27  * \brief Initialise a volume as 
28  */
29 int LVM_MBR_CountSubvolumes(tLVM_Vol *Volume, void *FirstSector)
30 {
31         tMBR    *MBR = FirstSector;
32          int    i;
33         Uint64  extendedLBA;
34         Uint64  base, len;
35          int    numPartitions = 0;
36         
37         ENTER("pVolume pFirstSector", Volume, FirstSector);
38         
39         // Count Partitions
40         numPartitions = 0;
41         extendedLBA = 0;
42         for( i = 0; i < 4; i ++ )
43         {
44                 if( MBR->Parts[i].SystemID == 0 )       continue;
45         
46                 if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
47                 {
48                         base = MBR->Parts[i].LBAStart;
49                 }
50                 else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 48
51                 {
52                         base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
53                 }
54                 else
55                         continue ;      // Invalid, so don't count
56                 
57                 if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 )
58                 {
59                         LOG("Extended Partition at 0x%llx", base);
60                         if(extendedLBA != 0) {
61                                 Log_Warning(
62                                         "LBA MBR",
63                                         "Volume %p has multiple extended partitions, ignoring all but first",
64                                         Volume
65                                         );
66                                 continue;
67                         }
68                         extendedLBA = base;
69                 }
70                 else
71                 {
72                         LOG("Primary Partition at 0x%llx", base);
73                         numPartitions ++;
74                 }
75         }
76         // Detect the GPT protector
77         if( extendedLBA == 0 && numPartitions == 1 && MBR->Parts[0].SystemID == 0xEE )
78         {
79                 // TODO: Hand off to GPT parsing code
80                 Log_Warning("LBA MBR", "TODO: Hand off to GPT");
81         }
82         
83         // Handle extended partions
84         while(extendedLBA != 0)
85         {
86                 extendedLBA = LVM_MBR_int_ReadExt(Volume, extendedLBA, &base, &len);
87                 if( extendedLBA == (Uint64)-1 )
88                         break;
89                 numPartitions ++;
90         }
91         LOG("numPartitions = %i", numPartitions);
92
93         LEAVE('i', numPartitions);
94         return numPartitions;   
95 }
96
97 void LVM_MBR_PopulateSubvolumes(tLVM_Vol *Volume, void *FirstSector)
98 {
99         Uint64  extendedLBA;
100         Uint64  base, len;
101          int    i, j;
102         tMBR    *MBR = FirstSector;
103
104         ENTER("pVolume pFirstSector", Volume, FirstSector);
105         
106         // --- Fill Partition Info ---
107         extendedLBA = 0;
108         for( j = 0, i = 0; i < 4; i ++ )
109         {
110                 LOG("MBR->Parts[%i].SystemID = 0x%02x", i, MBR->Parts[i].SystemID);
111                 if( MBR->Parts[i].SystemID == 0 )       continue;
112                 if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
113                 {
114                         base = MBR->Parts[i].LBAStart;
115                         len = MBR->Parts[i].LBALength;
116                 }
117                 else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 48
118                 {
119                         base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
120                         len = (MBR->Parts[i].LengthHi << 16) | MBR->Parts[i].LBALength;
121                 }
122                 else
123                         continue;
124                 
125                 if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
126                         if(extendedLBA == 0)
127                                 extendedLBA = base;
128                         continue;
129                 }
130                 // Create Partition
131                 LVM_int_SetSubvolume_Anon( Volume, j, base, len );
132                 j ++;
133                 
134         }
135         // Scan extended partitions
136         while(extendedLBA != 0)
137         {
138                 extendedLBA = LVM_MBR_int_ReadExt(Volume, extendedLBA, &base, &len);
139                 if(extendedLBA == (Uint64)-1)
140                         break;
141                 LVM_int_SetSubvolume_Anon( Volume, j, base, len );
142                 j ++ ;
143         }
144         
145         LEAVE('-');
146 }
147
148 /**
149  * \brief Reads an extended partition
150  * \return LBA of next Extended, -1 on error, 0 for last
151  */
152 Uint64 LVM_MBR_int_ReadExt(tLVM_Vol *Volume, Uint64 Addr, Uint64 *Base, Uint64 *Length)
153 {
154         Uint64  link = 0;
155          int    bFoundPart = 0;;
156          int    i;
157         tMBR    mbr;
158         Uint64  base, len;
159         
160         // TODO: Handle non-512 byte sectors
161         if( LVM_int_ReadVolume( Volume, Addr, 1, &mbr ) != 0 )
162                 return -1;      // Stop on Errors
163         
164         for( i = 0; i < 4; i ++ )
165         {
166                 if( mbr.Parts[i].SystemID == 0 )        continue;
167                 
168                 // LBA 24
169                 if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) {
170                         base = mbr.Parts[i].LBAStart;
171                         len = mbr.Parts[i].LBALength;
172                 }
173                 // LBA 48
174                 else if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) {
175                         base = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
176                         len = (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength;
177                 }
178                 else {
179                         Log_Warning("LVM MBR",
180                                 "Unknown partition type 0x%x, Volume %p Ext 0x%llx Part %i",
181                                 mbr.Parts[i].Boot, Volume, Addr, i
182                                 );
183                         return -1;
184                 }
185                 
186                 switch(mbr.Parts[i].SystemID)
187                 {
188                 case 0xF:
189                 case 0x5:
190                         if(link != 0) {
191                                 Log_Warning("LVM MBR",
192                                         "Volume %p has two forward links in the extended partition",
193                                         Volume
194                                         );
195                                 return -1;
196                         }
197                         link = base;
198                         break;
199                 default:
200                         if(bFoundPart) {
201                                 Warning("LVM MBR",
202                                         "Volume %p has more than one partition in the extended partition at 0x%llx",
203                                         Volume, Addr
204                                         );
205                                 return -1;
206                         }
207                         bFoundPart = 1;
208                         *Base = Addr + base;    // Extended partitions are based off the sub-mbr
209                         *Length = len;
210                         break;
211                 }
212         }
213         
214         if(!bFoundPart) {
215                 Log_Warning("LVM MBR",
216                         "No partition in extended partiton, Volume %p 0x%llx",
217                         Volume, Addr
218                         );
219                 return -1;
220         }
221         
222         return link;
223 }

UCC git Repository :: git.ucc.asn.au