Skip to contentSkip to conversation

add SMBIOS information to /proc/smbios/

PATCH In review Michael Brown 2 participants 3 messages Apr 29, 2004 Char and misc drivers

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 add SMBIOS information to /proc/smbios/

Marcelo,
Below is a small patch for 2.4. The purpose of the patch is to export
the BIOS-provided SMBIOS tables via /proc/smbios/.

This has been submitted against 2.6. Greg KH has agreed to forward to
mainline for the 2.6.7 release cycle. Original discussion thread for the 2.6 version, with rationale is here:
http://marc.theaimsgroup.com/?l=linux-kernel&m=108311953028747&w=1

In short, the normal way for userspace programs to access SMBIOS is
through /dev/mem. This will break in the near future as platforms move SMBIOS tables into highmem.

This patch adds two files, smbios.c and smbios.h. It does not modify
any other code in the tree. It is also small, ~250 lines. Thus, I believe that this is appropriate for 2.4.

Please apply.
--
Michael Brown

-----Forwarded Message-----
From: [email protected]
To: [email protected]
Subject: 2.4 patch for smbios
Date: Thu, 29 Apr 2004 00:22:03 -0500

# This is a BitKeeper generated diff -Nru style patch. #
# ChangeSet
# 2004/04/29 00:16:35-05:00 [email protected]
# rename smbios to proper smbios.c
#
# drivers/char/Makefile
# 2004/04/29 00:09:15-05:00 [email protected] +1 -1
# rename smbios driver to 'smbios'.
#

# drivers/char/smbios.c
#   2004/04/29 00:08:51-05:00 [email protected] +0 -0
#   Rename: drivers/char/procsmbios.c -> drivers/char/smbios.c
# 
# ChangeSet
#   2004/04/28 23:51:19-05:00 [email protected] 
#   Add SMBIOS driver that exports system SMBIOS information as files in /proc/smbios.
# 
# drivers/char/smbios.h
#   2004/04/28 23:50:15-05:00 [email protected] +53 -0
# 
# drivers/char/procsmbios.c
#   2004/04/28 23:50:15-05:00 [email protected] +251 -0
# 
# drivers/char/smbios.h
#   2004/04/28 23:50:15-05:00 [email protected] +0 -0
#   BitKeeper file /home/michael_e_brown/kernel/bk/subtrees/smbios-24-driver/drivers/char/smbios.h
# 
# drivers/char/procsmbios.c
#   2004/04/28 23:50:15-05:00 [email protected] +0 -0
#   BitKeeper file /home/michael_e_brown/kernel/bk/subtrees/smbios-24-driver/drivers/char/procsmbios.c
# 
# drivers/char/Makefile
#   2004/04/28 23:50:15-05:00 [email protected] +1 -0
#   Add SMBIOS driver to build system
# 
# drivers/char/Config.in
#   2004/04/28 23:50:15-05:00 [email protected] +1 -0
#   Add config option to turn on SMBIOS proc driver
# 
# Documentation/Configure.help
#   2004/04/28 23:50:15-05:00 [email protected] +14 -0
#   Add help text for SMBIOS driver
# 
diff -Nru a/Documentation/Configure.help b/Documentation/Configure.help
--- a/Documentation/Configure.help	Thu Apr 29 00:20:17 2004
+++ b/Documentation/Configure.help	Thu Apr 29 00:20:17 2004
@@ -19914,6 +19914,20 @@

If unsure, say N.

+SMBIOS table information in /proc
+CONFIG_SMBIOS

+  This driver creates two files in /proc, /proc/smbios/table_entry_point
+  and /proc/smbios/table. These two files contain the contents of the 
+  BIOS-generated SMBIOS tables. Generally, PC-like architectures made
+  after 1997 have this, it is safe to enable on any system.
+  
+  To compile this driver as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read <file:Documentation/modules.txt>. The module will be called
+  smbios.o.

+
+ If unsure, say N.
+
Sony Vaio Programmable I/O Control Device support CONFIG_SONYPI
This driver enables access to the Sony Programmable I/O Control

drivers/char/Config.in +1 -0
diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
@@ -333,6 +333,7 @@
 if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X86" = "y" -a "$CONFIG_X86_64" != "y" ]; then
    dep_tristate 'Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)' CONFIG_SONYPI $CONFIG_PCI
 fi
+tristate 'SMBIOS table information in /proc' CONFIG_SMBIOS
 
 mainmenu_option next_comment
 comment 'Ftape, the floppy tape device driver'
drivers/char/Makefile +1 -0
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
@@ -265,6 +265,7 @@
 obj-$(CONFIG_HW_RANDOM) += hw_random.o
 obj-$(CONFIG_AMD_PM768) += amd76x_pm.o
 obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
+obj-$(CONFIG_SMBIOS) += smbios.o
 
 obj-$(CONFIG_ITE_GPIO) += ite_gpio.o
 obj-$(CONFIG_AU1X00_GPIO) += au1000_gpio.o
drivers/char/smbios.c new file +251 -0

251 lines not on this page · raw message

drivers/char/smbios.h new file +53 -0

53 lines not on this page · raw message

#1 lore raw

drivers/char/smbios.c line 153

Quoted 12 lines · Michael Brown
drivers/char/smbios.c new file +12 -0
+smbios_read_table_entry_point(char *page, char **start,
+				off_t off, int count,
+				int *eof, void *data)
+{
+	unsigned int max_off = sizeof(the_smbios_device.table_eps);
+	MOD_INC_USE_COUNT;
+
+	memcpy(page, &the_smbios_device.table_eps, max_off);
+
+	MOD_DEC_USE_COUNT;
+	return max_off;
+}

