11#include "common/smbios.h"
22#include "common/io.h"
3- #include "common/unused.h"
43#include "common/mallocHelper.h"
54#include "common/debug.h"
65
@@ -138,14 +137,54 @@ static bool parseSmbiosTable(const uint8_t* data, uint32_t length) {
138137# include "common/properties.h"
139138# elif defined(__FreeBSD__ )
140139# include "common/settings.h"
141- # define loff_t off_t // FreeBSD doesn't have loff_t
142- # elif defined(__sun )
140+ # define loff_t off_t
141+ # elif defined(__sun ) || defined( __OpenBSD__ )
143142# define loff_t off_t
144143# elif defined(__NetBSD__ )
145144# include "common/sysctl.h"
146145# define loff_t off_t
147146# endif
148147
148+ static bool readPhysicalMemory (int fd , loff_t address , size_t length , void * buffer ) {
149+ # if !defined(__FreeBSD__ ) // Either causes kernel panic or returns EFAULT
150+ // -1: unknown, 0: failed before (stop trying), 1: succeeded before
151+ static int preadState = -1 ;
152+ if (preadState != 0 ) {
153+ ssize_t bytesRead = pread (fd , buffer , length , address );
154+ if (bytesRead == (ssize_t ) length ) {
155+ preadState = 1 ;
156+ return true;
157+ }
158+
159+ FF_DEBUG ("pread failed at address 0x%lx for %zu bytes: %s. Falling back to mmap%s" ,
160+ (unsigned long ) address ,
161+ length ,
162+ strerror (errno ),
163+ preadState < 0 ? " and caching failure" : "" );
164+ preadState = 0 ;
165+ } else {
166+ FF_DEBUG ("Skipping pread due to cached failure; using mmap" );
167+ }
168+ # endif
169+
170+ loff_t alignedAddress = address & ~((loff_t ) instance .state .platform .sysinfo .pageSize - 1 );
171+ size_t pageOffset = (size_t ) (address - alignedAddress );
172+ size_t mapLength = pageOffset + length ;
173+
174+ void * p = mmap (NULL , mapLength , PROT_READ , MAP_SHARED , fd , alignedAddress );
175+ if (p == MAP_FAILED ) {
176+ FF_DEBUG ("mmap failed at aligned address 0x%lx for %zu bytes: %s" ,
177+ (unsigned long ) alignedAddress ,
178+ mapLength ,
179+ strerror (errno ));
180+ return false;
181+ }
182+
183+ memcpy (buffer , (const uint8_t * ) p + pageOffset , length );
184+ munmap (p , mapLength );
185+ return true;
186+ }
187+
149188# ifdef __linux__
150189bool ffGetSmbiosValue (const char * devicesPath , const char * classPath , FFstrbuf * buffer ) {
151190 // /sys/class/dmi/id/* are all pseudo-files with very small content
@@ -291,22 +330,10 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
291330 FF_DEBUG ("Attempting to read %zu bytes from physical address 0x%lx" ,
292331 sizeof (entryPoint ),
293332 (unsigned long ) entryAddress );
294-
295- if (pread (fd , & entryPoint , sizeof (entryPoint ), entryAddress ) < 0x10 ) {
296- FF_DEBUG ("pread failed: %s. Trying mmap" , strerror (errno ));
297- // `pread /dev/mem` returns EFAULT in FreeBSD
298- // https://stackoverflow.com/questions/69372330/how-to-read-dev-mem-using-read
299- void * p = mmap (NULL , sizeof (entryPoint ), PROT_READ , MAP_SHARED , fd , entryAddress );
300- if (p == MAP_FAILED ) {
301- FF_DEBUG ("mmap failed: %s" , strerror (errno ));
302- return NULL ;
303- }
304- memcpy (& entryPoint , p , sizeof (entryPoint ));
305- munmap (p , sizeof (entryPoint ));
306- FF_DEBUG ("Successfully read entry point data via mmap" );
307- } else {
308- FF_DEBUG ("Successfully read entry point data via pread" );
333+ if (!readPhysicalMemory (fd , entryAddress , sizeof (entryPoint ), & entryPoint )) {
334+ return NULL ;
309335 }
336+ FF_DEBUG ("Successfully read SMBIOS entry point data" );
310337# else
311338 // Sun or NetBSD
312339 FF_DEBUG ("Using %s specific implementation" ,
@@ -388,37 +415,25 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
388415
389416 ffStrbufEnsureFixedLengthFree (& buffer , tableLength );
390417 FF_DEBUG ("Attempting to read SMBIOS table data: %u bytes at 0x%lx" , tableLength , (unsigned long ) tableAddress );
391- if (pread (fd , buffer . chars , tableLength , tableAddress ) == ( ssize_t ) tableLength ) {
418+ if (readPhysicalMemory (fd , tableAddress , tableLength , buffer . chars ) ) {
392419 buffer .length = tableLength ;
393420 buffer .chars [buffer .length ] = '\0' ;
394421 FF_DEBUG ("Successfully read SMBIOS table data: %u bytes" , tableLength );
395422 } else {
396- FF_DEBUG ("pread failed, trying mmap" );
397- // entryPoint.StructureTableAddress must be page aligned.
398- // Unaligned physical memory access results in all kinds of crashes.
399- void * p = mmap (NULL , tableLength , PROT_READ , MAP_SHARED , fd , tableAddress );
400- if (p == MAP_FAILED ) {
401- FF_DEBUG ("mmap failed: %s" , strerror (errno ));
402- ffStrbufDestroy (& buffer ); // free buffer and reset state
403- return NULL ;
404- }
405- ffStrbufSetNS (& buffer , tableLength , (char * ) p );
406- munmap (p , tableLength );
407- FF_DEBUG ("Successfully read SMBIOS table data via mmap: %u bytes" , tableLength );
423+ ffStrbufDestroy (& buffer ); // free buffer and reset state
424+ return NULL ;
408425 }
409426 }
410-
411- return NULL ;
412427# endif
413428
414429 fallback :
415430 if (buffer .length == 0 ) {
416431 const char * devMem =
417- # if __HAIKU__
432+ # if __HAIKU__
418433 "/dev/misc/mem" ;
419- # else
434+ # else
420435 "/dev/mem" ; // kern.securelevel must be -1
421- # endif
436+ # endif
422437 FF_DEBUG ("Using physical memory searching implementation: %s" , devMem );
423438
424439 uint32_t tableLength = 0 ;
@@ -436,8 +451,8 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
436451 // However, to acquire SMBIOS entry point, we need EFI configuration table (provided by EFI system table)
437452 // which is not available via EFIIOC_GET_TABLE.
438453 FF_AUTO_FREE uint8_t * smBiosBase = malloc (0x10000 );
439- if (pread (fd , smBiosBase , 0x10000 , 0xF0000 ) != 0x10000 ) {
440- FF_DEBUG ("Failed to read SMBIOS memory region: %s" , strerror ( errno ) );
454+ if (! readPhysicalMemory (fd , 0xF0000 , 0x10000 , smBiosBase ) ) {
455+ FF_DEBUG ("Failed to read SMBIOS memory region" );
441456 return NULL ;
442457 }
443458 FF_DEBUG ("Successfully read 0x10000 bytes from physical address 0xF0000" );
@@ -486,12 +501,12 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
486501
487502 ffStrbufEnsureFixedLengthFree (& buffer , tableLength );
488503 FF_DEBUG ("Attempting to read SMBIOS table data: %u bytes at 0x%lx" , tableLength , (unsigned long ) tableAddress );
489- if (pread (fd , buffer . chars , tableLength , tableAddress ) == tableLength ) {
504+ if (readPhysicalMemory (fd , ( loff_t ) tableAddress , tableLength , buffer . chars ) ) {
490505 buffer .length = tableLength ;
491506 buffer .chars [buffer .length ] = '\0' ;
492507 FF_DEBUG ("Successfully read SMBIOS table data: %u bytes" , tableLength );
493508 } else {
494- FF_DEBUG ("Failed to read SMBIOS table data: %s" , strerror ( errno ) );
509+ FF_DEBUG ("Failed to read SMBIOS table data" );
495510 return NULL ;
496511 }
497512 }
0 commit comments