Browse Source

[linux] Provide access to SMBIOS via /dev/mem

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
03957bcb47

+ 12
- 40
src/arch/i386/interface/pcbios/bios_smbios.c View File

@@ -41,49 +41,21 @@ FILE_LICENCE ( GPL2_OR_LATER );
41 41
  * @ret rc		Return status code
42 42
  */
43 43
 static int bios_find_smbios ( struct smbios *smbios ) {
44
-	union {
45
-		struct smbios_entry entry;
46
-		uint8_t bytes[256]; /* 256 is maximum length possible */
47
-	} u;
48
-	static unsigned int offset = 0;
49
-	size_t len;
50
-	unsigned int i;
51
-	uint8_t sum;
44
+	struct smbios_entry entry;
45
+	int rc;
52 46
 
53
-	/* Try to find SMBIOS */
54
-	for ( ; offset < 0x10000 ; offset += 0x10 ) {
47
+	/* Scan through BIOS segment to find SMBIOS entry point */
48
+	if ( ( rc = find_smbios_entry ( real_to_user ( BIOS_SEG, 0 ), 0x10000,
49
+					&entry ) ) != 0 )
50
+		return rc;
55 51
 
56
-		/* Read start of header and verify signature */
57
-		copy_from_real ( &u.entry, BIOS_SEG, offset,
58
-				 sizeof ( u.entry ));
59
-		if ( u.entry.signature != SMBIOS_SIGNATURE )
60
-			continue;
52
+	/* Fill in entry point descriptor structure */
53
+	smbios->address = phys_to_user ( entry.smbios_address );
54
+	smbios->len = entry.smbios_len;
55
+	smbios->count = entry.smbios_count;
56
+	smbios->version = SMBIOS_VERSION ( entry.major, entry.minor );
61 57
 
62
-		/* Read whole header and verify checksum */
63
-		len = u.entry.len;
64
-		copy_from_real ( &u.bytes, BIOS_SEG, offset, len );
65
-		for ( i = 0 , sum = 0 ; i < len ; i++ ) {
66
-			sum += u.bytes[i];
67
-		}
68
-		if ( sum != 0 ) {
69
-			DBG ( "SMBIOS at %04x:%04x has bad checksum %02x\n",
70
-			      BIOS_SEG, offset, sum );
71
-			continue;
72
-		}
73
-
74
-		/* Fill result structure */
75
-		DBG ( "Found SMBIOS v%d.%d entry point at %04x:%04x\n",
76
-		      u.entry.major, u.entry.minor, BIOS_SEG, offset );
77
-		smbios->address = phys_to_user ( u.entry.smbios_address );
78
-		smbios->len = u.entry.smbios_len;
79
-		smbios->count = u.entry.smbios_count;
80
-		smbios->version =
81
-			SMBIOS_VERSION ( u.entry.major, u.entry.minor );
82
-		return 0;
83
-	}
84
-
85
-	DBG ( "No SMBIOS found\n" );
86
-	return -ENODEV;
58
+	return 0;
87 59
 }
88 60
 
89 61
 PROVIDE_SMBIOS ( pcbios, find_smbios, bios_find_smbios );

+ 2
- 0
src/include/ipxe/smbios.h View File

