The Mali kernel driver allows the userland code to map a buffer in physical memory (via the MALI_IOC_MEM_MAP_EXT ioctl). This is normally used for mapping the framebuffer in the userland Mali blob and directly accessing it for rendering graphics. Because of security reasons, the kernel driver has a validation check, which only permits one chunk of physical memory to be mapped this way. And the Mali driver initialization code configures the address and the size of this chunk.
Now the problem is that the sunxi hardware has not just one, but up to two framebuffers (for example, one VGA and one HDMI monitor). Previously both framebuffers were allocated from the disp reservation area. So the Mali validation code was just allowing access to the whole disp reservation area. But with CMA support, the framebuffers may be allocated anywhere in the CMA area. And now we have two disconnected chunks of physical memory, which should be both supported by the MALI_IOC_MEM_MAP_EXT ioctl. This patch modifies the MALI_IOC_MEM_MAP_EXT validation code to support both of the sunxi disp framebuffers. PS. If the kernel driver does not allow to map physical memory via the MALI_IOC_MEM_MAP_EXT ioctl at all, then the Mali userland blob still can work and is able to render 3D graphics. However this is done by using memcpy to copy data into the framebuffer for each frame and the performance becomes ridiculously bad. Signed-off-by: Siarhei Siamashka <siarhei.siamas...@gmail.com> --- arch/arm/plat-sunxi/core.c | 12 +++++++++++ drivers/gpu/mali/mali/common/mali_mem_validation.c | 22 +++++++++++++++++-- .../mali/mali/platform/mali400-pmu/mali_platform.c | 25 ---------------------- drivers/video/sunxi/disp/dev_fb.c | 22 +++++++++++++++++++ 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/arch/arm/plat-sunxi/core.c b/arch/arm/plat-sunxi/core.c index e7da395..89f3187 100644 --- a/arch/arm/plat-sunxi/core.c +++ b/arch/arm/plat-sunxi/core.c @@ -135,6 +135,18 @@ static int __init reserve_fb_param(char *s) early_param("sunxi_fb_mem_reserve", reserve_fb_param); #endif +/* + * Physical addresses and sizes of two framebuffers. + */ +unsigned long fb0_start; +unsigned long fb0_size; +unsigned long fb1_start; +unsigned long fb1_size; +EXPORT_SYMBOL(fb0_start); +EXPORT_SYMBOL(fb0_size); +EXPORT_SYMBOL(fb1_start); +EXPORT_SYMBOL(fb1_size); + #if IS_ENABLED(CONFIG_SUNXI_G2D) /* The G2D block is used by: * diff --git a/drivers/gpu/mali/mali/common/mali_mem_validation.c b/drivers/gpu/mali/mali/common/mali_mem_validation.c index 2f57459..4a5b88c 100644 --- a/drivers/gpu/mali/mali/common/mali_mem_validation.c +++ b/drivers/gpu/mali/mali/common/mali_mem_validation.c @@ -14,6 +14,11 @@ #define MALI_INVALID_MEM_ADDR 0xFFFFFFFF +extern unsigned long fb0_start; +extern unsigned long fb0_size; +extern unsigned long fb1_start; +extern unsigned long fb1_size; + typedef struct { u32 phys_base; /**< Mali physical base of the memory, page aligned */ @@ -47,7 +52,8 @@ _mali_osk_errcode_t mali_mem_validation_add_range(const _mali_osk_resource_t *re return _MALI_OSK_ERR_OK; } -_mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size) +static _mali_osk_errcode_t validation_check_helper(u32 phys_addr, u32 size, + _mali_mem_validation_t mali_mem_validator) { if (phys_addr < (phys_addr + size)) /* Don't allow overflow (or zero size) */ { @@ -65,7 +71,19 @@ _mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size) } } - MALI_PRINT_ERROR(("MALI PHYSICAL RANGE VALIDATION ERROR: The range supplied was: phys_base=0x%08X, size=0x%08X\n", phys_addr, size)); + return _MALI_OSK_ERR_FAULT; +} +_mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size) +{ + _mali_mem_validation_t fb0 = { fb0_start, fb0_size }; + _mali_mem_validation_t fb1 = { fb1_start, fb1_size }; + + if (validation_check_helper(phys_addr, size, fb0) == _MALI_OSK_ERR_OK || + validation_check_helper(phys_addr, size, fb1) == _MALI_OSK_ERR_OK || + validation_check_helper(phys_addr, size, mali_mem_validator) == _MALI_OSK_ERR_OK) + return _MALI_OSK_ERR_OK; + + MALI_PRINT_ERROR(("MALI PHYSICAL RANGE VALIDATION ERROR: The range supplied was: phys_base=0x%08X, size=0x%08X\n", phys_addr, size)); return _MALI_OSK_ERR_FAULT; } diff --git a/drivers/gpu/mali/mali/platform/mali400-pmu/mali_platform.c b/drivers/gpu/mali/mali/platform/mali400-pmu/mali_platform.c index 290c1f9..d43bde0 100644 --- a/drivers/gpu/mali/mali/platform/mali400-pmu/mali_platform.c +++ b/drivers/gpu/mali/mali/platform/mali400-pmu/mali_platform.c @@ -24,13 +24,6 @@ #include <plat/sys_config.h> #include <plat/memory.h> -#ifdef CONFIG_FB_SUNXI_RESERVED_MEM -extern unsigned long fb_start; -extern unsigned long fb_size; -static int fb_validation_range_added; -#endif - - int mali_clk_div = 3; module_param(mali_clk_div, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); MODULE_PARM_DESC(mali_clk_div, "Clock divisor for mali"); @@ -45,24 +38,6 @@ _mali_osk_errcode_t mali_platform_init(void) int clk_div; int mali_used = 0; -#ifdef CONFIG_FB_SUNXI_RESERVED_MEM - /* mali_platform_init() may be called multiple times, - but we only need to set the validation range once */ - if (!fb_validation_range_added) { - _mali_osk_resource_t fb_resource = { - .type = MEM_VALIDATION, - .description = "Framebuffer", - .base = fb_start, - .size = fb_size, - .flags = 0 - }; - mali_mem_validation_add_range(&fb_resource); - MALI_PRINT(("permit MALI_IOC_MEM_MAP_EXT ioctl for framebuffer" - " (paddr=0x%08X, size=%d)\n", fb_start, fb_size)); - fb_validation_range_added = 1; - } -#endif - //get mali ahb clock h_ahb_mali = clk_get(NULL, "ahb_mali"); if(!h_ahb_mali){ diff --git a/drivers/video/sunxi/disp/dev_fb.c b/drivers/video/sunxi/disp/dev_fb.c index 7500764..6946222 100644 --- a/drivers/video/sunxi/disp/dev_fb.c +++ b/drivers/video/sunxi/disp/dev_fb.c @@ -1483,6 +1483,12 @@ static struct fb_ops dispfb_ops = { .fb_cursor = Fb_cursor, }; +/* For Mali addresses validation */ +extern unsigned long fb0_start; +extern unsigned long fb0_size; +extern unsigned long fb1_start; +extern unsigned long fb1_size; + __s32 Display_Fb_Request(__u32 fb_id, __disp_fb_create_para_t * fb_para) { struct fb_info *info = NULL; @@ -1510,6 +1516,14 @@ __s32 Display_Fb_Request(__u32 fb_id, __disp_fb_create_para_t * fb_para) info->fix.line_length * fb_para->height * fb_para->buffer_num); Fb_map_video_memory(fb_id, info); + if (fb_id == 0) { + fb0_start = info->fix.smem_start; + fb0_size = info->fix.smem_len; + } else if (fb_id == 1) { + fb1_start = info->fix.smem_start; + fb1_size = info->fix.smem_len; + } + for (sel = 0; sel < 2; sel++) { if (((sel == 0) && (fb_para->fb_mode != FB_MODE_SCREEN1)) || ((sel == 1) && (fb_para->fb_mode != FB_MODE_SCREEN0))) { @@ -1630,6 +1644,14 @@ __s32 Display_Fb_Release(__u32 fb_id) fb_dealloc_cmap(&info->cmap); Fb_unmap_video_memory(fb_id, info); + if (fb_id == 0) { + fb0_start = 0; + fb0_size = 0; + } else if (fb_id == 1) { + fb1_start = 0; + fb1_size = 0; + } + return DIS_SUCCESS; } -- 2.4.10 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.