From 26957cf5b0d92137643b28149c144641c0cb5b40 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Tue, 30 Jun 2026 15:59:10 +0800 Subject: [PATCH] fix(lcd): add color size check for i80 and boundary check for rgb --- components/esp_lcd/i80/esp_lcd_panel_io_i2s.c | 30 ++++++++++++++++--- components/esp_lcd/i80/esp_lcd_panel_io_i80.c | 9 ++++-- components/esp_lcd/rgb/esp_lcd_panel_rgb.c | 7 +++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c b/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c index 83c69180753..c8e016b8772 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -475,6 +475,25 @@ static void i2s_lcd_prepare_param_buffer(lcd_i80_trans_descriptor_t *trans_desc, #endif } +static bool i2s_lcd_get_color_buffer_size(const esp_lcd_i80_bus_t *bus, size_t color_size, size_t *buffer_size) +{ +#if SOC_I2S_TRANS_SIZE_ALIGN_WORD + size_t input_bytes_per_word = bus->bus_width / 4; + if (color_size % input_bytes_per_word) { + return false; + } + size_t word_num = color_size / input_bytes_per_word; + if (word_num > (size_t) -1 / 4) { + return false; + } + *buffer_size = word_num * 4; +#else + (void)bus; + *buffer_size = color_size; +#endif + return true; +} + static void i2s_lcd_prepare_color_buffer(lcd_i80_trans_descriptor_t *trans_desc, const void *color, size_t color_size) { #if SOC_I2S_TRANS_SIZE_ALIGN_WORD @@ -510,8 +529,8 @@ static esp_err_t panel_io_i80_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons esp_lcd_i80_bus_t *bus = next_device->bus; lcd_panel_io_i80_t *cur_device = bus->cur_device; lcd_i80_trans_descriptor_t *trans_desc = NULL; - assert(param_size <= bus->max_transfer_bytes && "parameter bytes too long, enlarge max_transfer_bytes"); - assert(param_size <= LCD_I80_IO_FORMAT_BUF_SIZE && "format buffer too small, increase LCD_I80_IO_FORMAT_BUF_SIZE"); + ESP_RETURN_ON_FALSE(param_size <= bus->max_transfer_bytes, ESP_ERR_INVALID_ARG, TAG, "parameter bytes too long, enlarge max_transfer_bytes"); + ESP_RETURN_ON_FALSE(param_size <= LCD_I80_IO_FORMAT_BUF_SIZE, ESP_ERR_INVALID_ARG, TAG, "format buffer too small, increase LCD_I80_IO_FORMAT_BUF_SIZE"); size_t num_trans_inflight = next_device->num_trans_inflight; // before issue a polling transaction, need to wait queued transactions finished for (size_t i = 0; i < num_trans_inflight; i++) { @@ -587,7 +606,10 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons esp_lcd_i80_bus_t *bus = next_device->bus; lcd_panel_io_i80_t *cur_device = bus->cur_device; lcd_i80_trans_descriptor_t *trans_desc = NULL; - assert(color_size <= bus->max_transfer_bytes && "color bytes too long, enlarge max_transfer_bytes"); + size_t color_buffer_size = 0; + bool valid_color_buffer_size = i2s_lcd_get_color_buffer_size(bus, color_size, &color_buffer_size); + ESP_RETURN_ON_FALSE(valid_color_buffer_size && color_buffer_size <= bus->max_transfer_bytes, ESP_ERR_INVALID_ARG, TAG, + "color bytes too long, enlarge max_transfer_bytes"); size_t num_trans_inflight = next_device->num_trans_inflight; // before issue a polling transaction, need to wait queued transactions finished for (size_t i = 0; i < num_trans_inflight; i++) { diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c index 519282ddbe4..eb3a90a8c32 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c @@ -498,8 +498,10 @@ static esp_err_t panel_io_i80_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons esp_lcd_i80_bus_t *bus = next_device->bus; lcd_panel_io_i80_t *cur_device = bus->cur_device; lcd_i80_trans_descriptor_t *trans_desc = NULL; - assert(param_size <= bus->max_transfer_bytes && "parameter bytes too long, enlarge max_transfer_bytes"); - assert(param_size <= LCD_I80_IO_FORMAT_BUF_SIZE && "format buffer too small, increase LCD_I80_IO_FORMAT_BUF_SIZE"); + ESP_RETURN_ON_FALSE(param_size <= bus->max_transfer_bytes, ESP_ERR_INVALID_ARG, TAG, + "parameter bytes too long, enlarge max_transfer_bytes"); + ESP_RETURN_ON_FALSE(param_size <= LCD_I80_IO_FORMAT_BUF_SIZE, ESP_ERR_INVALID_ARG, TAG, + "format buffer too small, increase LCD_I80_IO_FORMAT_BUF_SIZE"); uint32_t cmd_cycles = next_device->lcd_cmd_bits / bus->bus_width; // in case bus_width=16 and cmd_bits=8, we still need 1 cmd_cycle if (cmd_cycles * bus->bus_width < next_device->lcd_cmd_bits) { @@ -566,7 +568,8 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons lcd_panel_io_i80_t *i80_device = __containerof(io, lcd_panel_io_i80_t, base); esp_lcd_i80_bus_t *bus = i80_device->bus; lcd_i80_trans_descriptor_t *trans_desc = NULL; - assert(color_size <= bus->max_transfer_bytes && "color bytes too long, enlarge max_transfer_bytes"); + ESP_RETURN_ON_FALSE(color_size <= bus->max_transfer_bytes, ESP_ERR_INVALID_ARG, TAG, + "color bytes too long, enlarge max_transfer_bytes"); uint32_t cache_line_size = 0; if (esp_ptr_external_ram(color)) { // check alignment diff --git a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c index ef3d33333ce..6af20bac6b0 100644 --- a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c @@ -651,6 +651,13 @@ static esp_err_t rgb_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start = MAX(y_start, 0); y_end = MIN(y_end, v_res); } + if (x_start >= x_end || y_start >= y_end) { + // no valid region to draw, skip + if (cb) { + cb(&rgb_panel->base, NULL, rgb_panel->user_ctx); + } + return ESP_OK; + } // check if we want to copy the draw buffer to the internal frame buffer bool draw_buf_copy_to_fb = true;