]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[settings] Expose memory map via settings mechanism
authorMichael Brown <mcb30@ipxe.org>
Mon, 12 Aug 2013 12:42:12 +0000 (13:42 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 12 Aug 2013 21:00:36 +0000 (22:00 +0100)
Allow memory map entries to be read using the syntax

  ${memmap/<region>.<properties>.<scale>}

where <region> is the index of the memory region, <properties> is a
bitmask where bit 0 represents the start address and bit 1 represents
the length (allowing the end address to be encoded by having both bits
0 and 1 set), and <scale> is the number of bits by which to shift the
result.

This allows for several values of interest to be encoded.  For
example:

  ${memmap/<region>.1.0:hexraw}   # 64-bit start address of <region>
  ${memmap/<region>.2.0:hexraw}   # 64-bit length of <region>, in bytes
  ${memmap/<region>.3.0:hexraw}   # 64-bit end address of <region>
  ${memmap/<region>.2.10:int32}   # Length of <region>, in kB
  ${memmap/<region>.2.20:int32}   # Length of <region>, in MB

The numeric encoding is slightly more sophisticated than described
here, allowing a single encoding to cover multiple regions.  (See the
source code for details.)  The primary use case for this feature is to
provide the total system memory size (in MB) via the "memsize"
predefined setting.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/config/config.c
src/config/settings.h
src/core/memmap_settings.c [new file with mode: 0644]
src/include/ipxe/errfile.h

index 06c5713f0d3ba081f48bcbc3703eb1fef74afb11..c8cb53994646e80fa59fbf382308668ad8bf982b 100644 (file)
@@ -316,6 +316,9 @@ REQUIRE_OBJECT ( guestinfo );
 #ifdef CPUID_SETTINGS
 REQUIRE_OBJECT ( cpuid_settings );
 #endif
+#ifdef MEMMAP_SETTINGS
+REQUIRE_OBJECT ( memmap_settings );
+#endif
 
 /*
  * Drag in selected keyboard map
index 97131e883033f9b4ec989b6325845f3a1ba46b13..b06f2901b0cf3c291615c553ed569918f43c576d 100644 (file)
@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #define        PCI_SETTINGS    /* PCI device settings */
 //#define      CPUID_SETTINGS  /* CPUID settings */
+//#define      MEMMAP_SETTINGS /* Memory map settings */
 //#define      VMWARE_SETTINGS /* VMware GuestInfo settings */
 
 #include <config/local/settings.h>
diff --git a/src/core/memmap_settings.c b/src/core/memmap_settings.c
new file mode 100644 (file)
index 0000000..f06b875
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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 <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/init.h>
+#include <ipxe/settings.h>
+#include <ipxe/io.h>
+
+/** @file
+ *
+ * Memory map settings
+ *
+ * Memory map settings are numerically encoded as:
+ *
+ *  Bits 31-24 Number of regions, minus one
+ *  Bits 23-16 Starting region
+ *  Bits 15-11 Unused
+ *  Bit  10    Ignore non-existent regions (rather than generating an error)
+ *  Bit  9     Include length
+ *  Bit  8     Include start address
+ *  Bits 7-6   Unused
+ *  Bits 5-0   Scale factor (i.e. right shift count)
+ */
+
+/**
+ * Construct memory map setting tag
+ *
+ * @v start            Starting region
+ * @v count            Number of regions
+ * @v include_start    Include start address
+ * @v include_length   Include length
+ * @v ignore           Ignore non-existent regions
+ * @v scale            Scale factor
+ * @ret tag            Setting tag
+ */
+#define MEMMAP_TAG( start, count, include_start, include_length,       \
+                   ignore, scale )                                     \
+       ( ( (start) << 16 ) | ( ( (count) - 1 ) << 24 ) |               \
+         ( (ignore) << 10 ) | ( (include_length) << 9 ) |              \
+         ( (include_start) << 8 ) | (scale) )
+
+/**
+ * Extract number of regions from setting tag
+ *
+ * @v tag              Setting tag
+ * @ret count          Number of regions
+ */
+#define MEMMAP_COUNT( tag ) ( ( ( (tag) >> 24 ) & 0xff ) + 1 )
+
+/**
+ * Extract starting region from setting tag
+ *
+ * @v tag              Setting tag
+ * @ret start          Starting region
+ */
+#define MEMMAP_START( tag ) ( ( (tag) >> 16 ) & 0xff )
+
+/**
+ * Extract ignore flag from setting tag
+ *
+ * @v tag              Setting tag
+ * @ret ignore         Ignore non-existent regions
+ */
+#define MEMMAP_IGNORE_NONEXISTENT( tag ) ( (tag) & 0x00000400UL )
+
+/**
+ * Extract length inclusion flag from setting tag
+ *
+ * @v tag              Setting tag
+ * @ret include_length Include length
+ */
+#define MEMMAP_INCLUDE_LENGTH( tag ) ( (tag) & 0x00000200UL )
+
+/**
+ * Extract start address inclusion flag from setting tag
+ *
+ * @v tag              Setting tag
+ * @ret include_start  Include start address
+ */
+#define MEMMAP_INCLUDE_START( tag ) ( (tag) & 0x00000100UL )
+
+/**
+ * Extract scale factor from setting tag
+ *
+ * @v tag              Setting tag
+ * @v scale            Scale factor
+ */
+#define MEMMAP_SCALE( tag ) ( (tag) & 0x3f )
+
+/** Memory map settings scope */
+static struct settings_scope memmap_settings_scope;
+
+/**
+ * Check applicability of memory map setting
+ *
+ * @v settings         Settings block
+ * @v setting          Setting
+ * @ret applies                Setting applies within this settings block
+ */
+static int memmap_settings_applies ( struct settings *settings __unused,
+                                    struct setting *setting ) {
+
+       return ( setting->scope == &memmap_settings_scope );
+}
+
+/**
+ * Fetch value of memory map setting
+ *
+ * @v settings         Settings block
+ * @v setting          Setting to fetch
+ * @v data             Buffer to fill with setting data
+ * @v len              Length of buffer
+ * @ret len            Length of setting data, or negative error
+ */
+static int memmap_settings_fetch ( struct settings *settings,
+                                  struct setting *setting,
+                                  void *data, size_t len ) {
+       struct memory_map memmap;
+       struct memory_region *region;
+       uint64_t result = 0;
+       unsigned int i;
+       unsigned int count;
+
+       DBGC ( settings, "MEMMAP start %d count %d %s%s%s%s scale %d\n",
+              MEMMAP_START ( setting->tag ), MEMMAP_COUNT ( setting->tag ),
+              ( MEMMAP_INCLUDE_START ( setting->tag ) ? "start" : "" ),
+              ( ( MEMMAP_INCLUDE_START ( setting->tag ) &&
+                  MEMMAP_INCLUDE_LENGTH ( setting->tag ) ) ? "+" : "" ),
+              ( MEMMAP_INCLUDE_LENGTH ( setting->tag ) ? "length" : "" ),
+              ( MEMMAP_IGNORE_NONEXISTENT ( setting->tag ) ? " ignore" : "" ),
+              MEMMAP_SCALE ( setting->tag ) );
+
+       /* Fetch memory map */
+       get_memmap ( &memmap );
+
+       /* Extract results from memory map */
+       count = MEMMAP_COUNT ( setting->tag );
+       for ( i = MEMMAP_START ( setting->tag ) ; count-- ; i++ ) {
+
+               /* Check that region exists */
+               if ( i >= memmap.count ) {
+                       if ( MEMMAP_IGNORE_NONEXISTENT ( setting->tag ) ) {
+                               continue;
+                       } else {
+                               DBGC ( settings, "MEMMAP region %d does not "
+                                      "exist\n", i );
+                               return -ENOENT;
+                       }
+               }
+
+               /* Extract results from this region */
+               region = &memmap.regions[i];
+               if ( MEMMAP_INCLUDE_START ( setting->tag ) ) {
+                       result += region->start;
+                       DBGC ( settings, "MEMMAP %d start %08llx\n",
+                              i, region->start );
+               }
+               if ( MEMMAP_INCLUDE_LENGTH ( setting->tag ) ) {
+                       result += ( region->end - region->start );
+                       DBGC ( settings, "MEMMAP %d length %08llx\n",
+                              i, ( region->end - region->start ) );
+               }
+       }
+
+       /* Scale result */
+       result >>= MEMMAP_SCALE ( setting->tag );
+
+       /* Return result */
+       result = cpu_to_be64 ( result );
+       if ( len > sizeof ( result ) )
+               len = sizeof ( result );
+       memcpy ( data, &result, len );
+
+       /* Set type if not already specified */
+       if ( ! setting->type )
+               setting->type = &setting_type_hexraw;
+
+       return sizeof ( result );
+}
+
+/** Memory map settings operations */
+static struct settings_operations memmap_settings_operations = {
+       .applies = memmap_settings_applies,
+       .fetch = memmap_settings_fetch,
+};
+
+/** Memory map settings */
+static struct settings memmap_settings = {
+       .refcnt = NULL,
+       .siblings = LIST_HEAD_INIT ( memmap_settings.siblings ),
+       .children = LIST_HEAD_INIT ( memmap_settings.children ),
+       .op = &memmap_settings_operations,
+       .default_scope = &memmap_settings_scope,
+};
+
+/** Initialise memory map settings */
+static void memmap_settings_init ( void ) {
+       int rc;
+
+       if ( ( rc = register_settings ( &memmap_settings, NULL,
+                                       "memmap" ) ) != 0 ) {
+               DBG ( "MEMMAP could not register settings: %s\n",
+                     strerror ( rc ) );
+               return;
+       }
+}
+
+/** Memory map settings initialiser */
+struct init_fn memmap_settings_init_fn __init_fn ( INIT_NORMAL ) = {
+       .initialise = memmap_settings_init,
+};
+
+/** Memory map predefined settings */
+struct setting memmap_predefined_settings[] __setting ( SETTING_MISC ) = {
+       {
+               .name = "memsize",
+               .description = "Memory size (in MB)",
+               .tag = MEMMAP_TAG ( 0, 0x100, 0, 1, 1, 20 ),
+               .type = &setting_type_int32,
+               .scope = &memmap_settings_scope,
+       },
+};
index 0fd3facaaf8f0a532bceb3753ab4d7bce28308c4..4053923becd80727d574ba2f135e04f5999bc0d0 100644 (file)
@@ -285,6 +285,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_linux_pci            ( ERRFILE_OTHER | 0x003c0000 )
 #define ERRFILE_pci_settings         ( ERRFILE_OTHER | 0x003d0000 )
 #define ERRFILE_efi_reboot           ( ERRFILE_OTHER | 0x003e0000 )
+#define ERRFILE_memmap_settings              ( ERRFILE_OTHER | 0x003f0000 )
 
 /** @} */