2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018-2019 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
26 uint8_t first_head, first_cyl, first_sect;
28 uint8_t last_head, last_cyl, last_sect;
31 } __attribute__((packed));
33 static int read_sector(int dev, uint64_t sidx);
34 static const char *ptype_name(int type);
36 static unsigned char sectdata[512];
38 #define BOOTSIG_OFFS 510
39 #define PTABLE_OFFS 0x1be
41 #define BOOTSIG 0xaa55
43 #define IS_MBR (sidx == 0)
44 #define IS_FIRST_EBR (!IS_MBR && (first_ebr_offs == 0))
46 int read_partitions(int dev, struct partition *ptab, int ptabsz)
48 int i, num_rec, nparts = 0;
50 struct partition *part = ptab;
51 struct part_record *prec;
53 uint64_t first_ebr_offs = 0;
61 first_ebr_offs = sidx;
64 if(read_sector(dev, sidx) == -1) {
65 printf("failed to read sector %llu\n", (unsigned long long)sidx);
68 if(*(uint16_t*)(sectdata + BOOTSIG_OFFS) != BOOTSIG) {
69 printf("invalid partitionm table, sector %llu has no magic\n", (unsigned long long)sidx);
72 prec = (struct part_record*)(sectdata + PTABLE_OFFS);
74 /* MBR has 4 records, EBRs have 2 */
75 num_rec = IS_MBR ? 4 : 2;
77 for(i=0; i<num_rec; i++) {
78 /* ignore empty partitions in the MBR, stop on empty partitions in an EBR */
79 if(prec[i].type == 0) {
87 /* ignore extended partitions and setup sector index to read the
88 * next logical partition.
90 if(prec[i].type == PTYPE_EXT || prec[i].type == PTYPE_EXT_LBA) {
91 /* all EBR start fields are relative to the first EBR offset */
92 sidx = first_ebr_offs + prec[i].first_lba;
96 /* found a proper partition */
100 part->attr = prec[i].type;
102 if(prec[i].stat & 0x80) {
103 part->attr |= PART_ACT_BIT;
106 part->attr |= PART_PRIM_BIT;
108 part->start_sect = prec[i].first_lba + first_ebr_offs;
109 part->size_sect = prec[i].nsect_lba;
115 } while(sidx > 0 && (!ptab || nparts < ptabsz));
120 void print_partition_table(struct partition *ptab, int npart)
123 struct partition *p = ptab;
125 printf("Found %d partitions\n", npart);
126 for(i=0; i<npart; i++) {
127 printf("%d%c ", i, PART_IS_ACT(p->attr) ? '*' : ' ');
128 printf("(%s) %-20s ", PART_IS_PRIM(p->attr) ? "pri" : "log", ptype_name(PART_TYPE(p->attr)));
129 printf("start: %-10llu ", (unsigned long long)p->start_sect);
130 printf("size: %-10llu\n", (unsigned long long)p->size_sect);
135 static int read_sector(int dev, uint64_t sidx)
137 if(dev == -1 || dev == boot_drive_number) {
138 if(bdev_read_sect(sidx, sectdata) == -1) {
144 printf("BUG: reading partitions of drives other than the boot drive not implemented yet\n");
148 static const char *ptype_name(int type)
152 for(i=0; i<PTYPES_SIZE; i++) {
153 if(partypes[i].type == type) {
154 return partypes[i].name;