mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 07:27:45 +00:00
LibEDID: Fix handling extension maps
We weren't properly iterating the extension blocks and thought we encountered an unexpected extension map block, when we really should have just skipped over it.
This commit is contained in:
parent
18fc54fc34
commit
a821aa5f50
2 changed files with 164 additions and 17 deletions
|
@ -141,7 +141,7 @@ struct [[gnu::packed]] EDID {
|
|||
u8 checksum;
|
||||
};
|
||||
|
||||
enum ExtensionBlockTag : u8 {
|
||||
enum class ExtensionBlockTag : u8 {
|
||||
CEA_861 = 0x2,
|
||||
VideoTimingBlock = 0x10,
|
||||
DisplayInformation = 0x40,
|
||||
|
@ -220,8 +220,10 @@ public:
|
|||
ErrorOr<IterationDecision> for_each_dtd(Function<IterationDecision(Parser::DetailedTiming const&)> callback) const
|
||||
{
|
||||
u8 dtd_start = m_edid.read_host(&m_block->cea861extension.dtd_start_offset);
|
||||
if (dtd_start <= 4)
|
||||
if (dtd_start < 4) {
|
||||
// dtd_start == 4 means there are no data blocks, but there are still DTDs
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
if (dtd_start > offsetof(Definitions::ExtensionBlock, checksum) - sizeof(Definitions::DetailedTiming))
|
||||
return Error::from_string_literal("CEA 861 extension block has invalid DTD list"sv);
|
||||
|
@ -488,35 +490,39 @@ ErrorOr<IterationDecision> Parser::for_each_extension_block(Function<IterationDe
|
|||
if (sizeof(Definitions::EDID) + (size_t)raw_extension_block_count * sizeof(Definitions::ExtensionBlock) > m_bytes.size())
|
||||
return Error::from_string_literal("Truncated EDID");
|
||||
|
||||
auto validate_block_checksum = [&](Definitions::ExtensionBlock const& extension_map) {
|
||||
auto validate_block_checksum = [&](Definitions::ExtensionBlock const& block) {
|
||||
u8 checksum = 0x0;
|
||||
auto* bytes = (u8 const*)&extension_map;
|
||||
for (size_t i = 0; i < sizeof(extension_map); i++)
|
||||
auto* bytes = (u8 const*)█
|
||||
for (size_t i = 0; i < sizeof(block); i++)
|
||||
checksum += bytes[i];
|
||||
|
||||
return checksum == 0;
|
||||
};
|
||||
|
||||
size_t offset = sizeof(Definitions::EDID);
|
||||
auto* raw_extension_blocks = (Definitions::ExtensionBlock const*)(m_bytes.data() + offset);
|
||||
auto* raw_extension_blocks = (Definitions::ExtensionBlock const*)(m_bytes.data() + sizeof(Definitions::EDID));
|
||||
Definitions::ExtensionBlock const* current_extension_map = nullptr;
|
||||
|
||||
unsigned raw_index = 0;
|
||||
if (m_revision <= 3) {
|
||||
if (raw_extension_block_count > 1) {
|
||||
current_extension_map = &raw_extension_blocks[0];
|
||||
if (read_host(¤t_extension_map->tag) != Definitions::ExtensionBlockTag::ExtensionBlockMap)
|
||||
raw_index++;
|
||||
if (read_host(¤t_extension_map->tag) != (u8)Definitions::ExtensionBlockTag::ExtensionBlockMap)
|
||||
return Error::from_string_literal("Did not find extension map at block 1"sv);
|
||||
if (!validate_block_checksum(*current_extension_map))
|
||||
return Error::from_string_literal("Extension block map checksum mismatch"sv);
|
||||
}
|
||||
} else if (read_host(&raw_extension_blocks[0].tag) == Definitions::ExtensionBlockTag::ExtensionBlockMap) {
|
||||
} else if (read_host(&raw_extension_blocks[0].tag) == (u8)Definitions::ExtensionBlockTag::ExtensionBlockMap) {
|
||||
current_extension_map = &raw_extension_blocks[0];
|
||||
raw_index++;
|
||||
}
|
||||
|
||||
for (unsigned raw_index = 0; raw_index < raw_extension_block_count; raw_index++) {
|
||||
for (; raw_index < raw_extension_block_count; raw_index++) {
|
||||
auto& raw_block = raw_extension_blocks[raw_index];
|
||||
u8 tag = read_host(&raw_block.tag);
|
||||
|
||||
if (current_extension_map && raw_index == 127) {
|
||||
if (tag != Definitions::ExtensionBlockTag::ExtensionBlockMap)
|
||||
if (tag != (u8)Definitions::ExtensionBlockTag::ExtensionBlockMap)
|
||||
return Error::from_string_literal("Did not find extension map at block 128"sv);
|
||||
current_extension_map = &raw_extension_blocks[127];
|
||||
if (!validate_block_checksum(*current_extension_map))
|
||||
|
@ -524,17 +530,16 @@ ErrorOr<IterationDecision> Parser::for_each_extension_block(Function<IterationDe
|
|||
continue;
|
||||
}
|
||||
|
||||
if (tag == Definitions::ExtensionBlockTag::ExtensionBlockMap)
|
||||
if (tag == (u8)Definitions::ExtensionBlockTag::ExtensionBlockMap)
|
||||
return Error::from_string_literal("Unexpected extension map encountered"sv);
|
||||
|
||||
if (!validate_block_checksum(raw_block))
|
||||
return Error::from_string_literal("Extension block checksum mismatch"sv);
|
||||
|
||||
size_t offset = (u8 const*)&raw_block - m_bytes.data();
|
||||
IterationDecision decision = callback(raw_index + 1, tag, raw_block.block.revision, m_bytes.slice(offset, sizeof(Definitions::ExtensionBlock)));
|
||||
if (decision != IterationDecision::Continue)
|
||||
return decision;
|
||||
|
||||
offset += sizeof(Definitions::ExtensionBlock);
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
@ -1033,7 +1038,7 @@ ErrorOr<IterationDecision> Parser::for_each_detailed_timing(Function<IterationDe
|
|||
|
||||
Optional<Error> extension_error;
|
||||
auto result = for_each_extension_block([&](u8 block_id, u8 tag, u8, ReadonlyBytes bytes) {
|
||||
if (tag != Definitions::ExtensionBlockTag::CEA_861)
|
||||
if (tag != (u8)Definitions::ExtensionBlockTag::CEA_861)
|
||||
return IterationDecision::Continue;
|
||||
|
||||
CEA861ExtensionBlock cea861(*this, (Definitions::ExtensionBlock const*)bytes.data());
|
||||
|
@ -1077,7 +1082,7 @@ ErrorOr<IterationDecision> Parser::for_each_short_video_descriptor(Function<Iter
|
|||
{
|
||||
Optional<Error> extension_error;
|
||||
auto result = for_each_extension_block([&](u8 block_id, u8 tag, u8, ReadonlyBytes bytes) {
|
||||
if (tag != Definitions::ExtensionBlockTag::CEA_861)
|
||||
if (tag != (u8)Definitions::ExtensionBlockTag::CEA_861)
|
||||
return IterationDecision::Continue;
|
||||
|
||||
CEA861ExtensionBlock cea861(*this, (Definitions::ExtensionBlock const*)bytes.data());
|
||||
|
@ -1113,7 +1118,7 @@ ErrorOr<IterationDecision> Parser::for_each_display_descriptor(Function<Iteratio
|
|||
|
||||
Optional<Error> extension_error;
|
||||
auto result = for_each_extension_block([&](u8, u8 tag, u8, ReadonlyBytes bytes) {
|
||||
if (tag != Definitions::ExtensionBlockTag::CEA_861)
|
||||
if (tag != (u8)Definitions::ExtensionBlockTag::CEA_861)
|
||||
return IterationDecision::Continue;
|
||||
|
||||
CEA861ExtensionBlock cea861(*this, (Definitions::ExtensionBlock const*)bytes.data());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue