Working SDHOST/FatFS, boot partition mounts, some other minor fixes too.
[rpi-open-firmware.git] / arm_chainloader / drivers / mbr_disk.cc
1 /*=============================================================================
2 Copyright (C) 2016 Kristina Brooks
3 All rights reserved.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 FILE DESCRIPTION
16 MBR based disk interface modelling primary partitions as separate disks.
17
18 =============================================================================*/
19
20 #include <stdint.h>
21 #include <chainloader.h>
22
23 #include "block_device.hpp"
24
25 #define logf(fmt, ...) printf("[MBRDISK:%s]: " fmt, __FUNCTION__, ##__VA_ARGS__);
26
27 /*****************************************************************************
28 * MBR
29 *****************************************************************************/
30
31 struct MbrPartition {
32 uint8_t part_flag; /* bootstrap flags */
33 uint8_t part_shd; /* starting head */
34 uint8_t part_ssect; /* starting sector */
35 uint8_t part_scyl; /* starting cylinder */
36 uint8_t part_typ; /* partition type */
37 uint8_t part_ehd; /* end head */
38 uint8_t part_esect; /* end sector */
39 uint8_t part_ecyl; /* end cylinder */
40 #if 0
41 uint16_t part_start_lo; /* absolute starting ... */
42 uint16_t part_start_hi; /* ... sector number */
43 uint16_t part_size_lo; /* partition size ... */
44 uint16_t part_size_hi; /* ... in sectors */
45 #endif
46 uint32_t part_start;
47 uint32_t part_size;
48 } __attribute__((packed));
49
50 #define MBR_SIG 0xAA55
51
52 struct Mbr {
53 uint16_t mbr_code[223];
54 MbrPartition mbr_part[4];
55 uint16_t mbr_sig;
56 } __attribute__((packed));
57
58 static_assert(sizeof(Mbr) >= 512, "What the fuck");
59
60 #define MBR_FAT16 0x04
61 #define MBR_FAT32 0x0B
62 #define MBR_FAT32_INT13 0x0C
63 #define MBR_FAT16_INT13 0x0E
64 #define MBR_LINUX 0x83
65 #define MBR_NTFS 0x07
66
67 static const char* mbr_fs_to_string(int fs) {
68 switch (fs) {
69 case MBR_FAT32: return "FAT32"; break;
70 case MBR_FAT32_INT13: return "FAT32-INT13"; break;
71 case MBR_FAT16_INT13: return "FAT16-INT13"; break;
72 case MBR_FAT16: return "FAT16"; break;
73 case MBR_LINUX: return "Linux (ext2/ext3)"; break;
74 case MBR_NTFS: return "NTFS"; break;
75 default: return "<Unknown>";
76 }
77 }
78
79 struct MbrImpl {
80 Mbr* mbr;
81 BlockDevice* mmc;
82
83 inline bool validate_signature() {
84 return reinterpret_cast<uint16_t>(mbr->mbr_sig) == MBR_SIG;
85 }
86
87 template <typename T>
88 inline bool read_block(uint8_t volume, uint32_t sector, T* dest_buffer) {
89 read_block(volume, sector, reinterpret_cast<uint32_t*>(dest_buffer));
90 }
91
92 inline unsigned int get_block_size() {
93 return mmc->block_size;
94 }
95
96 inline int get_partition_type(uint8_t volume) {
97 if (volume > 3)
98 return 0;
99 return mbr->mbr_part[volume].part_typ;
100 }
101
102 bool read_block(uint8_t volume, uint32_t sector, uint32_t* buf) {
103 if (volume > 3)
104 return false;
105
106 MbrPartition& p = mbr->mbr_part[volume];
107
108 if (p.part_typ == 0)
109 return false;
110
111 return mmc->read_block(p.part_start + sector, buf);
112 }
113
114 void read_mbr() {
115 logf("Reading master boot record ...\n");
116
117 if (!mmc->read_block(0, mbr)) {
118 panic("unable to read master boot record from the SD card");
119 }
120
121 if (!validate_signature()) {
122 panic("invalid master boot record signature (got 0x%x)", mbr->mbr_sig);
123 }
124
125 logf("MBR contents:\n");
126
127 for (int i = 0; i < 4; i++) {
128 MbrPartition& p = mbr->mbr_part[i];
129 printf(" %d: %s at:%d size:%d\n", i, mbr_fs_to_string(p.part_typ), p.part_start, p.part_size);
130 }
131 }
132
133 MbrImpl() {
134 mbr = new Mbr;
135 mmc = get_sdhost_device();
136 if (!mmc) {
137 panic("parent block device not initilalized!");
138 }
139 read_mbr();
140 logf("Disk ready!\n");
141 }
142 };
143
144 MbrImpl STATIC_FILESYSTEM g_MbrDisk {};
145
146 /*****************************************************************************
147 * Wrappers for FatFS.
148 *****************************************************************************/
149
150 #include "fatfs/diskio.h"
151
152 DSTATUS disk_initialize (BYTE pdrv) {
153 BYTE pt = g_MbrDisk.get_partition_type(pdrv);
154 switch (pt) {
155 case MBR_FAT32_INT13:
156 case MBR_FAT16_INT13:
157 case MBR_FAT32:
158 case MBR_FAT16:
159 logf("Mounting FAT partition %d of type 0x%x\n", pdrv, pt);
160 return (DRESULT)0;
161 }
162 logf("Disk %d isn't a FAT volume (partition type is 0x%x)!\n", pdrv, pt);
163 return STA_NOINIT;
164 }
165
166 DSTATUS disk_status (BYTE pdrv) {
167 return disk_initialize(pdrv);
168 }
169
170 DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
171 while (count--)
172 {
173 g_MbrDisk.read_block(pdrv, sector, buff);
174 sector++;
175 buff += g_MbrDisk.get_block_size();
176 }
177 return (DRESULT)0;
178 }
179
180 DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) {
181 switch (cmd)
182 {
183 case CTRL_SYNC:
184 return (DRESULT)0;
185 case GET_SECTOR_SIZE:
186 *(WORD*)buff = g_MbrDisk.get_block_size();
187 return (DRESULT)0;
188
189 case GET_SECTOR_COUNT:
190 *(WORD*)buff = 0;
191 return (DRESULT)0;
192
193 case GET_BLOCK_SIZE:
194 *(WORD*)buff = 1;
195 return (DRESULT)0;
196 }
197 return RES_PARERR;
198 }
This page took 0.119146 seconds and 4 git commands to generate.