Merge branch 'makefile' into haiku
[grub2/phcoder.git] / commands / dmigen.c
blobe121e17a27efdbd59f00fea5040fa0468f3da0fc
1 /* dmigen.c - generate smbios tables based on template. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/err.h>
21 #include <grub/command.h>
22 #include <grub/efiemu/efiemu.h>
23 #include <grub/i386/pc/efiemu.h>
24 #include <grub/misc.h>
25 #include <grub/mm.h>
26 #include <grub/file.h>
27 #include <grub/dl.h>
28 #include <grub/gzio.h>
29 #include <grub/acpi.h>
31 struct dmi_anchor
33 grub_uint8_t magic[5];
34 grub_uint8_t csum;
35 grub_uint16_t data_size;
36 grub_uint32_t data_addr;
37 grub_uint16_t ntables;
38 grub_uint8_t revision;
39 } __attribute__ ((packed));
41 struct sm_anchor
43 grub_uint8_t magic[4];
44 grub_uint8_t csum;
45 grub_uint8_t anchor_length;
46 grub_uint8_t ver_major;
47 grub_uint8_t ver_minor;
48 grub_uint16_t biggest_table;
49 grub_uint8_t anchor_revision;
50 grub_uint8_t pad[5];
51 struct dmi_anchor dmi;
52 } __attribute__ ((packed));
54 struct dmi_table_header
56 grub_uint8_t type;
57 grub_uint8_t size;
58 grub_uint16_t handle;
59 } __attribute__ ((packed));
61 static char *tables = 0;
62 static int tables_total_size = 0;
63 static int tablehandle = 0;
64 static int ntables = 0;
65 static int biggest_table = 0;
67 static int smvermajor = 2, smverminor = 1;
69 static void *
70 get_table (void *data __attribute__ ((unused)))
72 struct sm_anchor *sm;
73 sm = (struct sm_anchor *) grub_efiemu_mm_obtain_request (tablehandle);
74 grub_memcpy (sm + 1, tables, tables_total_size);
75 grub_memcpy (sm->magic, "_SM_", 4);
76 sm->anchor_length = sizeof (*sm);
77 sm->ver_major = smvermajor;
78 sm->ver_minor = smverminor;
79 sm->anchor_revision = 0;
80 grub_memset (sm->pad, 0, sizeof (sm->pad));
81 grub_memcpy (sm->dmi.magic, "_DMI_", 5);
82 sm->dmi.data_addr = PTR_TO_UINT32 (sm + 1);
83 grub_dprintf ("dmigen", "new SMBIOS at %p\n", sm + 1);
84 sm->dmi.data_size = tables_total_size;
85 sm->dmi.revision = ((smvermajor & 0xf) << 4) | smverminor;
86 sm->biggest_table = biggest_table;
87 sm->dmi.ntables = ntables;
88 sm->dmi.csum = 0;
89 sm->dmi.csum = 1 + ~grub_byte_checksum ((grub_uint8_t *) &(sm->dmi),
90 sizeof (sm->dmi));
91 sm->csum = 0;
92 sm->csum = 1 + ~grub_byte_checksum ((grub_uint8_t *) sm, sizeof (*sm));
93 return sm;
96 static void
97 unload (void *data __attribute__ ((unused)))
99 grub_efiemu_mm_return_request (tablehandle);
100 grub_free (tables);
101 tablehandle = 0;
102 tables = 0;
103 tables_total_size = 0;
106 static grub_err_t
107 grub_cmd_efiemu_dmigen (grub_command_t cmd __attribute__ ((unused)),
108 int argc, char *args[])
110 grub_efi_guid_t smbios = GRUB_EFI_SMBIOS_TABLE_GUID;
111 char *ptr;
112 char *inptr, *outptr;
113 grub_file_t file;
114 struct sm_anchor *sm;
115 int excluded[256], handle;
116 grub_size_t fsize;
117 grub_err_t err;
118 char handles[65536];
120 if (argc != 1)
121 return grub_error (GRUB_ERR_BAD_ARGUMENT, "template required");
123 err = grub_efiemu_autocore ();
124 if (err)
125 return err;
127 file = grub_gzfile_open (args[0], 1);
128 if (! file)
129 return grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't read %s");
131 fsize = grub_file_size (file);
133 for (ptr = (char *) 0xf0000; ptr < (char *) 0x100000; ptr += 16)
134 if (grub_memcmp (ptr, "_SM_", 4) == 0
135 && grub_byte_checksum ((grub_uint8_t *) ptr,
136 ((struct sm_anchor *)ptr)->anchor_length) == 0)
137 break;
139 if (ptr < (char *) 0x100000)
141 sm = (struct sm_anchor *) ptr;
142 tables_total_size = sm->dmi.data_size;
143 smvermajor = sm->ver_major;
144 smverminor = sm->ver_minor;
146 else
148 smvermajor = 2;
149 smverminor = 1;
150 sm = 0;
151 tables_total_size = 0;
154 tables_total_size += fsize;
155 tables = grub_malloc (tables_total_size);
156 ntables = 0;
157 biggest_table = 0;
158 if (! tables)
160 grub_file_close (file);
161 return grub_error (GRUB_ERR_OUT_OF_MEMORY,
162 "couldn't allocate space for new tables");
165 grub_ssize_t read;
166 read = grub_file_read (file, tables, fsize);
168 if (read != (grub_ssize_t) fsize)
170 grub_dprintf ("dmigen", "read %d instead of %d\n", (int)read, (int)fsize);
172 grub_file_close (file);
173 grub_free (tables);
174 tables_total_size = 0;
175 tables = 0;
176 return grub_errno;
178 grub_file_close (file);
180 grub_memset (excluded, 0, sizeof (excluded));
181 grub_memset (handles, 0, sizeof (handles));
183 for (inptr = tables; inptr < tables + fsize; )
185 excluded[((struct dmi_table_header *) inptr)->type] = 1;
186 ptr = inptr;
187 ptr += ((struct dmi_table_header *) inptr)->size;
188 if (((struct dmi_table_header *) inptr)->size == 0)
190 fsize = inptr - tables;
191 break;
193 while (ptr + 2 < tables + fsize && (ptr[0] != 0 || ptr[1] != 0))
194 ptr++;
195 ptr += 2;
196 ntables++;
197 if (biggest_table < ptr - inptr)
198 biggest_table = ptr - inptr;
199 inptr = ptr;
201 grub_dprintf ("dmigen", "SM at 0x%x, length %d\n",
202 (int) sm->dmi.data_addr, (int) sm->dmi.data_size);
203 for (inptr = (char *) UINT_TO_PTR (sm->dmi.data_addr),
204 outptr = tables + fsize;
205 inptr < (char *) UINT_TO_PTR (sm->dmi.data_addr)
206 + sm->dmi.data_size; )
208 ptr = inptr;
209 ptr += ((struct dmi_table_header *) inptr)->size;
210 if (((struct dmi_table_header *) inptr)->size == 0)
211 break;
212 while ((ptr + 2 < (char *) UINT_TO_PTR (sm->dmi.data_addr)
213 + sm->dmi.data_size) && (ptr[0] != 0 || ptr[1] != 0))
214 ptr++;
215 ptr += 2;
217 if (! excluded[((struct dmi_table_header *) inptr)->type])
219 grub_memcpy (outptr, inptr, ptr - inptr);
220 outptr += ptr - inptr;
221 ntables++;
222 if (biggest_table < ptr - inptr)
223 biggest_table = ptr - inptr;
224 handles[((struct dmi_table_header *) inptr)->handle] = 1;
226 inptr = ptr;
228 tables_total_size = outptr - tables;
230 handle = 0;
231 for (inptr = tables; inptr < tables + fsize; )
233 if (handles[((struct dmi_table_header *) inptr)->handle])
235 while (handle < 0xfefe && handles[handle])
236 handle++;
237 ((struct dmi_table_header *) inptr)->handle = handle;
239 ptr = inptr;
240 ptr += ((struct dmi_table_header *) inptr)->size;
241 while (ptr + 2 < tables + fsize && (ptr[0] != 0 || ptr[1] != 0))
242 ptr++;
243 ptr += 2;
244 inptr = ptr;
246 grub_dprintf ("dmigen", "tables_total_size=%d\n", tables_total_size);
248 tables = grub_realloc (tables, tables_total_size);
249 if (! tables)
250 return grub_error (GRUB_ERR_OUT_OF_MEMORY,
251 "couldn't allocate space for new tables");
253 tablehandle = grub_efiemu_request_memalign (16, tables_total_size
254 + sizeof (struct dmi_anchor),
255 GRUB_EFI_RUNTIME_SERVICES_DATA);
256 if (tablehandle < 0)
258 tablehandle = 0;
259 grub_free (tables);
260 tables = 0;
261 tables_total_size = 0;
262 return grub_error (GRUB_ERR_OUT_OF_MEMORY,
263 "couldn't allocate space for new tables");
266 err = grub_efiemu_register_configuration_table (smbios, get_table,
267 unload, 0);
269 if (err)
271 grub_efiemu_mm_return_request (tablehandle);
272 grub_free (tables);
273 tablehandle = 0;
274 tables = 0;
275 tables_total_size = 0;
276 return err;
279 return GRUB_ERR_NONE;
282 static grub_command_t cmd_dmigen;
284 GRUB_MOD_INIT(dmigen)
286 cmd_dmigen = grub_register_command ("efiemu_dmigen",
287 grub_cmd_efiemu_dmigen,
288 "efiemu_dmigen TEMPLATE",
289 "Generate DMI tables");
292 GRUB_MOD_FINI(dmigen)
294 grub_unregister_command (cmd_dmigen);