iPXE
acpi_settings.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2017 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 /**
00027  * @file
00028  *
00029  * ACPI settings
00030  *
00031  */
00032 
00033 #include <string.h>
00034 #include <errno.h>
00035 #include <ipxe/init.h>
00036 #include <ipxe/settings.h>
00037 #include <ipxe/acpi.h>
00038 
00039 /** ACPI settings scope */
00040 static const struct settings_scope acpi_settings_scope;
00041 
00042 /**
00043  * Check applicability of ACPI setting
00044  *
00045  * @v settings          Settings block
00046  * @v setting           Setting
00047  * @ret applies         Setting applies within this settings block
00048  */
00049 static int acpi_settings_applies ( struct settings *settings __unused,
00050                                    const struct setting *setting ) {
00051 
00052         return ( setting->scope == &acpi_settings_scope );
00053 }
00054 
00055 /**
00056  * Fetch value of ACPI setting
00057  *
00058  * @v settings          Settings block
00059  * @v setting           Setting to fetch
00060  * @v data              Buffer to fill with setting data
00061  * @v len               Length of buffer
00062  * @ret len             Length of setting data, or negative error
00063  */
00064 static int acpi_settings_fetch ( struct settings *settings,
00065                                  struct setting *setting,
00066                                  void *data, size_t len ) {
00067         struct acpi_header acpi;
00068         uint32_t tag_high;
00069         uint32_t tag_low;
00070         uint32_t tag_signature;
00071         unsigned int tag_index;
00072         size_t tag_offset;
00073         size_t tag_len;
00074         userptr_t table;
00075         size_t offset;
00076         size_t max_len;
00077         int delta;
00078         unsigned int i;
00079 
00080         /* Parse settings tag */
00081         tag_high = ( setting->tag >> 32 );
00082         tag_low = setting->tag;
00083         tag_signature = bswap_32 ( tag_high );
00084         tag_index = ( ( tag_low >> 24 ) & 0xff );
00085         tag_offset = ( ( tag_low >> 8 ) & 0xffff );
00086         tag_len = ( ( tag_low >> 0 ) & 0xff );
00087         DBGC ( settings, "ACPI %s.%d offset %#zx length %#zx\n",
00088                acpi_name ( tag_signature ), tag_index, tag_offset, tag_len );
00089 
00090         /* Locate ACPI table */
00091         table = acpi_find ( tag_signature, tag_index );
00092         if ( ! table )
00093                 return -ENOENT;
00094 
00095         /* Read table header */
00096         copy_from_user ( &acpi, table, 0, sizeof ( acpi ) );
00097 
00098         /* Calculate starting offset and maximum available length */
00099         max_len = le32_to_cpu ( acpi.length );
00100         if ( tag_offset > max_len )
00101                 return -ENOENT;
00102         offset = tag_offset;
00103         max_len -= offset;
00104 
00105         /* Restrict to requested length, if specified */
00106         if ( tag_len && ( tag_len < max_len ) )
00107                 max_len = tag_len;
00108 
00109         /* Invert endianness for numeric settings */
00110         if ( setting->type && setting->type->numerate ) {
00111                 offset += ( max_len - 1 );
00112                 delta = -1;
00113         } else {
00114                 delta = +1;
00115         }
00116 
00117         /* Read data */
00118         for ( i = 0 ; ( ( i < max_len ) && ( i < len ) ) ; i++ ) {
00119                 copy_from_user ( data, table, offset, 1 );
00120                 data++;
00121                 offset += delta;
00122         }
00123 
00124         /* Set type if not already specified */
00125         if ( ! setting->type )
00126                 setting->type = &setting_type_hexraw;
00127 
00128         return max_len;
00129 }
00130 
00131 /** ACPI settings operations */
00132 static struct settings_operations acpi_settings_operations = {
00133         .applies = acpi_settings_applies,
00134         .fetch = acpi_settings_fetch,
00135 };
00136 
00137 /** ACPI settings */
00138 static struct settings acpi_settings = {
00139         .refcnt = NULL,
00140         .siblings = LIST_HEAD_INIT ( acpi_settings.siblings ),
00141         .children = LIST_HEAD_INIT ( acpi_settings.children ),
00142         .op = &acpi_settings_operations,
00143         .default_scope = &acpi_settings_scope,
00144 };
00145 
00146 /** Initialise ACPI settings */
00147 static void acpi_settings_init ( void ) {
00148         int rc;
00149 
00150         if ( ( rc = register_settings ( &acpi_settings, NULL,
00151                                         "acpi" ) ) != 0 ) {
00152                 DBG ( "ACPI could not register settings: %s\n",
00153                       strerror ( rc ) );
00154                 return;
00155         }
00156 }
00157 
00158 /** ACPI settings initialiser */
00159 struct init_fn acpi_settings_init_fn __init_fn ( INIT_NORMAL ) = {
00160         .initialise = acpi_settings_init,
00161 };