Commit 5db72099 authored by Jani Nikula's avatar Jani Nikula

drm/i915/bios: abstract finding the panel sequence block

Make the whole thing easier to read. While at it, make the parsing more
robust, and ensure we don't read past buffer being parsed.

v2: improve commit message (Daniel)
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1452001851-8967-1-git-send-email-jani.nikula@intel.com
parent 08c0888b
...@@ -697,7 +697,7 @@ parse_psr(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) ...@@ -697,7 +697,7 @@ parse_psr(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
dev_priv->vbt.psr.tp2_tp3_wakeup_time = psr_table->tp2_tp3_wakeup_time; dev_priv->vbt.psr.tp2_tp3_wakeup_time = psr_table->tp2_tp3_wakeup_time;
} }
static u8 *goto_next_sequence(u8 *data, int *size) static u8 *goto_next_sequence(u8 *data, u16 *size)
{ {
u16 len; u16 len;
int tmp = *size; int tmp = *size;
...@@ -818,15 +818,52 @@ parse_mipi_config(struct drm_i915_private *dev_priv, ...@@ -818,15 +818,52 @@ parse_mipi_config(struct drm_i915_private *dev_priv,
dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID;
} }
/* Find the sequence block and size for the given panel. */
static const u8 *
find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
u16 panel_id, u16 *seq_size)
{
u32 total = get_blocksize(sequence);
const u8 *data = &sequence->data[0];
u8 current_id;
u16 current_size;
int index = 0;
int i;
for (i = 0; i < MAX_MIPI_CONFIGURATIONS && index + 3 < total; i++) {
current_id = *(data + index);
index++;
current_size = *((const u16 *)(data + index));
index += 2;
if (index + current_size > total) {
DRM_ERROR("Invalid sequence block\n");
return NULL;
}
if (current_id == panel_id) {
*seq_size = current_size;
return data + index;
}
index += current_size;
}
DRM_ERROR("Sequence block detected but no valid configuration\n");
return NULL;
}
static void static void
parse_mipi_sequence(struct drm_i915_private *dev_priv, parse_mipi_sequence(struct drm_i915_private *dev_priv,
const struct bdb_header *bdb) const struct bdb_header *bdb)
{ {
const struct bdb_mipi_sequence *sequence; const struct bdb_mipi_sequence *sequence;
const u8 *seq_data; const u8 *seq_data;
u16 seq_size;
u8 *data; u8 *data;
u16 block_size; u16 block_size;
int i, panel_id, seq_size;
/* Only our generic panel driver uses the sequence block. */ /* Only our generic panel driver uses the sequence block. */
if (dev_priv->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID) if (dev_priv->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID)
...@@ -853,40 +890,11 @@ parse_mipi_sequence(struct drm_i915_private *dev_priv, ...@@ -853,40 +890,11 @@ parse_mipi_sequence(struct drm_i915_private *dev_priv,
*/ */
dev_priv->vbt.dsi.seq_version = sequence->version; dev_priv->vbt.dsi.seq_version = sequence->version;
seq_data = &sequence->data[0]; seq_data = find_panel_sequence_block(sequence, panel_type, &seq_size);
if (!seq_data)
/*
* sequence block is variable length and hence we need to parse and
* get the sequence data for specific panel id
*/
for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) {
panel_id = *seq_data;
seq_size = *((u16 *) (seq_data + 1));
if (panel_id == panel_type)
break;
/* skip the sequence including seq header of 3 bytes */
seq_data = seq_data + 3 + seq_size;
if ((seq_data - &sequence->data[0]) > block_size) {
DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n");
return;
}
}
if (i == MAX_MIPI_CONFIGURATIONS) {
DRM_ERROR("Sequence block detected but no valid configuration\n");
return;
}
/* check if found sequence is completely within the sequence block
* just being paranoid */
if (seq_size > block_size) {
DRM_ERROR("Corrupted sequence/size, bailing out\n");
return; return;
}
/* skip the panel id(1 byte) and seq size(2 bytes) */ dev_priv->vbt.dsi.data = kmemdup(seq_data, seq_size, GFP_KERNEL);
dev_priv->vbt.dsi.data = kmemdup(seq_data + 3, seq_size, GFP_KERNEL);
if (!dev_priv->vbt.dsi.data) if (!dev_priv->vbt.dsi.data)
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment