iPXE
memmap_settings.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013 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 #include <string.h>
00027 #include <errno.h>
00028 #include <byteswap.h>
00029 #include <ipxe/init.h>
00030 #include <ipxe/settings.h>
00031 #include <ipxe/io.h>
00032 
00033 /** @file
00034  *
00035  * Memory map settings
00036  *
00037  * Memory map settings are numerically encoded as:
00038  *
00039  *  Bits 31-24  Number of regions, minus one
00040  *  Bits 23-16  Starting region
00041  *  Bits 15-11  Unused
00042  *  Bit  10     Ignore non-existent regions (rather than generating an error)
00043  *  Bit  9      Include length
00044  *  Bit  8      Include start address
00045  *  Bits 7-6    Unused
00046  *  Bits 5-0    Scale factor (i.e. right shift count)
00047  */
00048 
00049 /**
00050  * Construct memory map setting tag
00051  *
00052  * @v start             Starting region
00053  * @v count             Number of regions
00054  * @v include_start     Include start address
00055  * @v include_length    Include length
00056  * @v ignore            Ignore non-existent regions
00057  * @v scale             Scale factor
00058  * @ret tag             Setting tag
00059  */
00060 #define MEMMAP_TAG( start, count, include_start, include_length,        \
00061                     ignore, scale )                                     \
00062         ( ( (start) << 16 ) | ( ( (count) - 1 ) << 24 ) |               \
00063           ( (ignore) << 10 ) | ( (include_length) << 9 ) |              \
00064           ( (include_start) << 8 ) | (scale) )
00065 
00066 /**
00067  * Extract number of regions from setting tag
00068  *
00069  * @v tag               Setting tag
00070  * @ret count           Number of regions
00071  */
00072 #define MEMMAP_COUNT( tag ) ( ( ( (tag) >> 24 ) & 0xff ) + 1 )
00073 
00074 /**
00075  * Extract starting region from setting tag
00076  *
00077  * @v tag               Setting tag
00078  * @ret start           Starting region
00079  */
00080 #define MEMMAP_START( tag ) ( ( (tag) >> 16 ) & 0xff )
00081 
00082 /**
00083  * Extract ignore flag from setting tag
00084  *
00085  * @v tag               Setting tag
00086  * @ret ignore          Ignore non-existent regions
00087  */
00088 #define MEMMAP_IGNORE_NONEXISTENT( tag ) ( (tag) & 0x00000400UL )
00089 
00090 /**
00091  * Extract length inclusion flag from setting tag
00092  *
00093  * @v tag               Setting tag
00094  * @ret include_length  Include length
00095  */
00096 #define MEMMAP_INCLUDE_LENGTH( tag ) ( (tag) & 0x00000200UL )
00097 
00098 /**
00099  * Extract start address inclusion flag from setting tag
00100  *
00101  * @v tag               Setting tag
00102  * @ret include_start   Include start address
00103  */
00104 #define MEMMAP_INCLUDE_START( tag ) ( (tag) & 0x00000100UL )
00105 
00106 /**
00107  * Extract scale factor from setting tag
00108  *
00109  * @v tag               Setting tag
00110  * @v scale             Scale factor
00111  */
00112 #define MEMMAP_SCALE( tag ) ( (tag) & 0x3f )
00113 
00114 /** Memory map settings scope */
00115 static const struct settings_scope memmap_settings_scope;
00116 
00117 /**
00118  * Check applicability of memory map setting
00119  *
00120  * @v settings          Settings block
00121  * @v setting           Setting
00122  * @ret applies         Setting applies within this settings block
00123  */
00124 static int memmap_settings_applies ( struct settings *settings __unused,
00125                                      const struct setting *setting ) {
00126 
00127         return ( setting->scope == &memmap_settings_scope );
00128 }
00129 
00130 /**
00131  * Fetch value of memory map setting
00132  *
00133  * @v settings          Settings block
00134  * @v setting           Setting to fetch
00135  * @v data              Buffer to fill with setting data
00136  * @v len               Length of buffer
00137  * @ret len             Length of setting data, or negative error
00138  */
00139 static int memmap_settings_fetch ( struct settings *settings,
00140                                    struct setting *setting,
00141                                    void *data, size_t len ) {
00142         struct memory_map memmap;
00143         struct memory_region *region;
00144         uint64_t result = 0;
00145         unsigned int start;
00146         unsigned int count;
00147         unsigned int scale;
00148         int include_start;
00149         int include_length;
00150         int ignore_nonexistent;
00151         unsigned int i;
00152 
00153         /* Parse settings tag */
00154         start = MEMMAP_START ( setting->tag );
00155         count = MEMMAP_COUNT ( setting->tag );
00156         scale = MEMMAP_SCALE ( setting->tag );
00157         include_start = MEMMAP_INCLUDE_START ( setting->tag );
00158         include_length = MEMMAP_INCLUDE_LENGTH ( setting->tag );
00159         ignore_nonexistent = MEMMAP_IGNORE_NONEXISTENT ( setting->tag );
00160         DBGC ( settings, "MEMMAP start %d count %d %s%s%s%s scale %d\n",
00161                start, count, ( include_start ? "start" : "" ),
00162                ( ( include_start && include_length ) ? "+" : "" ),
00163                ( include_length ? "length" : "" ),
00164                ( ignore_nonexistent ? " ignore" : "" ), scale );
00165 
00166         /* Fetch memory map */
00167         get_memmap ( &memmap );
00168 
00169         /* Extract results from memory map */
00170         for ( i = start ; count-- ; i++ ) {
00171 
00172                 /* Check that region exists */
00173                 if ( i >= memmap.count ) {
00174                         if ( ignore_nonexistent ) {
00175                                 continue;
00176                         } else {
00177                                 DBGC ( settings, "MEMMAP region %d does not "
00178                                        "exist\n", i );
00179                                 return -ENOENT;
00180                         }
00181                 }
00182 
00183                 /* Extract results from this region */
00184                 region = &memmap.regions[i];
00185                 if ( include_start ) {
00186                         result += region->start;
00187                         DBGC ( settings, "MEMMAP %d start %08llx\n",
00188                                i, region->start );
00189                 }
00190                 if ( include_length ) {
00191                         result += ( region->end - region->start );
00192                         DBGC ( settings, "MEMMAP %d length %08llx\n",
00193                                i, ( region->end - region->start ) );
00194                 }
00195         }
00196 
00197         /* Scale result */
00198         result >>= scale;
00199 
00200         /* Return result */
00201         result = cpu_to_be64 ( result );
00202         if ( len > sizeof ( result ) )
00203                 len = sizeof ( result );
00204         memcpy ( data, &result, len );
00205 
00206         /* Set type if not already specified */
00207         if ( ! setting->type )
00208                 setting->type = &setting_type_hexraw;
00209 
00210         return sizeof ( result );
00211 }
00212 
00213 /** Memory map settings operations */
00214 static struct settings_operations memmap_settings_operations = {
00215         .applies = memmap_settings_applies,
00216         .fetch = memmap_settings_fetch,
00217 };
00218 
00219 /** Memory map settings */
00220 static struct settings memmap_settings = {
00221         .refcnt = NULL,
00222         .siblings = LIST_HEAD_INIT ( memmap_settings.siblings ),
00223         .children = LIST_HEAD_INIT ( memmap_settings.children ),
00224         .op = &memmap_settings_operations,
00225         .default_scope = &memmap_settings_scope,
00226 };
00227 
00228 /** Initialise memory map settings */
00229 static void memmap_settings_init ( void ) {
00230         int rc;
00231 
00232         if ( ( rc = register_settings ( &memmap_settings, NULL,
00233                                         "memmap" ) ) != 0 ) {
00234                 DBG ( "MEMMAP could not register settings: %s\n",
00235                       strerror ( rc ) );
00236                 return;
00237         }
00238 }
00239 
00240 /** Memory map settings initialiser */
00241 struct init_fn memmap_settings_init_fn __init_fn ( INIT_NORMAL ) = {
00242         .initialise = memmap_settings_init,
00243 };
00244 
00245 /** Memory map predefined settings */
00246 const struct setting memsize_setting __setting ( SETTING_MISC, memsize ) = {
00247         .name = "memsize",
00248         .description = "Memory size (in MB)",
00249         .tag = MEMMAP_TAG ( 0, 0x100, 0, 1, 1, 20 ),
00250         .type = &setting_type_int32,
00251         .scope = &memmap_settings_scope,
00252 };