2020-01-18 09:38:21 +01:00
/*
2020-03-06 16:55:17 +02:00
* Copyright ( c ) 2020 , Liav A . < liavalb @ hotmail . co . il >
2020-01-18 09:38:21 +01:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2020-03-23 13:45:10 +01:00
# include <AK/StringView.h>
2019-12-31 13:02:21 +02:00
# include <Kernel/ACPI/DMIDecoder.h>
# include <Kernel/VM/MemoryManager.h>
2020-02-09 16:47:15 +02:00
# include <LibBareMetal/StdLib.h>
2019-12-31 13:02:21 +02:00
2020-02-16 01:27:42 +01:00
namespace Kernel {
2019-12-31 13:02:21 +02:00
static DMIDecoder * s_dmi_decoder ;
//#define SMBIOS_DEBUG
# define SMBIOS_BASE_SEARCH_ADDR 0xf0000
# define SMBIOS_END_SEARCH_ADDR 0xfffff
# define SMBIOS_SEARCH_AREA_SIZE (SMBIOS_END_SEARCH_ADDR - SMBIOS_BASE_SEARCH_ADDR)
DMIDecoder & DMIDecoder : : the ( )
{
if ( s_dmi_decoder = = nullptr ) {
s_dmi_decoder = new DMIDecoder ( true ) ;
}
return * s_dmi_decoder ;
}
void DMIDecoder : : initialize ( )
{
if ( s_dmi_decoder = = nullptr ) {
s_dmi_decoder = new DMIDecoder ( true ) ;
}
}
void DMIDecoder : : initialize_untrusted ( )
{
if ( s_dmi_decoder = = nullptr ) {
s_dmi_decoder = new DMIDecoder ( false ) ;
}
}
2020-02-24 13:59:48 +02:00
void DMIDecoder : : set_64_bit_entry_initialization_values ( PhysicalAddress entry )
2020-01-21 04:35:57 +02:00
{
2020-03-06 15:00:44 +01:00
klog ( ) < < " DMIDecoder: SMBIOS 64bit Entry point @ " < < m_entry64bit_point ;
2020-01-21 04:35:57 +02:00
m_use_64bit_entry = true ;
2020-02-24 13:59:48 +02:00
auto region = MM . allocate_kernel_region ( entry . page_base ( ) , PAGE_ROUND_UP ( SMBIOS_SEARCH_AREA_SIZE ) , " DMI Decoder 64 bit Initialization " , Region : : Access : : Read , false , false ) ;
2020-03-08 18:29:48 +02:00
auto & entry_ptr = * ( SMBIOS : : EntryPoint64bit * ) region - > vaddr ( ) . offset ( entry . offset_in_page ( ) ) . as_ptr ( ) ;
2020-02-24 13:59:48 +02:00
m_structure_table = PhysicalAddress ( entry_ptr . table_ptr ) ;
2020-01-21 04:35:57 +02:00
m_structures_count = entry_ptr . table_maximum_size ;
m_table_length = entry_ptr . table_maximum_size ;
}
2020-02-24 13:59:48 +02:00
void DMIDecoder : : set_32_bit_entry_initialization_values ( PhysicalAddress entry )
2020-01-21 04:35:57 +02:00
{
2020-03-06 15:00:44 +01:00
klog ( ) < < " DMIDecoder: SMBIOS 32bit Entry point @ " < < m_entry32bit_point ;
2020-01-21 04:35:57 +02:00
m_use_64bit_entry = false ;
2020-02-24 13:59:48 +02:00
auto region = MM . allocate_kernel_region ( entry . page_base ( ) , PAGE_ROUND_UP ( SMBIOS_SEARCH_AREA_SIZE ) , " DMI Decoder 32 bit Initialization " , Region : : Access : : Read , false , false ) ;
2020-03-08 18:29:48 +02:00
auto & entry_ptr = * ( SMBIOS : : EntryPoint32bit * ) region - > vaddr ( ) . offset ( entry . offset_in_page ( ) ) . as_ptr ( ) ;
2020-01-21 04:35:57 +02:00
2020-02-24 13:59:48 +02:00
m_structure_table = PhysicalAddress ( entry_ptr . legacy_structure . smbios_table_ptr ) ;
2020-01-21 04:35:57 +02:00
m_structures_count = entry_ptr . legacy_structure . smbios_tables_count ;
m_table_length = entry_ptr . legacy_structure . smboios_table_length ;
}
2019-12-31 13:02:21 +02:00
void DMIDecoder : : initialize_parser ( )
{
2020-02-24 13:59:48 +02:00
if ( m_entry32bit_point . is_null ( ) & & m_entry64bit_point . is_null ( ) ) {
2019-12-31 13:02:21 +02:00
m_operable = false ;
2020-03-01 21:45:39 +02:00
klog ( ) < < " DMI Decoder is disabled. Cannot find SMBIOS tables. " ;
2020-02-24 13:59:48 +02:00
return ;
2019-12-31 13:02:21 +02:00
}
2020-02-24 13:59:48 +02:00
m_operable = true ;
2020-03-01 21:45:39 +02:00
klog ( ) < < " DMI Decoder is enabled " ;
2020-02-24 13:59:48 +02:00
if ( ! m_entry64bit_point . is_null ( ) ) {
set_64_bit_entry_initialization_values ( m_entry64bit_point ) ;
} else if ( ! m_entry32bit_point . is_null ( ) ) {
set_32_bit_entry_initialization_values ( m_entry32bit_point ) ;
}
2020-03-06 15:00:44 +01:00
klog ( ) < < " DMIDecoder: Data table @ " < < m_structure_table ;
2020-02-24 13:59:48 +02:00
enumerate_smbios_tables ( ) ;
2019-12-31 13:02:21 +02:00
}
void DMIDecoder : : enumerate_smbios_tables ( )
{
2020-01-09 23:33:36 +02:00
2019-12-31 13:02:21 +02:00
u32 table_length = m_table_length ;
2020-02-24 13:59:48 +02:00
auto p_table = m_structure_table ;
2019-12-31 13:02:21 +02:00
2020-02-24 13:59:48 +02:00
auto region = MM . allocate_kernel_region ( p_table . page_base ( ) , PAGE_ROUND_UP ( table_length ) , " DMI Decoder Enumerating SMBIOS " , Region : : Access : : Read , false , false ) ;
2020-03-08 18:29:48 +02:00
volatile SMBIOS : : TableHeader * v_table_ptr = ( SMBIOS : : TableHeader * ) region - > vaddr ( ) . offset ( p_table . offset_in_page ( ) ) . as_ptr ( ) ;
2019-12-31 13:02:21 +02:00
2020-01-09 23:33:36 +02:00
# ifdef SMBIOS_DEBUG
2020-02-24 14:33:14 +02:00
dbg ( ) < < " DMIDecoder: Total Table length " < < m_table_length ;
2020-01-09 23:33:36 +02:00
# endif
2019-12-31 13:02:21 +02:00
u32 structures_count = 0 ;
while ( table_length > 0 ) {
# ifdef SMBIOS_DEBUG
2020-02-24 14:33:14 +02:00
dbg ( ) < < " DMIDecoder: Examining table @ P " < < ( void * ) p_table . as_ptr ( ) < < " V " < < const_cast < SMBIOS : : TableHeader * > ( v_table_ptr ) ;
2019-12-31 13:02:21 +02:00
# endif
structures_count + + ;
2020-01-20 13:06:14 +01:00
if ( v_table_ptr - > type = = ( u8 ) SMBIOS : : TableType : : EndOfTable ) {
2020-03-01 21:45:39 +02:00
klog ( ) < < " DMIDecoder: Detected table with type 127, End of SMBIOS data. " ;
2019-12-31 13:02:21 +02:00
break ;
}
2020-03-01 21:45:39 +02:00
klog ( ) < < " DMIDecoder: Detected table with type " < < v_table_ptr - > type ;
2020-02-24 13:59:48 +02:00
m_smbios_tables . append ( p_table ) ;
2020-01-09 23:33:36 +02:00
table_length - = v_table_ptr - > length ;
2020-02-24 13:59:48 +02:00
size_t table_size = get_table_size ( p_table ) ;
p_table = p_table . offset ( table_size ) ;
2020-03-08 10:36:51 +01:00
v_table_ptr = ( SMBIOS : : TableHeader * ) ( ( FlatPtr ) v_table_ptr + table_size ) ;
2019-12-31 13:02:21 +02:00
# ifdef SMBIOS_DEBUG
2020-02-24 14:33:14 +02:00
dbg ( ) < < " DMIDecoder: Next table @ P 0x " < < p_table . get ( ) ;
2019-12-31 13:02:21 +02:00
# endif
}
m_structures_count = structures_count ;
}
2020-02-24 13:59:48 +02:00
size_t DMIDecoder : : get_table_size ( PhysicalAddress table )
2019-12-31 13:02:21 +02:00
{
2020-02-24 13:59:48 +02:00
auto region = MM . allocate_kernel_region ( table . page_base ( ) , PAGE_ROUND_UP ( m_table_length ) , " DMI Decoder Determining table size " , Region : : Access : : Read , false , false ) ;
2020-03-08 18:29:48 +02:00
auto & table_v_ptr = ( SMBIOS : : TableHeader & ) * region - > vaddr ( ) . offset ( table . offset_in_page ( ) ) . as_ptr ( ) ;
2019-12-31 13:02:21 +02:00
# ifdef SMBIOS_DEBUG
2020-02-24 14:33:14 +02:00
dbg ( ) < < " DMIDecoder: table legnth - " < < table_v_ptr . length ;
2019-12-31 13:02:21 +02:00
# endif
2020-01-21 04:35:57 +02:00
const char * strtab = ( char * ) & table_v_ptr + table_v_ptr . length ;
2019-12-31 13:02:21 +02:00
size_t index = 1 ;
while ( strtab [ index - 1 ] ! = ' \0 ' | | strtab [ index ] ! = ' \0 ' ) {
if ( index > m_table_length ) {
ASSERT_NOT_REACHED ( ) ; // FIXME: Instead of halting, find a better solution (Hint: use m_operable to disallow further use of DMIDecoder)
}
index + + ;
}
# ifdef SMBIOS_DEBUG
2020-02-24 14:33:14 +02:00
dbg ( ) < < " DMIDecoder: table size - " < < ( table_v_ptr . length + index + 1 ) ;
2019-12-31 13:02:21 +02:00
# endif
2020-01-21 04:35:57 +02:00
return table_v_ptr . length + index + 1 ;
2019-12-31 13:02:21 +02:00
}
2020-02-24 13:59:48 +02:00
PhysicalAddress DMIDecoder : : get_next_physical_table ( PhysicalAddress p_table )
2019-12-31 13:02:21 +02:00
{
2020-02-24 13:59:48 +02:00
return p_table . offset ( get_table_size ( p_table ) ) ;
2019-12-31 13:02:21 +02:00
}
2020-02-24 13:59:48 +02:00
PhysicalAddress DMIDecoder : : get_smbios_physical_table_by_handle ( u16 handle )
2019-12-31 13:02:21 +02:00
{
2020-02-24 13:59:48 +02:00
for ( auto table : m_smbios_tables ) {
if ( table . is_null ( ) )
2019-12-31 13:02:21 +02:00
continue ;
2020-02-24 13:59:48 +02:00
auto region = MM . allocate_kernel_region ( table . page_base ( ) , PAGE_SIZE * 2 , " DMI Decoder Finding Table " , Region : : Access : : Read , false , false ) ;
2020-03-08 18:29:48 +02:00
SMBIOS : : TableHeader * table_v_ptr = ( SMBIOS : : TableHeader * ) region - > vaddr ( ) . offset ( table . offset_in_page ( ) ) . as_ptr ( ) ;
2020-01-09 23:33:36 +02:00
2019-12-31 13:02:21 +02:00
if ( table_v_ptr - > handle = = handle ) {
return table ;
}
}
2020-02-24 13:59:48 +02:00
return { } ;
2019-12-31 13:02:21 +02:00
}
2020-02-24 13:59:48 +02:00
PhysicalAddress DMIDecoder : : get_smbios_physical_table_by_type ( u8 table_type )
2019-12-31 13:02:21 +02:00
{
2020-02-24 13:59:48 +02:00
for ( auto table : m_smbios_tables ) {
if ( table . is_null ( ) )
2019-12-31 13:02:21 +02:00
continue ;
2020-02-24 13:59:48 +02:00
auto region = MM . allocate_kernel_region ( table . page_base ( ) , PAGE_ROUND_UP ( PAGE_SIZE * 2 ) , " DMI Decoder Finding Table " , Region : : Access : : Read , false , false ) ;
2020-03-08 18:29:48 +02:00
SMBIOS : : TableHeader * table_v_ptr = ( SMBIOS : : TableHeader * ) region - > vaddr ( ) . offset ( table . offset_in_page ( ) ) . as_ptr ( ) ;
2019-12-31 13:02:21 +02:00
if ( table_v_ptr - > type = = table_type ) {
return table ;
}
}
2020-02-24 13:59:48 +02:00
return { } ;
2019-12-31 13:02:21 +02:00
}
DMIDecoder : : DMIDecoder ( bool trusted )
: m_entry32bit_point ( find_entry32bit_point ( ) )
, m_entry64bit_point ( find_entry64bit_point ( ) )
2020-02-24 13:59:48 +02:00
, m_structure_table ( PhysicalAddress ( ) )
2019-12-31 13:02:21 +02:00
, m_untrusted ( ! trusted )
{
if ( ! trusted ) {
2020-03-01 21:45:39 +02:00
klog ( ) < < " DMI Decoder initialized as untrusted due to user request. " ;
2019-12-31 13:02:21 +02:00
}
initialize_parser ( ) ;
}
2020-02-24 13:59:48 +02:00
PhysicalAddress DMIDecoder : : find_entry64bit_point ( )
2019-12-31 13:02:21 +02:00
{
PhysicalAddress paddr = PhysicalAddress ( SMBIOS_BASE_SEARCH_ADDR ) ;
2020-01-09 23:33:36 +02:00
auto region = MM . allocate_kernel_region ( paddr , PAGE_ROUND_UP ( SMBIOS_SEARCH_AREA_SIZE ) , " DMI Decoder Entry Point 64 bit Finding " , Region : : Access : : Read , false , false ) ;
2019-12-31 13:02:21 +02:00
char * tested_physical_ptr = ( char * ) paddr . get ( ) ;
for ( char * entry_str = ( char * ) ( region - > vaddr ( ) . get ( ) ) ; entry_str < ( char * ) ( region - > vaddr ( ) . get ( ) + ( SMBIOS_SEARCH_AREA_SIZE ) ) ; entry_str + = 16 ) {
# ifdef SMBIOS_DEBUG
2020-02-24 14:33:14 +02:00
dbg ( ) < < " DMI Decoder: Looking for 64 bit Entry point @ V " < < ( void * ) entry_str < < " P " < < ( void * ) tested_physical_ptr ;
2019-12-31 13:02:21 +02:00
# endif
if ( ! strncmp ( " _SM3_ " , entry_str , strlen ( " _SM3_ " ) ) )
2020-03-08 10:36:51 +01:00
return PhysicalAddress ( ( FlatPtr ) tested_physical_ptr ) ;
2019-12-31 13:02:21 +02:00
tested_physical_ptr + = 16 ;
}
2020-02-24 13:59:48 +02:00
return { } ;
2019-12-31 13:02:21 +02:00
}
2020-02-24 13:59:48 +02:00
PhysicalAddress DMIDecoder : : find_entry32bit_point ( )
2019-12-31 13:02:21 +02:00
{
PhysicalAddress paddr = PhysicalAddress ( SMBIOS_BASE_SEARCH_ADDR ) ;
2020-01-09 23:33:36 +02:00
auto region = MM . allocate_kernel_region ( paddr , PAGE_ROUND_UP ( SMBIOS_SEARCH_AREA_SIZE ) , " DMI Decoder Entry Point 32 bit Finding " , Region : : Access : : Read , false , false ) ;
2019-12-31 13:02:21 +02:00
char * tested_physical_ptr = ( char * ) paddr . get ( ) ;
for ( char * entry_str = ( char * ) ( region - > vaddr ( ) . get ( ) ) ; entry_str < ( char * ) ( region - > vaddr ( ) . get ( ) + ( SMBIOS_SEARCH_AREA_SIZE ) ) ; entry_str + = 16 ) {
# ifdef SMBIOS_DEBUG
2020-02-24 14:33:14 +02:00
dbg ( ) < < " DMI Decoder: Looking for 32 bit Entry point @ V " < < ( void * ) entry_str < < " P " < < ( void * ) tested_physical_ptr ;
2019-12-31 13:02:21 +02:00
# endif
if ( ! strncmp ( " _SM_ " , entry_str , strlen ( " _SM_ " ) ) )
2020-03-08 10:36:51 +01:00
return PhysicalAddress ( ( FlatPtr ) tested_physical_ptr ) ;
2019-12-31 13:02:21 +02:00
tested_physical_ptr + = 16 ;
}
2020-02-24 13:59:48 +02:00
return { } ;
2019-12-31 13:02:21 +02:00
}
Vector < SMBIOS : : PhysicalMemoryArray * > & DMIDecoder : : get_physical_memory_areas ( )
{
// FIXME: Implement it...
2020-03-01 21:45:39 +02:00
klog ( ) < < " DMIDecoder::get_physical_memory_areas() is not implemented. " ;
2019-12-31 13:02:21 +02:00
ASSERT_NOT_REACHED ( ) ;
}
bool DMIDecoder : : is_reliable ( )
{
return ! m_untrusted ;
}
u64 DMIDecoder : : get_bios_characteristics ( )
{
// FIXME: Make sure we have some mapping here so we don't rely on existing identity mapping...
2020-02-24 13:59:48 +02:00
ASSERT_NOT_REACHED ( ) ;
2019-12-31 13:02:21 +02:00
ASSERT ( m_operable = = true ) ;
2020-02-24 13:59:48 +02:00
auto * bios_info = ( SMBIOS : : BIOSInfo * ) get_smbios_physical_table_by_type ( 0 ) . as_ptr ( ) ;
2019-12-31 13:02:21 +02:00
ASSERT ( bios_info ! = nullptr ) ;
2020-01-21 04:35:57 +02:00
2020-03-08 10:36:51 +01:00
klog ( ) < < " DMIDecoder: BIOS info @ " < < PhysicalAddress ( ( FlatPtr ) bios_info ) ;
2019-12-31 13:02:21 +02:00
return bios_info - > bios_characteristics ;
}
2020-02-24 13:59:48 +02:00
char * DMIDecoder : : get_smbios_string ( PhysicalAddress , u8 )
2019-12-31 13:02:21 +02:00
{
// FIXME: Implement it...
// FIXME: Make sure we have some mapping here so we don't rely on existing identity mapping...
2020-03-01 21:45:39 +02:00
klog ( ) < < " DMIDecoder::get_smbios_string() is not implemented. " ;
2019-12-31 13:02:21 +02:00
ASSERT_NOT_REACHED ( ) ;
return nullptr ;
}
2020-02-16 01:27:42 +01:00
}