*LART*

Use ->owner instead of (racy) messing with MOD_{INC,DEC}_USE_COUNT.

Quoted 25 lines
drivers/char/smbios.c new file +25 -0
+/* Use the more flexible procfs style. We tell the core that we can handle
+ * >4k transactions by setting *start. When doing this we also have to handle
+ * our own *eof and make sure not to overrun the page or count given.
+ */
+static ssize_t
+smbios_read_table(char *page, char **start,
+		off_t offset, int count,
+		int *eof, void *data)
+{
+	u8 *buf;
+	int i = 0;
+	int max_off = the_smbios_device.smbios_table_real_length;
+	MOD_INC_USE_COUNT;
+
+	if (offset > max_off)
+		return 0;
+
+	if (count > (max_off - offset))
+		count = max_off - offset;
+
+	buf = ioremap(the_smbios_device.table_eps.table_address, max_off);
+	if (buf == NULL)
+		return -ENXIO;
+
+	/* memcpy( buffer, buf+pos, count ); */

drivers/char/smbios.c line 189

Quoted 10 lines
drivers/char/smbios.c new file +10 -0
+	for (i = 0; i < count; ++i) {
+		page[i] = readb( buf+offset+i );
+	}
+
+	iounmap(buf);
+
+	*start = page; /* tells procfs that we handle >1 page */
+	MOD_DEC_USE_COUNT;
+	return count;
+}

... and the reason why you need to go through procfs default ->read() instead of providing an obvious one of your own would be...? Note that it would be smaller and simpler than your callback above.

#2 lore raw
Quoted 16 lines · On Thu, 2004-04-29 at 00:50, [email protected] wrote:

drivers/char/smbios.c line 153

Quoted 12 lines · Michael Brown
drivers/char/smbios.c new file +12 -0
+smbios_read_table_entry_point(char *page, char **start,
+				off_t off, int count,
+				int *eof, void *data)
+{
+	unsigned int max_off = sizeof(the_smbios_device.table_eps);
+	MOD_INC_USE_COUNT;
+
+	memcpy(page, &the_smbios_device.table_eps, max_off);
+
+	MOD_DEC_USE_COUNT;
+	return max_off;
+}

*LART*

Quoted 1 line

Use ->owner instead of (racy) messing with MOD_{INC,DEC}_USE_COUNT.

First, thanks for the feedback Al. I really appreciate it.

I had set ->owner in my module init function.

in smbios_init():
+ smbios_dir->owner = THIS_MODULE;
and a bit further down...
+ table_eps_file->owner = THIS_MODULE;

Documentation/DocBook/procfs_example.c is what I used as my example along with the "Linux Device Drivers" book. The in-tree docs have MOD_{INC,DEC}_USE_COUNT, so that is what I did. If these are not necessary, I will remove them.

Also note that one of my standard tests that I do before submission is a "while true; insmod smbios; rmmod smbios; done &"
"while true; hexdump -C /proc/smbios/*; done"

and let it run for a few hours. This code had all passed that test.

Quoted 32 lines
Quoted 32 lines
drivers/char/smbios.c new file +31 -0
+/* Use the more flexible procfs style. We tell the core that we can handle
+ * >4k transactions by setting *start. When doing this we also have to handle
+ * our own *eof and make sure not to overrun the page or count given.
+ */
+static ssize_t
+smbios_read_table(char *page, char **start,
+		off_t offset, int count,
+		int *eof, void *data)
+{
+	u8 *buf;
+	int i = 0;
+	int max_off = the_smbios_device.smbios_table_real_length;
+	MOD_INC_USE_COUNT;
+
+	if (offset > max_off)
+		return 0;
+
+	if (count > (max_off - offset))
+		count = max_off - offset;
+
+	buf = ioremap(the_smbios_device.table_eps.table_address, max_off);
+	if (buf == NULL)
+		return -ENXIO;
+
+	/* memcpy( buffer, buf+pos, count ); */
+	for (i = 0; i < count; ++i) {
+		page[i] = readb( buf+offset+i );
+	}
+
+	iounmap(buf);
+
Quoted 8 lines

drivers/char/smbios.c line 189

Quoted 4 lines
drivers/char/smbios.c new file +4 -0
+	*start = page; /* tells procfs that we handle >1 page */
+	MOD_DEC_USE_COUNT;
+	return count;
+}

... and the reason why you need to go through procfs default ->read() instead of providing an obvious one of your own would be...? Note that it would be smaller and simpler than your callback above.

You will have to excuse my ignorace here. I used the in tree Documentation/, google, and fs/proc/proc_misc.c as reference. I assume you mean something like this:

        table_file = create_proc_read_entry( "table",
                                               0444, smbios_dir,
                                               smbios_read_table,
                                               NULL);
	if(table_file)
		table_file->fops.read = &smbios_read_table;

Correct?

And then in my smbios_read_table, do a normal read-like method where I put_user().

Comparing the code above to proc_misc.c, it looks like almost the same amount of code, but it is probably easier to understand than the above magic (which, admittedly took a while of googling to figure out), but I thought that was just normal proc/ style and I was just unfamiliar with it.

I will make these two changes and resubmit later today.

Thanks,
Michael