1 /* 2 * Copyright 2016-2020 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <boot/partitions.h> 8 #include <boot/platform.h> 9 #include <boot/stage2.h> 10 11 #include "efi_platform.h" 12 #include <efi/protocol/block-io.h> 13 14 15 //#define TRACE_DEVICES 16 #ifdef TRACE_DEVICES 17 # define TRACE(x...) dprintf("efi/devices: " x) 18 #else 19 # define TRACE(x...) ; 20 #endif 21 22 23 static efi_guid BlockIoGUID = EFI_BLOCK_IO_PROTOCOL_GUID; 24 25 26 class EfiDevice : public Node 27 { 28 public: 29 EfiDevice(efi_block_io_protocol *blockIo); 30 virtual ~EfiDevice(); 31 32 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, 33 size_t bufferSize); 34 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, 35 size_t bufferSize) { return B_UNSUPPORTED; } 36 virtual off_t Size() const { 37 return (fBlockIo->Media->LastBlock + 1) * BlockSize(); } 38 39 uint32 BlockSize() const { return fBlockIo->Media->BlockSize; } 40 bool ReadOnly() const { return fBlockIo->Media->ReadOnly; } 41 private: 42 efi_block_io_protocol* fBlockIo; 43 }; 44 45 46 EfiDevice::EfiDevice(efi_block_io_protocol *blockIo) 47 : 48 fBlockIo(blockIo) 49 { 50 } 51 52 53 EfiDevice::~EfiDevice() 54 { 55 } 56 57 58 ssize_t 59 EfiDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 60 { 61 TRACE("%s called. pos: %" B_PRIdOFF ", %p, %" B_PRIuSIZE "\n", __func__, 62 pos, buffer, bufferSize); 63 64 off_t offset = pos % BlockSize(); 65 pos /= BlockSize(); 66 67 uint32 numBlocks = (offset + bufferSize + BlockSize()) / BlockSize(); 68 char readBuffer[numBlocks * BlockSize()]; 69 70 if (fBlockIo->ReadBlocks(fBlockIo, fBlockIo->Media->MediaId, 71 pos, sizeof(readBuffer), readBuffer) != EFI_SUCCESS) 72 return B_ERROR; 73 74 memcpy(buffer, readBuffer + offset, bufferSize); 75 76 return bufferSize; 77 } 78 79 80 static off_t 81 get_next_check_sum_offset(int32 index, off_t maxSize) 82 { 83 TRACE("%s: called\n", __func__); 84 85 if (index < 2) 86 return index * 512; 87 88 if (index < 4) 89 return (maxSize >> 10) + index * 2048; 90 91 return ((system_time() + index) % (maxSize >> 9)) * 512; 92 } 93 94 95 static uint32 96 compute_check_sum(Node *device, off_t offset) 97 { 98 TRACE("%s: called\n", __func__); 99 100 char buffer[512]; 101 ssize_t bytesRead = device->ReadAt(NULL, offset, buffer, sizeof(buffer)); 102 if (bytesRead < B_OK) 103 return 0; 104 105 if (bytesRead < (ssize_t)sizeof(buffer)) 106 memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead); 107 108 uint32 *array = (uint32*)buffer; 109 uint32 sum = 0; 110 111 for (uint32 i = 0; i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); i++) 112 sum += array[i]; 113 114 return sum; 115 } 116 117 118 status_t 119 platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) 120 { 121 TRACE("%s: called\n", __func__); 122 123 efi_block_io_protocol *blockIo; 124 size_t memSize = 0; 125 126 // Read to zero sized buffer to get memory needed for handles 127 if (kBootServices->LocateHandle(ByProtocol, &BlockIoGUID, 0, &memSize, 0) 128 != EFI_BUFFER_TOO_SMALL) 129 panic("Cannot read size of block device handles!"); 130 131 uint32 noOfHandles = memSize / sizeof(efi_handle); 132 133 efi_handle handles[noOfHandles]; 134 if (kBootServices->LocateHandle(ByProtocol, &BlockIoGUID, 0, &memSize, 135 handles) != EFI_SUCCESS) 136 panic("Failed to locate block devices!"); 137 138 // All block devices has one for the disk and one per partition 139 // There is a special case for a device with one fixed partition 140 // But we probably do not care about booting on that kind of device 141 // So find all disk block devices and let Haiku do partition scan 142 for (uint32 n = 0; n < noOfHandles; n++) { 143 if (kBootServices->HandleProtocol(handles[n], &BlockIoGUID, 144 (void**)&blockIo) != EFI_SUCCESS) 145 panic("Cannot get block device handle!"); 146 147 TRACE("%s: %p: present: %s, logical: %s, removeable: %s, " 148 "blocksize: %" B_PRIuSIZE ", lastblock: %" B_PRIu64 "\n", 149 __func__, blockIo, 150 blockIo->Media->MediaPresent ? "true" : "false", 151 blockIo->Media->LogicalPartition ? "true" : "false", 152 blockIo->Media->RemovableMedia ? "true" : "false", 153 blockIo->Media->BlockSize, blockIo->Media->LastBlock); 154 155 if (!blockIo->Media->MediaPresent || blockIo->Media->LogicalPartition) 156 continue; 157 158 EfiDevice *device = new(std::nothrow)EfiDevice(blockIo); 159 if (device == NULL) 160 panic("Can't allocate memory for block devices!"); 161 devicesList->Insert(device); 162 } 163 return devicesList->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND; 164 } 165 166 status_t 167 platform_add_block_devices(struct stage2_args *args, NodeList *devicesList) 168 { 169 TRACE("%s: called\n", __func__); 170 171 //TODO: Currently we add all in platform_add_boot_device 172 return B_ENTRY_NOT_FOUND; 173 } 174 175 status_t 176 platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, 177 NodeList *partitions, boot::Partition **_partition) 178 { 179 TRACE("%s: called\n", __func__); 180 *_partition = (boot::Partition*)partitions->GetIterator().Next(); 181 return *_partition != NULL ? B_OK : B_ENTRY_NOT_FOUND; 182 } 183 184 185 status_t 186 platform_register_boot_device(Node *device) 187 { 188 TRACE("%s: called\n", __func__); 189 190 EfiDevice *efiDevice = (EfiDevice *)device; 191 disk_identifier identifier; 192 193 identifier.bus_type = UNKNOWN_BUS; 194 identifier.device_type = UNKNOWN_DEVICE; 195 identifier.device.unknown.size = device->Size(); 196 197 for (uint32 i = 0; i < NUM_DISK_CHECK_SUMS; ++i) { 198 off_t offset = get_next_check_sum_offset(i, device->Size()); 199 identifier.device.unknown.check_sums[i].offset = offset; 200 identifier.device.unknown.check_sums[i].sum = compute_check_sum(device, 201 offset); 202 } 203 204 gBootVolume.SetInt32(BOOT_METHOD, efiDevice->ReadOnly() ? BOOT_METHOD_CD: 205 BOOT_METHOD_HARD_DISK); 206 gBootVolume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, efiDevice->ReadOnly()); 207 gBootVolume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE, 208 &identifier, sizeof(disk_identifier)); 209 210 return B_OK; 211 } 212 213 214 void 215 platform_cleanup_devices() 216 { 217 } 218