Kernel: Cleanup GPT parsing code
This commit is contained in:
		
							parent
							
								
									2ec18855f2
								
							
						
					
					
						commit
						96579b88cf
					
				|  | @ -3,15 +3,12 @@ | |||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| namespace BAN | ||||
| namespace BAN::UTF8 | ||||
| { | ||||
| 
 | ||||
| 	namespace UTF8 | ||||
| 	{ | ||||
| 		static constexpr uint32_t invalid = 0xFFFFFFFF; | ||||
| 	} | ||||
| 	static constexpr uint32_t invalid = 0xFFFFFFFF; | ||||
| 
 | ||||
| 	static constexpr uint32_t utf8_byte_length(uint8_t first_byte) | ||||
| 	constexpr uint32_t byte_length(uint8_t first_byte) | ||||
| 	{ | ||||
| 		if ((first_byte & 0x80) == 0x00) | ||||
| 			return 1; | ||||
|  | @ -24,9 +21,9 @@ namespace BAN | |||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	static constexpr uint32_t utf8_to_codepoint(uint8_t* bytes) | ||||
| 	constexpr uint32_t to_codepoint(uint8_t* bytes) | ||||
| 	{ | ||||
| 		uint32_t length = utf8_byte_length(bytes[0]); | ||||
| 		uint32_t length = byte_length(bytes[0]); | ||||
| 
 | ||||
| 		for (uint32_t i = 1; i < length; i++) | ||||
| 			if ((bytes[i] & 0xC0) != 0x80) | ||||
|  | @ -43,4 +40,42 @@ namespace BAN | |||
| 		return UTF8::invalid; | ||||
| 	} | ||||
| 
 | ||||
| 	template<typename T> | ||||
| 	constexpr bool from_codepoints(const T* codepoints, size_t count, char* out) | ||||
| 	{ | ||||
| 		uint8_t* ptr = (uint8_t*)out; | ||||
| 
 | ||||
| 		for (size_t i = 0; i < count; i++) | ||||
| 		{ | ||||
| 			if (codepoints[i] < 0x80) | ||||
| 			{ | ||||
| 				*ptr++ = codepoints[i]; | ||||
| 			} | ||||
| 			else if (codepoints[i] < 0x800) | ||||
| 			{ | ||||
| 				*ptr++ = 0xC0 | ((codepoints[i] >> 6) & 0x1F); | ||||
| 				*ptr++ = 0x80 | ((codepoints[i] >> 0) & 0x3F); | ||||
| 			} | ||||
| 			else if (codepoints[i] < 0x10000) | ||||
| 			{ | ||||
| 				*ptr++ = 0xE0 | ((codepoints[i] >> 12) & 0x0F); | ||||
| 				*ptr++ = 0x80 | ((codepoints[i] >>  6) & 0x3F); | ||||
| 				*ptr++ = 0x80 | ((codepoints[i] >>  0) & 0x3F); | ||||
| 			} | ||||
| 			else if (codepoints[i] < 0x110000) | ||||
| 			{ | ||||
| 				*ptr++ = 0xF0 | ((codepoints[i] >> 18) & 0x07); | ||||
| 				*ptr++ = 0x80 | ((codepoints[i] >> 12) & 0x3F); | ||||
| 				*ptr++ = 0x80 | ((codepoints[i] >>  6) & 0x3F); | ||||
| 				*ptr++ = 0x80 | ((codepoints[i] >>  0) & 0x3F); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -38,7 +38,7 @@ namespace Kernel | |||
| 			const uint64_t m_lba_start; | ||||
| 			const uint64_t m_lba_end; | ||||
| 			const uint64_t m_attributes; | ||||
| 			char m_name[36 * 3 + 1]; | ||||
| 			char m_name[36 * 4 + 1]; | ||||
| 		}; | ||||
| 
 | ||||
| 	public: | ||||
|  |  | |||
|  | @ -202,7 +202,7 @@ namespace Kernel | |||
| 					ASSERT(byte_index < 4); | ||||
| 					bytes[byte_index++] = byte; | ||||
| 
 | ||||
| 					uint32_t len = BAN::utf8_byte_length(bytes[0]); | ||||
| 					uint32_t len = BAN::UTF8::byte_length(bytes[0]); | ||||
| 
 | ||||
| 					if (len == 0) | ||||
| 					{ | ||||
|  | @ -211,7 +211,7 @@ namespace Kernel | |||
| 					} | ||||
| 					else if (len == byte_index) | ||||
| 					{ | ||||
| 						uint32_t codepoint = BAN::utf8_to_codepoint(bytes); | ||||
| 						uint32_t codepoint = BAN::UTF8::to_codepoint(bytes); | ||||
| 						if (codepoint == BAN::UTF8::invalid) | ||||
| 							invalid_utf = true; | ||||
| 						else if (glyph_offsets.contains(codepoint)) | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| #include <BAN/Endianness.h> | ||||
| #include <BAN/ScopeGuard.h> | ||||
| #include <BAN/StringView.h> | ||||
| #include <BAN/UTF8.h> | ||||
| #include <kernel/FS/Ext2.h> | ||||
| #include <kernel/FS/VirtualFileSystem.h> | ||||
| #include <kernel/PCI.h> | ||||
|  | @ -14,21 +16,33 @@ namespace Kernel | |||
| 
 | ||||
| 	struct GPTHeader | ||||
| 	{ | ||||
| 		char signature[8]; | ||||
| 		uint32_t revision; | ||||
| 		uint32_t size; | ||||
| 		uint32_t crc32; | ||||
| 		uint64_t my_lba; | ||||
| 		uint64_t first_lba; | ||||
| 		uint64_t last_lba; | ||||
| 		GUID     guid; | ||||
| 		uint64_t partition_entry_lba; | ||||
| 		uint32_t partition_entry_count; | ||||
| 		uint32_t partition_entry_size; | ||||
| 		uint32_t partition_entry_array_crc32; | ||||
| 		char						signature[8]; | ||||
| 		BAN::LittleEndian<uint32_t> revision; | ||||
| 		BAN::LittleEndian<uint32_t> size; | ||||
| 		BAN::LittleEndian<uint32_t> crc32; | ||||
| 		BAN::LittleEndian<uint32_t> reserved; | ||||
| 		BAN::LittleEndian<uint64_t> my_lba; | ||||
| 		BAN::LittleEndian<uint64_t> alternate_lba; | ||||
| 		BAN::LittleEndian<uint64_t> first_usable_lba; | ||||
| 		BAN::LittleEndian<uint64_t> last_usable_lba; | ||||
| 		GUID						disk_guid; | ||||
| 		BAN::LittleEndian<uint64_t> partition_entry_lba; | ||||
| 		BAN::LittleEndian<uint32_t> partition_entry_count; | ||||
| 		BAN::LittleEndian<uint32_t> partition_entry_size; | ||||
| 		BAN::LittleEndian<uint32_t> partition_entry_array_crc32; | ||||
| 	}; | ||||
| 
 | ||||
| 	uint32_t crc32_table[256] = | ||||
| 	struct PartitionEntry | ||||
| 	{ | ||||
| 		GUID partition_type_guid; | ||||
| 		GUID unique_partition_guid; | ||||
| 		BAN::LittleEndian<uint64_t> starting_lba; | ||||
| 		BAN::LittleEndian<uint64_t> ending_lba; | ||||
| 		BAN::LittleEndian<uint64_t> attributes; | ||||
| 		BAN::LittleEndian<uint16_t> partition_name[36]; | ||||
| 	} __attribute__((packed)); | ||||
| 
 | ||||
| 	static uint32_t crc32_table[256] = | ||||
| 	{ | ||||
| 		0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, | ||||
| 		0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, | ||||
|  | @ -107,16 +121,6 @@ namespace Kernel | |||
| 		return crc32 ^ 0xFFFFFFFF; | ||||
| 	} | ||||
| 
 | ||||
| 	static GUID parse_guid(const uint8_t* guid) | ||||
| 	{ | ||||
| 		GUID result; | ||||
| 		result.data1 = BAN::Math::big_endian_to_host<uint32_t>(guid + 0); | ||||
| 		result.data2 = BAN::Math::big_endian_to_host<uint16_t>(guid + 4); | ||||
| 		result.data3 = BAN::Math::big_endian_to_host<uint16_t>(guid + 6); | ||||
| 		memcpy(result.data4, guid + 8, 8); | ||||
| 		return result; | ||||
| 	} | ||||
| 
 | ||||
| 	static bool is_valid_gpt_header(const GPTHeader& header, uint32_t sector_size) | ||||
| 	{ | ||||
| 		if (memcmp(header.signature, "EFI PART", 8) != 0) | ||||
|  | @ -140,58 +144,12 @@ namespace Kernel | |||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	static GPTHeader parse_gpt_header(const BAN::Vector<uint8_t>& lba1) | ||||
| 	{ | ||||
| 		GPTHeader header; | ||||
| 		memset(&header, 0, sizeof(header)); | ||||
| 
 | ||||
| 		memcpy(header.signature, lba1.data(), 8); | ||||
| 		header.revision						= BAN::Math::little_endian_to_host<uint32_t>(lba1.data() + 8); | ||||
| 		header.size							= BAN::Math::little_endian_to_host<uint32_t>(lba1.data() + 12); | ||||
| 		header.crc32						= BAN::Math::little_endian_to_host<uint32_t>(lba1.data() + 16); | ||||
| 		header.my_lba						= BAN::Math::little_endian_to_host<uint64_t>(lba1.data() + 24); | ||||
| 		header.first_lba					= BAN::Math::little_endian_to_host<uint64_t>(lba1.data() + 40); | ||||
| 		header.last_lba						= BAN::Math::little_endian_to_host<uint64_t>(lba1.data() + 48); | ||||
| 		header.guid							= parse_guid(lba1.data() + 56); | ||||
| 		header.partition_entry_lba			= BAN::Math::little_endian_to_host<uint64_t>(lba1.data() + 72); | ||||
| 		header.partition_entry_count		= BAN::Math::little_endian_to_host<uint32_t>(lba1.data() + 80); | ||||
| 		header.partition_entry_size			= BAN::Math::little_endian_to_host<uint32_t>(lba1.data() + 84); | ||||
| 		header.partition_entry_array_crc32	= BAN::Math::little_endian_to_host<uint32_t>(lba1.data() + 88); | ||||
| 		return header; | ||||
| 	} | ||||
| 
 | ||||
| 	static void utf8_encode(const uint16_t* codepoints, size_t count, char* out) | ||||
| 	{ | ||||
| 		uint32_t len = 0; | ||||
| 		while (*codepoints && count--) | ||||
| 		{ | ||||
| 			uint16_t cp = *codepoints; | ||||
| 			if (cp < 128) | ||||
| 			{ | ||||
| 				out[len++] = cp & 0x7F; | ||||
| 			} | ||||
| 			else if (cp < 2048) | ||||
| 			{ | ||||
| 				out[len++] = 0xC0 | ((cp >> 0x6) & 0x1F); | ||||
| 				out[len++] = 0x80 | (cp & 0x3F); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				out[len++] = 0xE0 | ((cp >> 0xC) & 0x0F); | ||||
| 				out[len++] = 0x80 | ((cp >> 0x6) & 0x3F); | ||||
| 				out[len++] = 0x80 | (cp & 0x3F); | ||||
| 			} | ||||
| 			codepoints++; | ||||
| 		} | ||||
| 		out[len] = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> StorageDevice::initialize_partitions() | ||||
| 	{ | ||||
| 		BAN::Vector<uint8_t> lba1(sector_size()); | ||||
| 		TRY(read_sectors(1, 1, lba1.data())); | ||||
| 
 | ||||
| 		GPTHeader header = parse_gpt_header(lba1); | ||||
| 		const GPTHeader& header = *(const GPTHeader*)lba1.data(); | ||||
| 		if (!is_valid_gpt_header(header, sector_size())) | ||||
| 			return BAN::Error::from_c_string("Invalid GPT header"); | ||||
| 
 | ||||
|  | @ -199,7 +157,8 @@ namespace Kernel | |||
| 		if (uint32_t remainder = size % sector_size()) | ||||
| 			size += sector_size() - remainder; | ||||
| 
 | ||||
| 		BAN::Vector<uint8_t> entry_array(size); | ||||
| 		BAN::Vector<uint8_t> entry_array; | ||||
| 		TRY(entry_array.resize(size)); | ||||
| 		TRY(read_sectors(header.partition_entry_lba, size / sector_size(), entry_array.data())); | ||||
| 
 | ||||
| 		if (!is_valid_gpt_crc32(header, lba1, entry_array)) | ||||
|  | @ -207,18 +166,18 @@ namespace Kernel | |||
| 
 | ||||
| 		for (uint32_t i = 0; i < header.partition_entry_count; i++) | ||||
| 		{ | ||||
| 			uint8_t* partition_data = entry_array.data() + header.partition_entry_size * i; | ||||
| 			const PartitionEntry& entry = *(const PartitionEntry*)(entry_array.data() + header.partition_entry_size * i); | ||||
| 
 | ||||
| 			char utf8_name[36 * 3 + 1]; // 36 16-bit codepoints + nullbyte
 | ||||
| 			utf8_encode((uint16_t*)(partition_data + 56), header.partition_entry_size - 56, utf8_name); | ||||
| 			char utf8_name[36 * 4 + 1]; | ||||
| 			BAN::UTF8::from_codepoints(entry.partition_name, 36, utf8_name); | ||||
| 
 | ||||
| 			MUST(m_partitions.emplace_back( | ||||
| 				*this,  | ||||
| 				parse_guid(partition_data + 0), | ||||
| 				parse_guid(partition_data + 16), | ||||
| 				BAN::Math::little_endian_to_host<uint64_t>(partition_data + 32), | ||||
| 				BAN::Math::little_endian_to_host<uint64_t>(partition_data + 40), | ||||
| 				BAN::Math::little_endian_to_host<uint64_t>(partition_data + 48), | ||||
| 				entry.partition_type_guid, | ||||
| 				entry.unique_partition_guid, | ||||
| 				entry.starting_lba, | ||||
| 				entry.ending_lba, | ||||
| 				entry.attributes, | ||||
| 				utf8_name | ||||
| 			)); | ||||
| 		} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue