|  | @@ -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 );
 |