Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / core / memmap_settings.c
1 /*
2  * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <string.h>
23 #include <errno.h>
24 #include <byteswap.h>
25 #include <ipxe/init.h>
26 #include <ipxe/settings.h>
27 #include <ipxe/io.h>
28
29 /** @file
30  *
31  * Memory map settings
32  *
33  * Memory map settings are numerically encoded as:
34  *
35  *  Bits 31-24  Number of regions, minus one
36  *  Bits 23-16  Starting region
37  *  Bits 15-11  Unused
38  *  Bit  10     Ignore non-existent regions (rather than generating an error)
39  *  Bit  9      Include length
40  *  Bit  8      Include start address
41  *  Bits 7-6    Unused
42  *  Bits 5-0    Scale factor (i.e. right shift count)
43  */
44
45 /**
46  * Construct memory map setting tag
47  *
48  * @v start             Starting region
49  * @v count             Number of regions
50  * @v include_start     Include start address
51  * @v include_length    Include length
52  * @v ignore            Ignore non-existent regions
53  * @v scale             Scale factor
54  * @ret tag             Setting tag
55  */
56 #define MEMMAP_TAG( start, count, include_start, include_length,        \
57                     ignore, scale )                                     \
58         ( ( (start) << 16 ) | ( ( (count) - 1 ) << 24 ) |               \
59           ( (ignore) << 10 ) | ( (include_length) << 9 ) |              \
60           ( (include_start) << 8 ) | (scale) )
61
62 /**
63  * Extract number of regions from setting tag
64  *
65  * @v tag               Setting tag
66  * @ret count           Number of regions
67  */
68 #define MEMMAP_COUNT( tag ) ( ( ( (tag) >> 24 ) & 0xff ) + 1 )
69
70 /**
71  * Extract starting region from setting tag
72  *
73  * @v tag               Setting tag
74  * @ret start           Starting region
75  */
76 #define MEMMAP_START( tag ) ( ( (tag) >> 16 ) & 0xff )
77
78 /**
79  * Extract ignore flag from setting tag
80  *
81  * @v tag               Setting tag
82  * @ret ignore          Ignore non-existent regions
83  */
84 #define MEMMAP_IGNORE_NONEXISTENT( tag ) ( (tag) & 0x00000400UL )
85
86 /**
87  * Extract length inclusion flag from setting tag
88  *
89  * @v tag               Setting tag
90  * @ret include_length  Include length
91  */
92 #define MEMMAP_INCLUDE_LENGTH( tag ) ( (tag) & 0x00000200UL )
93
94 /**
95  * Extract start address inclusion flag from setting tag
96  *
97  * @v tag               Setting tag
98  * @ret include_start   Include start address
99  */
100 #define MEMMAP_INCLUDE_START( tag ) ( (tag) & 0x00000100UL )
101
102 /**
103  * Extract scale factor from setting tag
104  *
105  * @v tag               Setting tag
106  * @v scale             Scale factor
107  */
108 #define MEMMAP_SCALE( tag ) ( (tag) & 0x3f )
109
110 /** Memory map settings scope */
111 static const struct settings_scope memmap_settings_scope;
112
113 /**
114  * Check applicability of memory map setting
115  *
116  * @v settings          Settings block
117  * @v setting           Setting
118  * @ret applies         Setting applies within this settings block
119  */
120 static int memmap_settings_applies ( struct settings *settings __unused,
121                                      const struct setting *setting ) {
122
123         return ( setting->scope == &memmap_settings_scope );
124 }
125
126 /**
127  * Fetch value of memory map setting
128  *
129  * @v settings          Settings block
130  * @v setting           Setting to fetch
131  * @v data              Buffer to fill with setting data
132  * @v len               Length of buffer
133  * @ret len             Length of setting data, or negative error
134  */
135 static int memmap_settings_fetch ( struct settings *settings,
136                                    struct setting *setting,
137                                    void *data, size_t len ) {
138         struct memory_map memmap;
139         struct memory_region *region;
140         uint64_t result = 0;
141         unsigned int i;
142         unsigned int count;
143
144         DBGC ( settings, "MEMMAP start %d count %d %s%s%s%s scale %d\n",
145                MEMMAP_START ( setting->tag ), MEMMAP_COUNT ( setting->tag ),
146                ( MEMMAP_INCLUDE_START ( setting->tag ) ? "start" : "" ),
147                ( ( MEMMAP_INCLUDE_START ( setting->tag ) &&
148                    MEMMAP_INCLUDE_LENGTH ( setting->tag ) ) ? "+" : "" ),
149                ( MEMMAP_INCLUDE_LENGTH ( setting->tag ) ? "length" : "" ),
150                ( MEMMAP_IGNORE_NONEXISTENT ( setting->tag ) ? " ignore" : "" ),
151                MEMMAP_SCALE ( setting->tag ) );
152
153         /* Fetch memory map */
154         get_memmap ( &memmap );
155
156         /* Extract results from memory map */
157         count = MEMMAP_COUNT ( setting->tag );
158         for ( i = MEMMAP_START ( setting->tag ) ; count-- ; i++ ) {
159
160                 /* Check that region exists */
161                 if ( i >= memmap.count ) {
162                         if ( MEMMAP_IGNORE_NONEXISTENT ( setting->tag ) ) {
163                                 continue;
164                         } else {
165                                 DBGC ( settings, "MEMMAP region %d does not "
166                                        "exist\n", i );
167                                 return -ENOENT;
168                         }
169                 }
170
171                 /* Extract results from this region */
172                 region = &memmap.regions[i];
173                 if ( MEMMAP_INCLUDE_START ( setting->tag ) ) {
174                         result += region->start;
175                         DBGC ( settings, "MEMMAP %d start %08llx\n",
176                                i, region->start );
177                 }
178                 if ( MEMMAP_INCLUDE_LENGTH ( setting->tag ) ) {
179                         result += ( region->end - region->start );
180                         DBGC ( settings, "MEMMAP %d length %08llx\n",
181                                i, ( region->end - region->start ) );
182                 }
183         }
184
185         /* Scale result */
186         result >>= MEMMAP_SCALE ( setting->tag );
187
188         /* Return result */
189         result = cpu_to_be64 ( result );
190         if ( len > sizeof ( result ) )
191                 len = sizeof ( result );
192         memcpy ( data, &result, len );
193
194         /* Set type if not already specified */
195         if ( ! setting->type )
196                 setting->type = &setting_type_hexraw;
197
198         return sizeof ( result );
199 }
200
201 /** Memory map settings operations */
202 static struct settings_operations memmap_settings_operations = {
203         .applies = memmap_settings_applies,
204         .fetch = memmap_settings_fetch,
205 };
206
207 /** Memory map settings */
208 static struct settings memmap_settings = {
209         .refcnt = NULL,
210         .siblings = LIST_HEAD_INIT ( memmap_settings.siblings ),
211         .children = LIST_HEAD_INIT ( memmap_settings.children ),
212         .op = &memmap_settings_operations,
213         .default_scope = &memmap_settings_scope,
214 };
215
216 /** Initialise memory map settings */
217 static void memmap_settings_init ( void ) {
218         int rc;
219
220         if ( ( rc = register_settings ( &memmap_settings, NULL,
221                                         "memmap" ) ) != 0 ) {
222                 DBG ( "MEMMAP could not register settings: %s\n",
223                       strerror ( rc ) );
224                 return;
225         }
226 }
227
228 /** Memory map settings initialiser */
229 struct init_fn memmap_settings_init_fn __init_fn ( INIT_NORMAL ) = {
230         .initialise = memmap_settings_init,
231 };
232
233 /** Memory map predefined settings */
234 const struct setting memsize_setting __setting ( SETTING_MISC, memsize ) = {
235         .name = "memsize",
236         .description = "Memory size (in MB)",
237         .tag = MEMMAP_TAG ( 0, 0x100, 0, 1, 1, 20 ),
238         .type = &setting_type_int32,
239         .scope = &memmap_settings_scope,
240 };