@@ -162,6 +162,8 @@ struct smbios {
162 162
 #define SMBIOS_VERSION( major, minor ) ( ( (major) << 8 ) | (minor) )
163 163
 
164 164
 extern int find_smbios ( struct smbios *smbios );
165
+extern int find_smbios_entry ( userptr_t start, size_t len,
166
+			       struct smbios_entry *entry );
165 167
 extern int find_smbios_structure ( unsigned int type, unsigned int instance,
166 168
 				   struct smbios_structure *structure );
167 169
 extern int read_smbios_structure ( struct smbios_structure *structure,

+ 87
- 9
src/interface/linux/linux_smbios.c View File

@@ -1,5 +1,5 @@
1 1
 /*
2
- * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com>
2
+ * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
3 3
  *
4 4
  * This program is free software; you can redistribute it and/or
5 5
  * modify it under the terms of the GNU General Public License as
@@ -13,25 +13,103 @@
13 13
  *
14 14
  * You should have received a copy of the GNU General Public License
15 15
  * along with this program; if not, write to the Free Software
16
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
17 18
  */
18 19
 
19
-FILE_LICENCE(GPL2_OR_LATER);
20
+FILE_LICENCE ( GPL2_OR_LATER );
20 21
 
21 22
 #include <errno.h>
23
+#include <linux_api.h>
24
+#include <ipxe/linux.h>
22 25
 #include <ipxe/smbios.h>
23 26
 
27
+/** SMBIOS filename */
28
+static const char smbios_filename[] = "/dev/mem";
29
+
30
+/** SMBIOS entry point scan region start address */
31
+#define SMBIOS_ENTRY_START 0xf0000
32
+
33
+/** SMBIOS entry point scan region length */
34
+#define SMBIOS_ENTRY_LEN 0x10000
35
+
36
+/** SMBIOS mapping alignment */
37
+#define SMBIOS_ALIGN 0x1000
38
+
24 39
 /**
25 40
  * Find SMBIOS
26 41
  *
27
- * Not implemented currently.
28
- *
29 42
  * @v smbios		SMBIOS entry point descriptor structure to fill in
30 43
  * @ret rc		Return status code
31 44
  */
32
-static int linux_find_smbios(struct smbios *smbios __unused)
33
-{
34
-	return -ENODEV;
45
+static int linux_find_smbios ( struct smbios *smbios ) {
46
+	struct smbios_entry entry;
47
+	void *entry_mem;
48
+	void *smbios_mem;
49
+	size_t smbios_offset;
50
+	size_t smbios_indent;
51
+	size_t smbios_len;
52
+	int fd;
53
+	int rc;
54
+
55
+	/* Open SMBIOS file */
56
+	fd = linux_open ( smbios_filename, O_RDONLY );
57
+	if ( fd < 0 ) {
58
+		rc = -ELINUX ( linux_errno );
59
+		DBGC ( smbios, "SMBIOS could not open %s: %s\n",
60
+		       smbios_filename, linux_strerror ( linux_errno ) );
61
+		goto err_open;
62
+	}
63
+
64
+	/* Map the region potentially containing the SMBIOS entry point */
65
+	entry_mem = linux_mmap ( NULL, SMBIOS_ENTRY_LEN, PROT_READ, MAP_SHARED,
66
+				 fd, SMBIOS_ENTRY_START );
67
+	if ( entry_mem == MAP_FAILED ) {
68
+		rc = -ELINUX ( linux_errno );
69
+		DBGC ( smbios, "SMBIOS could not mmap %s (%#x+%#x): %s\n",
70
+		       smbios_filename, SMBIOS_ENTRY_START, SMBIOS_ENTRY_LEN,
71
+		       linux_strerror ( linux_errno ) );
72
+		goto err_mmap_entry;
73
+	}
74
+
75
+	/* Scan for the SMBIOS entry point */
76
+	if ( ( rc = find_smbios_entry ( virt_to_user ( entry_mem ),
77
+					SMBIOS_ENTRY_LEN, &entry ) ) != 0 )
78
+		goto err_find_entry;
79
+
80
+	/* Map the region containing the SMBIOS structures */
81
+	smbios_indent = ( entry.smbios_address & ( SMBIOS_ALIGN - 1 ) );
82
+	smbios_offset = ( entry.smbios_address - smbios_indent );
83
+	smbios_len = ( entry.smbios_len + smbios_indent );
84
+	smbios_mem = linux_mmap ( NULL, smbios_len, PROT_READ, MAP_SHARED,
85
+				  fd, smbios_offset );
86
+	if ( smbios_mem == MAP_FAILED ) {
87
+		rc = -ELINUX ( linux_errno );
88
+		DBGC ( smbios, "SMBIOS could not mmap %s (%#zx+%#zx): %s\n",
89
+		       smbios_filename, smbios_offset, smbios_len,
90
+		       linux_strerror ( linux_errno ) );
91
+		goto err_mmap_smbios;
92
+	}
93
+
94
+	/* Fill in entry point descriptor structure */
95
+	smbios->address = virt_to_user ( smbios_mem + smbios_indent );
96
+	smbios->len = entry.smbios_len;
97
+	smbios->count = entry.smbios_count;
98
+	smbios->version = SMBIOS_VERSION ( entry.major, entry.minor );
99
+
100
+	/* Unmap the entry point region (no longer required) */
101
+	linux_munmap ( entry_mem, SMBIOS_ENTRY_LEN );
102
+
103
+	return 0;
104
+
105
+	linux_munmap ( smbios_mem, smbios_len );
106
+ err_mmap_smbios:
107
+ err_find_entry:
108
+	linux_munmap ( entry_mem, SMBIOS_ENTRY_LEN );
109
+ err_mmap_entry:
110
+	linux_close ( fd );
111
+ err_open:
112
+	return rc;
35 113
 }
36 114
 
37
-PROVIDE_SMBIOS(linux, find_smbios, linux_find_smbios);
115
+PROVIDE_SMBIOS ( linux, find_smbios, linux_find_smbios );

+ 48
- 0
src/interface/smbios/smbios.c View File

@@ -37,6 +37,54 @@ static struct smbios smbios = {
37 37
 	.address = UNULL,
38 38
 };
39 39
 
40
+/**
41
+ * Scan for SMBIOS entry point structure
42
+ *
43
+ * @v start		Start address of region to scan
44
+ * @v len		Length of region to scan
45
+ * @v entry		SMBIOS entry point structure to fill in
46
+ * @ret rc		Return status code
47
+ */
48
+int find_smbios_entry ( userptr_t start, size_t len,
49
+			struct smbios_entry *entry ) {
50
+	uint8_t buf[256]; /* 256 is maximum length possible */
51
+	static size_t offset = 0; /* Avoid repeated attempts to locate SMBIOS */
52
+	size_t entry_len;
53
+	unsigned int i;
54
+	uint8_t sum;
55
+
56
+	/* Try to find SMBIOS */
57
+	for ( ; offset < len ; offset += 0x10 ) {
58
+
59
+		/* Read start of header and verify signature */
60
+		copy_from_user ( entry, start, offset, sizeof ( *entry ) );
61
+		if ( entry->signature != SMBIOS_SIGNATURE )
62
+			continue;
63
+
64
+		/* Read whole header and verify checksum */
65
+		entry_len = entry->len;
66
+		assert ( entry_len <= sizeof ( buf ) );
67
+		copy_from_user ( buf, start, offset, entry_len );
68
+		for ( i = 0, sum = 0 ; i < entry_len ; i++ ) {
69
+			sum += buf[i];
70
+		}
71
+		if ( sum != 0 ) {
72
+			DBG ( "SMBIOS at %08lx has bad checksum %02x\n",
73
+			      user_to_phys ( start, offset ), sum );
74
+			continue;
75
+		}
76
+
77
+		/* Fill result structure */
78
+		DBG ( "Found SMBIOS v%d.%d entry point at %08lx\n",
79
+		      entry->major, entry->minor,
80
+		      user_to_phys ( start, offset ) );
81
+		return 0;
82
+	}
83
+
84
+	DBG ( "No SMBIOS found\n" );
85
+	return -ENODEV;
86
+}
87
+
40 88
 /**
41 89
  * Find SMBIOS strings terminator
42 90
  *

Loading…
Cancel
Save