1 /* dmigen.c - generate smbios tables based on template. */
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/>.
21 #include <grub/command.h>
22 #include <grub/efiemu/efiemu.h>
23 #include <grub/i386/pc/efiemu.h>
24 #include <grub/misc.h>
26 #include <grub/file.h>
28 #include <grub/gzio.h>
29 #include <grub/acpi.h>
33 grub_uint8_t magic
[5];
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
));
43 grub_uint8_t magic
[4];
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
;
51 struct dmi_anchor dmi
;
52 } __attribute__ ((packed
));
54 struct dmi_table_header
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;
70 get_table (void *data
__attribute__ ((unused
)))
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
;
89 sm
->dmi
.csum
= 1 + ~grub_byte_checksum ((grub_uint8_t
*) &(sm
->dmi
),
92 sm
->csum
= 1 + ~grub_byte_checksum ((grub_uint8_t
*) sm
, sizeof (*sm
));
97 unload (void *data
__attribute__ ((unused
)))
99 grub_efiemu_mm_return_request (tablehandle
);
103 tables_total_size
= 0;
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
;
112 char *inptr
, *outptr
;
114 struct sm_anchor
*sm
;
115 int excluded
[256], handle
;
121 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "template required");
123 err
= grub_efiemu_autocore ();
127 file
= grub_gzfile_open (args
[0], 1);
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)
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
;
151 tables_total_size
= 0;
154 tables_total_size
+= fsize
;
155 tables
= grub_malloc (tables_total_size
);
160 grub_file_close (file
);
161 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
162 "couldn't allocate space for new tables");
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
);
174 tables_total_size
= 0;
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;
187 ptr
+= ((struct dmi_table_header
*) inptr
)->size
;
188 if (((struct dmi_table_header
*) inptr
)->size
== 0)
190 fsize
= inptr
- tables
;
193 while (ptr
+ 2 < tables
+ fsize
&& (ptr
[0] != 0 || ptr
[1] != 0))
197 if (biggest_table
< ptr
- inptr
)
198 biggest_table
= ptr
- inptr
;
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
; )
209 ptr
+= ((struct dmi_table_header
*) inptr
)->size
;
210 if (((struct dmi_table_header
*) inptr
)->size
== 0)
212 while ((ptr
+ 2 < (char *) UINT_TO_PTR (sm
->dmi
.data_addr
)
213 + sm
->dmi
.data_size
) && (ptr
[0] != 0 || ptr
[1] != 0))
217 if (! excluded
[((struct dmi_table_header
*) inptr
)->type
])
219 grub_memcpy (outptr
, inptr
, ptr
- inptr
);
220 outptr
+= ptr
- inptr
;
222 if (biggest_table
< ptr
- inptr
)
223 biggest_table
= ptr
- inptr
;
224 handles
[((struct dmi_table_header
*) inptr
)->handle
] = 1;
228 tables_total_size
= outptr
- tables
;
231 for (inptr
= tables
; inptr
< tables
+ fsize
; )
233 if (handles
[((struct dmi_table_header
*) inptr
)->handle
])
235 while (handle
< 0xfefe && handles
[handle
])
237 ((struct dmi_table_header
*) inptr
)->handle
= handle
;
240 ptr
+= ((struct dmi_table_header
*) inptr
)->size
;
241 while (ptr
+ 2 < tables
+ fsize
&& (ptr
[0] != 0 || ptr
[1] != 0))
246 grub_dprintf ("dmigen", "tables_total_size=%d\n", tables_total_size
);
248 tables
= grub_realloc (tables
, tables_total_size
);
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
);
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
,
271 grub_efiemu_mm_return_request (tablehandle
);
275 tables_total_size
= 0;
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
);