Modules/ATA - Bugfix to MBR extended partition handling
[tpg/acess2.git] / KernelLand / Modules / Storage / ATA / mbr.c
1 /*
2  * Acess2 IDE Harddisk Driver
3  * - MBR Parsing Code
4  * mbr.c
5  */
6 #define DEBUG   0
7 #include <acess.h>
8 #include "common.h"
9
10 // === PROTOTYPES ===
11 void    ATA_ParseMBR(int Disk, tMBR *MBR);
12 Uint64  ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length);
13
14 // === GLOBALS ===
15
16 // === CODE ===
17 /**
18  * \fn void ATA_ParseMBR(int Disk, tMBR *MBR)
19  */
20 void ATA_ParseMBR(int Disk, tMBR *MBR)
21 {
22          int    i, j = 0, k = 4;
23         Uint64  extendedLBA;
24         Uint64  base, len;
25         
26         ENTER("iDisk", Disk);
27         
28         // Count Partitions
29         gATA_Disks[Disk].NumPartitions = 0;
30         extendedLBA = 0;
31         for( i = 0; i < 4; i ++ )
32         {
33                 if( MBR->Parts[i].SystemID == 0 )       continue;
34                 
35                 if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
36                 {
37                         base = MBR->Parts[i].LBAStart;
38                 }
39                 else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 48
40                 {
41                         base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
42                 }
43                 else
44                         continue;       // Invalid, don't count
45
46                 if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
47                         LOG("Extended Partition at 0x%llx", base);
48                         if(extendedLBA != 0) {
49                                 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
50                                 continue;
51                         }
52                         extendedLBA = base;
53                 }
54                 else {
55                         LOG("Primary Partition at 0x%llx", base);
56                         
57                         gATA_Disks[Disk].NumPartitions ++;
58                 }
59         }
60         while(extendedLBA != 0)
61         {
62                 extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
63                 if( extendedLBA == -1 ) break;
64                 gATA_Disks[Disk].NumPartitions ++;
65         }
66         LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
67         
68         // Create patition array
69         gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
70         
71         // --- Fill Partition Info ---
72         extendedLBA = 0;
73         for( j = 0, i = 0; i < 4; i ++ )
74         {
75                 LOG("MBR->Parts[%i].SystemID = 0x%02x", i, MBR->Parts[i].SystemID);
76                 if( MBR->Parts[i].SystemID == 0 )       continue;
77                 if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
78                 {
79                         base = MBR->Parts[i].LBAStart;
80                         len = MBR->Parts[i].LBALength;
81                 }
82                 else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 48
83                 {
84                         base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
85                         len = (MBR->Parts[i].LengthHi << 16) | MBR->Parts[i].LBALength;
86                 }
87                 else
88                         continue;
89                 
90                 if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
91                         if(extendedLBA != 0) {
92                                 Log_Warning("ATA", "Disk %i has multiple extended partitions, ignoring rest", Disk);
93                                 continue;
94                         }
95                         extendedLBA = base;
96                         continue;
97                 }
98                 // Create Partition
99                 ATA_int_MakePartition(
100                         &gATA_Disks[Disk].Partitions[j], Disk, j,
101                         base, len
102                         );
103                 j ++;
104                 
105         }
106         // Scan extended partitions
107         while(extendedLBA != 0)
108         {
109                 extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
110                 if(extendedLBA == -1)   break;
111                 ATA_int_MakePartition(
112                         &gATA_Disks[Disk].Partitions[j], Disk, k, base, len
113                         );
114         }
115         
116         LEAVE('-');
117 }
118
119 /**
120  * \brief Reads an extended partition
121  * \return LBA of next Extended, -1 on error, 0 for last
122  */
123 Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length)
124 {
125         Uint64  link = 0;
126          int    bFoundPart = 0;;
127          int    i;
128         tMBR    mbr;
129         Uint64  base, len;
130         
131         if( ATA_ReadDMA( Disk, Addr, 1, &mbr ) != 0 )
132                 return -1;      // Stop on Errors
133         
134         for( i = 0; i < 4; i ++ )
135         {
136                 if( mbr.Parts[i].SystemID == 0 )        continue;
137                 
138                 // LBA 24
139                 if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) {
140                         base = mbr.Parts[i].LBAStart;
141                         len = mbr.Parts[i].LBALength;
142                 }
143                 // LBA 48
144                 else if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) {
145                         base = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
146                         len = (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength;
147                 }
148                 else {
149                         Log_Warning("ATA MBR",
150                                 "Unknown partition type 0x%x, Disk %i Ext 0x%llx Part %i",
151                                 mbr.Parts[i].Boot, Disk, Addr, i
152                                 );
153                         return -1;
154                 }
155                 base += Addr;   // Addresses are relative
156                 
157                 switch(mbr.Parts[i].SystemID)
158                 {
159                 case 0xF:
160                 case 0x5:
161                         if(link != 0) {
162                                 Log_Warning("ATA MBR",
163                                         "Disk %i has two forward links in the extended partition",
164                                         Disk
165                                         );
166                                 return -1;
167                         }
168                         link = base;
169                         break;
170                 default:
171                         if(bFoundPart) {
172                                 Warning("ATA MBR",
173                                         "Disk %i has more than one partition in the extended partition at 0x%llx",
174                                         Disk, Addr
175                                         );
176                                 return -1;
177                         }
178                         bFoundPart = 1;
179                         *Base = base;
180                         *Length = len;
181                         break;
182                 }
183         }
184         
185         if(!bFoundPart) {
186                 Log_Warning("ATA MBR",
187                         "No partition in extended partiton, Disk %i 0x%llx",
188                         Disk, Addr);
189                 return -1;
190         }
191         
192         return link;
193 }

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