From dda03c884d70d18546bb2d02f92acb4c4da28fc8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 4 Nov 2020 15:18:49 +0000 Subject: [dma] Define a DMA API to allow for non-flat device address spaces iPXE currently assumes that DMA-capable devices can directly address physical memory using host addresses. This assumption fails when using an IOMMU. Define an internal DMA API with two implementations: a "flat" implementation for use in legacy BIOS or other environments in which flat physical addressing is guaranteed to be used and all allocated physical addresses are guaranteed to be within a 32-bit address space, and an "operations-based" implementation for use in UEFI or other environments in which DMA mapping may require bus-specific handling. The purpose of the fully inlined "flat" implementation is to allow the trivial identity DMA mappings to be optimised out at build time, thereby avoiding an increase in code size for legacy BIOS builds. Signed-off-by: Michael Brown --- src/config/defaults/linux.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/config/defaults/linux.h') diff --git a/src/config/defaults/linux.h b/src/config/defaults/linux.h index 75fd617f9..98d2dafec 100644 --- a/src/config/defaults/linux.h +++ b/src/config/defaults/linux.h @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define TIME_LINUX #define REBOOT_NULL #define PCIAPI_LINUX +#define DMAAPI_FLAT #define DRIVERS_LINUX -- cgit v1.2.3-55-g7522 From c09b627973d9362caba39de09f7d2c6990eb9701 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 1 Mar 2021 01:38:54 +0000 Subject: [linux] Provide ACPI settings via /sys/firmware/acpi/tables Signed-off-by: Michael Brown --- src/config/defaults/linux.h | 1 + src/include/ipxe/acpi.h | 1 + src/include/ipxe/linux/linux_acpi.h | 18 ++++ src/interface/linux/linux_acpi.c | 173 ++++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 src/include/ipxe/linux/linux_acpi.h create mode 100644 src/interface/linux/linux_acpi.c (limited to 'src/config/defaults/linux.h') diff --git a/src/config/defaults/linux.h b/src/config/defaults/linux.h index 98d2dafec..5c4106d30 100644 --- a/src/config/defaults/linux.h +++ b/src/config/defaults/linux.h @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define REBOOT_NULL #define PCIAPI_LINUX #define DMAAPI_FLAT +#define ACPI_LINUX #define DRIVERS_LINUX diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index 6d19f05fa..81ef7ff76 100644 --- a/src/include/ipxe/acpi.h +++ b/src/include/ipxe/acpi.h @@ -360,6 +360,7 @@ extern userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ); /* Include all architecture-independent ACPI API headers */ #include #include +#include /* Include all architecture-dependent ACPI API headers */ #include diff --git a/src/include/ipxe/linux/linux_acpi.h b/src/include/ipxe/linux/linux_acpi.h new file mode 100644 index 000000000..a2c33ce2c --- /dev/null +++ b/src/include/ipxe/linux/linux_acpi.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_LINUX_ACPI_H +#define _IPXE_LINUX_ACPI_H + +/** @file + * + * iPXE ACPI API for Linux + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#ifdef ACPI_LINUX +#define ACPI_PREFIX_linux +#else +#define ACPI_PREFIX_linux __linux_ +#endif + +#endif /* _IPXE_LINUX_ACPI_H */ diff --git a/src/interface/linux/linux_acpi.c b/src/interface/linux/linux_acpi.c new file mode 100644 index 000000000..0f369bdaa --- /dev/null +++ b/src/interface/linux/linux_acpi.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2021 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include + +/** ACPI sysfs directory */ +#define ACPI_SYSFS_PREFIX "/sys/firmware/acpi/tables/" + +/** A cached ACPI table */ +struct linux_acpi_table { + /** List of cached tables */ + struct list_head list; + /** Signature */ + uint32_t signature; + /** Index */ + unsigned int index; + /** Cached data */ + void *data; +}; + +/** List of cached ACPI tables */ +static LIST_HEAD ( linux_acpi_tables ); + +/** + * Locate ACPI table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +static userptr_t linux_acpi_find ( uint32_t signature, unsigned int index ) { + struct linux_acpi_table *table; + struct acpi_header header; + union { + uint32_t signature; + char filename[5]; + } u; + static const char prefix[] = ACPI_SYSFS_PREFIX; + char filename[ sizeof ( prefix ) - 1 /* NUL */ + 4 /* signature */ + + 3 /* "999" */ + 1 /* NUL */ ]; + ssize_t rlen; + size_t len; + void *data; + int fd; + + /* Check for existing table */ + list_for_each_entry ( table, &linux_acpi_tables, list ) { + if ( ( table->signature == signature ) && + ( table->index == index ) ) + return virt_to_user ( table->data ); + } + + /* Allocate a new table */ + table = malloc ( sizeof ( *table ) ); + if ( ! table ) + goto err_alloc; + table->signature = signature; + table->index = index; + + /* Construct filename */ + memset ( &u, 0, sizeof ( u ) ); + u.signature = le32_to_cpu ( signature ); + snprintf ( filename, sizeof ( filename ), "%s%s%d", prefix, + u.filename, ( index + 1 ) ); + + /* Open file */ + fd = linux_open ( filename, O_RDONLY ); + if ( ( fd < 0 ) && ( index == 0 ) ) { + filename[ sizeof ( prefix ) - 1 /* NUL */ + + 4 /* signature */ ] = '\0'; + fd = linux_open ( filename, O_RDONLY ); + } + if ( fd < 0 ) { + DBGC ( &linux_acpi_tables, "ACPI could not open %s: %s\n", + filename, linux_strerror ( linux_errno ) ); + goto err_open; + } + + /* Read header */ + rlen = linux_read ( fd, &header, sizeof ( header ) ); + if ( rlen < 0 ) { + DBGC ( &linux_acpi_tables, "ACPI could not read %s header: " + "%s\n", filename, linux_strerror ( linux_errno ) ); + goto err_header; + } + if ( ( ( size_t ) rlen ) != sizeof ( header ) ) { + DBGC ( &linux_acpi_tables, "ACPI underlength %s header\n", + filename ); + goto err_header_len; + } + + /* Parse header */ + len = le32_to_cpu ( header.length ); + if ( len < sizeof ( header ) ) { + DBGC ( &linux_acpi_tables, "ACPI malformed %s header\n", + filename ); + goto err_malformed; + } + + /* Allocate data */ + table->data = malloc ( len ); + if ( ! table->data ) + goto err_data; + + /* Read table */ + memcpy ( table->data, &header, sizeof ( header ) ); + data = ( table->data + sizeof ( header ) ); + len -= sizeof ( header ); + while ( len ) { + rlen = linux_read ( fd, data, len ); + if ( rlen < 0 ) { + DBGC ( &linux_acpi_tables, "ACPI could not read %s: " + "%s\n", filename, + linux_strerror ( linux_errno ) ); + goto err_body; + } + if ( rlen == 0 ) { + DBGC ( &linux_acpi_tables, "ACPI underlength %s\n", + filename ); + goto err_body_len; + } + data += rlen; + len -= rlen; + } + + /* Close file */ + linux_close ( fd ); + + /* Add to list of tables */ + list_add ( &table->list, &linux_acpi_tables ); + DBGC ( &linux_acpi_tables, "ACPI cached %s\n", filename ); + + return virt_to_user ( table->data ); + + err_body_len: + err_body: + free ( table->data ); + err_data: + err_malformed: + err_header_len: + err_header: + linux_close ( fd ); + err_open: + free ( table ); + err_alloc: + return UNULL; +} + +PROVIDE_ACPI ( linux, acpi_find, linux_acpi_find ); -- cgit v1.2.3-55-g7522