Serenity Operating System
at hosted 200 lines 7.4 kB view raw
1/* 2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/ByteBuffer.h> 28#include <Kernel/Devices/EBRPartitionTable.h> 29 30#define EBR_DEBUG 31 32namespace Kernel { 33 34EBRPartitionTable::EBRPartitionTable(NonnullRefPtr<BlockDevice> device) 35 : m_device(move(device)) 36{ 37} 38 39EBRPartitionTable::~EBRPartitionTable() 40{ 41} 42 43const MBRPartitionHeader& EBRPartitionTable::header() const 44{ 45 return *reinterpret_cast<const MBRPartitionHeader*>(m_cached_mbr_header); 46} 47 48const EBRPartitionExtension& EBRPartitionTable::ebr_extension() const 49{ 50 return *reinterpret_cast<const EBRPartitionExtension*>(m_cached_ebr_header); 51} 52 53int EBRPartitionTable::index_of_ebr_container() const 54{ 55 for (int i = 0; i < 4; i++) { 56 if (header().entry[i].type == EBR_CHS_CONTAINER || header().entry[i].type == EBR_LBA_CONTAINER) 57 return i; 58 } 59 ASSERT_NOT_REACHED(); 60} 61 62bool EBRPartitionTable::initialize() 63{ 64 if (!m_device->read_block(0, m_cached_mbr_header)) { 65 return false; 66 } 67 auto& header = this->header(); 68 69 m_ebr_container_id = index_of_ebr_container() + 1; 70 71#ifdef EBR_DEBUG 72 klog() << "EBRPartitionTable::initialize: MBR_signature=0x" << String::format("%x", header.mbr_signature); 73#endif 74 75 if (header.mbr_signature != MBR_SIGNATURE) { 76 klog() << "EBRPartitionTable::initialize: bad MBR signature 0x" << String::format("%x", header.mbr_signature); 77 return false; 78 } 79 80 auto& ebr_entry = header.entry[m_ebr_container_id - 1]; 81 if (!m_device->read_block(ebr_entry.offset, m_cached_ebr_header)) { 82 return false; 83 } 84 size_t index = 1; 85 while (index < 128) { // Unlikely to encounter a disk with 128 partitions in this configuration... 86 if (ebr_extension().next_chained_ebr_extension.offset == 0 && ebr_extension().next_chained_ebr_extension.type == 0) { 87 break; 88 } 89 index++; 90 if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, m_cached_ebr_header)) { 91 return false; 92 } 93 } 94 95 m_ebr_chained_extensions_count = index; 96 97 klog() << "EBRPartitionTable::initialize: Extended partitions count - " << m_ebr_chained_extensions_count; 98 99 return true; 100} 101 102RefPtr<DiskPartition> EBRPartitionTable::get_non_extended_partition(unsigned index) 103{ 104 auto& header = this->header(); 105 auto& entry = header.entry[index - 1]; 106 107#ifdef EBR_DEBUG 108 klog() << "EBRPartitionTable::partition: status=0x" << String::format("%x", entry.status) << " offset=0x" << String::format("%x", entry.offset); 109#endif 110 111 if (entry.offset == 0x00) { 112#ifdef EBR_DEBUG 113 klog() << "EBRPartitionTable::partition: missing partition requested index=" << index; 114#endif 115 116 return nullptr; 117 } 118 119#ifdef EBR_DEBUG 120 klog() << "EBRPartitionTable::partition: found partition index=" << index << " type=" << String::format("%x", entry.type); 121#endif 122 123 return DiskPartition::create(m_device, entry.offset, (entry.offset + entry.length)); 124} 125 126RefPtr<DiskPartition> EBRPartitionTable::get_extended_partition(unsigned index) 127{ 128 129 unsigned relative_index = index - m_ebr_container_id; 130 auto& header = this->header(); 131 132#ifdef EBR_DEBUG 133 klog() << "EBRPartitionTable::partition: relative index " << relative_index; 134#endif 135 136 auto& ebr_entry = header.entry[m_ebr_container_id - 1]; 137#ifdef EBR_DEBUG 138 klog() << "EBRPartitionTable::partition: Extended partition, offset 0x" << String::format("%x", ebr_entry.offset) << ", type " << String::format("%x", ebr_entry.type); 139#endif 140 141 if (!m_device->read_block(ebr_entry.offset, m_cached_ebr_header)) { 142 return nullptr; 143 } 144 size_t i = 0; 145 while (i < relative_index) { 146#ifdef EBR_DEBUG 147 klog() << "EBRPartitionTable::partition: logical partition, relative offset 0x" << String::format("%x", ebr_extension().entry.offset) << ", type " << String::format("%x", ebr_extension().entry.type); 148 klog() << "EBRPartitionTable::partition: next logical partition, relative offset 0x" << String::format("%x", ebr_extension().next_chained_ebr_extension.offset) << ", type " << String::format("%x", ebr_extension().next_chained_ebr_extension.type); 149#endif 150 if (ebr_extension().next_chained_ebr_extension.offset == 0 && ebr_extension().next_chained_ebr_extension.type == 0) { 151 break; 152 } 153 154 i++; 155 if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, m_cached_ebr_header)) { 156 return nullptr; 157 } 158 } 159 160#ifdef EBR_DEBUG 161 klog() << "EBRPartitionTable::partition: status=" << String::format("%x", ebr_extension().entry.status) << " offset=" << String::format("%x", ebr_extension().entry.offset + ebr_entry.offset); 162#endif 163 164 if (ebr_extension().entry.offset == 0x00) { 165#ifdef EBR_DEBUG 166 klog() << "EBRPartitionTable::partition: missing partition requested index=" << index; 167#endif 168 169 return nullptr; 170 } 171 172#ifdef EBR_DEBUG 173 klog() << "EBRPartitionTable::partition: found partition index=" << index << " type=" << String::format("%x", ebr_extension().entry.type); 174#endif 175 176 return DiskPartition::create(m_device, ebr_extension().entry.offset + ebr_entry.offset, (ebr_extension().entry.offset + ebr_entry.offset + ebr_extension().entry.length)); 177} 178 179bool EBRPartitionTable::index_is_extended_partition(unsigned index) const 180{ 181 return !(m_ebr_container_id > index || index > (m_ebr_container_id + m_ebr_chained_extensions_count)); 182} 183 184RefPtr<DiskPartition> EBRPartitionTable::partition(unsigned index) 185{ 186 ASSERT(index >= 1 && index <= m_ebr_chained_extensions_count + 4); 187 188 auto& header = this->header(); 189 if (header.mbr_signature != MBR_SIGNATURE) { 190 klog() << "EBRPartitionTable::initialize: bad MBR signature - not initalized? 0x" << String::format("%x", header.mbr_signature); 191 return nullptr; 192 } 193 if (index_is_extended_partition(index)) 194 return get_extended_partition(index); 195 if (index > 4) 196 return get_non_extended_partition(index - m_ebr_chained_extensions_count); 197 return get_non_extended_partition(index); 198} 199 200}