162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2012 Intel Corporation 462306a36Sopenharmony_ci * Author: Josh Triplett <josh@joshtriplett.org> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Based on the bgrt driver: 762306a36Sopenharmony_ci * Copyright 2012 Red Hat, Inc <mjg@redhat.com> 862306a36Sopenharmony_ci * Author: Matthew Garrett 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/acpi.h> 1662306a36Sopenharmony_ci#include <linux/efi.h> 1762306a36Sopenharmony_ci#include <linux/efi-bgrt.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct acpi_table_bgrt bgrt_tab; 2062306a36Sopenharmony_cisize_t bgrt_image_size; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct bmp_header { 2362306a36Sopenharmony_ci u16 id; 2462306a36Sopenharmony_ci u32 size; 2562306a36Sopenharmony_ci} __packed; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_civoid __init efi_bgrt_init(struct acpi_table_header *table) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci void *image; 3062306a36Sopenharmony_ci struct bmp_header bmp_header; 3162306a36Sopenharmony_ci struct acpi_table_bgrt *bgrt = &bgrt_tab; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (acpi_disabled) 3462306a36Sopenharmony_ci return; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (!efi_enabled(EFI_MEMMAP)) 3762306a36Sopenharmony_ci return; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (table->length < sizeof(bgrt_tab)) { 4062306a36Sopenharmony_ci pr_notice("Ignoring BGRT: invalid length %u (expected %zu)\n", 4162306a36Sopenharmony_ci table->length, sizeof(bgrt_tab)); 4262306a36Sopenharmony_ci return; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci *bgrt = *(struct acpi_table_bgrt *)table; 4562306a36Sopenharmony_ci /* 4662306a36Sopenharmony_ci * Only version 1 is defined but some older laptops (seen on Lenovo 4762306a36Sopenharmony_ci * Ivy Bridge models) have a correct version 1 BGRT table with the 4862306a36Sopenharmony_ci * version set to 0, so we accept version 0 and 1. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci if (bgrt->version > 1) { 5162306a36Sopenharmony_ci pr_notice("Ignoring BGRT: invalid version %u (expected 1)\n", 5262306a36Sopenharmony_ci bgrt->version); 5362306a36Sopenharmony_ci goto out; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci if (bgrt->image_type != 0) { 5662306a36Sopenharmony_ci pr_notice("Ignoring BGRT: invalid image type %u (expected 0)\n", 5762306a36Sopenharmony_ci bgrt->image_type); 5862306a36Sopenharmony_ci goto out; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci if (!bgrt->image_address) { 6162306a36Sopenharmony_ci pr_notice("Ignoring BGRT: null image address\n"); 6262306a36Sopenharmony_ci goto out; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (efi_mem_type(bgrt->image_address) != EFI_BOOT_SERVICES_DATA) { 6662306a36Sopenharmony_ci pr_notice("Ignoring BGRT: invalid image address\n"); 6762306a36Sopenharmony_ci goto out; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci image = early_memremap(bgrt->image_address, sizeof(bmp_header)); 7062306a36Sopenharmony_ci if (!image) { 7162306a36Sopenharmony_ci pr_notice("Ignoring BGRT: failed to map image header memory\n"); 7262306a36Sopenharmony_ci goto out; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci memcpy(&bmp_header, image, sizeof(bmp_header)); 7662306a36Sopenharmony_ci early_memunmap(image, sizeof(bmp_header)); 7762306a36Sopenharmony_ci if (bmp_header.id != 0x4d42) { 7862306a36Sopenharmony_ci pr_notice("Ignoring BGRT: Incorrect BMP magic number 0x%x (expected 0x4d42)\n", 7962306a36Sopenharmony_ci bmp_header.id); 8062306a36Sopenharmony_ci goto out; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci bgrt_image_size = bmp_header.size; 8362306a36Sopenharmony_ci efi_mem_reserve(bgrt->image_address, bgrt_image_size); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return; 8662306a36Sopenharmony_ciout: 8762306a36Sopenharmony_ci memset(bgrt, 0, sizeof(bgrt_tab)); 8862306a36Sopenharmony_ci} 89