Browse Source

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

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

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

41
  * @ret rc		Return status code
41
  * @ret rc		Return status code
42
  */
42
  */
43
 static int bios_find_smbios ( struct smbios *smbios ) {
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
 PROVIDE_SMBIOS ( pcbios, find_smbios, bios_find_smbios );
61
 PROVIDE_SMBIOS ( pcbios, find_smbios, bios_find_smbios );

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

162
 #define SMBIOS_VERSION( major, minor ) ( ( (major) << 8 ) | (minor) )
162
 #define SMBIOS_VERSION( major, minor ) ( ( (major) << 8 ) | (minor) )
163
 
163
 
164
 extern int find_smbios ( struct smbios *smbios );
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
 extern int find_smbios_structure ( unsigned int type, unsigned int instance,
167
 extern int find_smbios_structure ( unsigned int type, unsigned int instance,
166
 				   struct smbios_structure *structure );
168
 				   struct smbios_structure *structure );
167
 extern int read_smbios_structure ( struct smbios_structure *structure,
169
 extern int read_smbios_structure ( struct smbios_structure *structure,

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

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
  * This program is free software; you can redistribute it and/or
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
5
  * modify it under the terms of the GNU General Public License as
13
  *
13
  *
14
  * You should have received a copy of the GNU General Public License
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
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
 #include <errno.h>
22
 #include <errno.h>
23
+#include <linux_api.h>
24
+#include <ipxe/linux.h>
22
 #include <ipxe/smbios.h>
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
  * Find SMBIOS
40
  * Find SMBIOS
26
  *
41
  *
27
- * Not implemented currently.
28
- *
29
  * @v smbios		SMBIOS entry point descriptor structure to fill in
42
  * @v smbios		SMBIOS entry point descriptor structure to fill in
30
  * @ret rc		Return status code
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
 	.address = UNULL,
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
  * Find SMBIOS strings terminator
89
  * Find SMBIOS strings terminator
42
  *
90
  *

Loading…
Cancel
Save