@ -181,51 +181,24 @@ static void acpi_ghes_build_append_mem_cper(GArray *table,
build_append_int_noprefix ( table , 0 , 7 ) ;
}
static int acpi_ghes_record_mem_error ( uint64_t error_block_address ,
uint64_t error_physical_addr )
static void
ghes_gen_err_data_uncorrectable_recoverable ( GArray * block ,
const uint8_t * section_type ,
int data_length )
{
GArray * block ;
/* Memory Error Section Type */
const uint8_t uefi_cper_mem_sec [ ] =
UUID_LE ( 0xA5BC1114 , 0x6F64 , 0x4EDE , 0xB8 , 0x63 , 0x3E , 0x83 , \
0xED , 0x7C , 0x83 , 0xB1 ) ;
/* invalid fru id: ACPI 4.0: 17.3.2.6.1 Generic Error Data,
* Table 17 - 13 Generic Error Data Entry
*/
QemuUUID fru_id = { } ;
uint32_t data_length ;
block = g_array_new ( false , true /* clear */ , 1 ) ;
/* This is the length if adding a new generic error data entry*/
data_length = ACPI_GHES_DATA_LENGTH + ACPI_GHES_MEM_CPER_LENGTH ;
/*
* It should not run out of the preallocated memory if adding a new generic
* error data entry
*/
assert ( ( data_length + ACPI_GHES_GESB_SIZE ) < =
ACPI_GHES_MAX_RAW_DATA_LENGTH ) ;
/* Build the new generic error status block header */
acpi_ghes_generic_error_status ( block , ACPI_GEBS_UNCORRECTABLE ,
0 , 0 , data_length , ACPI_CPER_SEV_RECOVERABLE ) ;
/* Build this new generic error data entry header */
acpi_ghes_generic_error_data ( block , uefi_cper_mem_sec ,
acpi_ghes_generic_error_data ( block , section_type ,
ACPI_CPER_SEV_RECOVERABLE , 0 , 0 ,
ACPI_GHES_MEM_CPER_LENGTH , fru_id , 0 ) ;
/* Build the memory section CPER for above new generic error data entry */
acpi_ghes_build_append_mem_cper ( block , error_physical_addr ) ;
/* Write the generic error data entry into guest memory */
cpu_physical_memory_write ( error_block_address , block - > data , block - > len ) ;
g_array_free ( block , true ) ;
return 0 ;
}
/*
@ -383,15 +356,18 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s,
ags - > present = true ;
}
int acpi_ghes_record_errors ( uint16_t source_id , uint64_t physical_address )
void ghes_record_cper_errors ( const void * cper , size_t len ,
uint16_t source_id , Error * * errp )
{
uint64_t error_block_addr , read_ack_register_addr , read_ack_register = 0 ;
uint64_t start_addr ;
bool ret = - 1 ;
AcpiGedState * acpi_ged_state ;
AcpiGhesState * ags ;
assert ( source_id < ACPI_GHES_ERROR_SOURCE_COUNT ) ;
if ( len > ACPI_GHES_MAX_RAW_DATA_LENGTH ) {
error_setg ( errp , " GHES CPER record is too big: %zd " , len ) ;
return ;
}
acpi_ged_state = ACPI_GED ( object_resolve_path_type ( " " , TYPE_ACPI_GED ,
NULL ) ) ;
@ -406,6 +382,10 @@ int acpi_ghes_record_errors(uint16_t source_id, uint64_t physical_address)
sizeof ( error_block_addr ) ) ;
error_block_addr = le64_to_cpu ( error_block_addr ) ;
if ( ! error_block_addr ) {
error_setg ( errp , " can not find Generic Error Status Block " ) ;
return ;
}
read_ack_register_addr = start_addr +
ACPI_GHES_ERROR_SOURCE_COUNT * sizeof ( uint64_t ) ;
@ -415,24 +395,62 @@ int acpi_ghes_record_errors(uint16_t source_id, uint64_t physical_address)
/* zero means OSPM does not acknowledge the error */
if ( ! read_ack_register ) {
error_report ( " OSPM does not acknowledge previous error, "
" so can not record CPER for current error anymore " ) ;
} else if ( error_block_addr ) {
read_ack_register = cpu_to_le64 ( 0 ) ;
/*
* Clear the Read Ack Register , OSPM will write it to 1 when
* it acknowledges this error .
*/
cpu_physical_memory_write ( read_ack_register_addr ,
& read_ack_register , sizeof ( uint64_t ) ) ;
error_setg ( errp ,
" OSPM does not acknowledge previous error, "
" so can not record CPER for current error anymore " ) ;
return ;
}
ret = acpi_ghes_record_mem_error ( error_block_addr ,
physical_address ) ;
} else {
error_report ( " can not find Generic Error Status Block " ) ;
read_ack_register = cpu_to_le64 ( 0 ) ;
/*
* Clear the Read Ack Register , OSPM will write 1 to this register when
* it acknowledges the error .
*/
cpu_physical_memory_write ( read_ack_register_addr ,
& read_ack_register , sizeof ( uint64_t ) ) ;
/* Write the generic error data entry into guest memory */
cpu_physical_memory_write ( error_block_addr , cper , len ) ;
return ;
}
int acpi_ghes_record_errors ( uint16_t source_id , uint64_t physical_address )
{
/* Memory Error Section Type */
const uint8_t guid [ ] =
UUID_LE ( 0xA5BC1114 , 0x6F64 , 0x4EDE , 0xB8 , 0x63 , 0x3E , 0x83 , \
0xED , 0x7C , 0x83 , 0xB1 ) ;
Error * errp = NULL ;
int data_length ;
GArray * block ;
block = g_array_new ( false , true /* clear */ , 1 ) ;
data_length = ACPI_GHES_DATA_LENGTH + ACPI_GHES_MEM_CPER_LENGTH ;
/*
* It should not run out of the preallocated memory if adding a new generic
* error data entry
*/
assert ( ( data_length + ACPI_GHES_GESB_SIZE ) < =
ACPI_GHES_MAX_RAW_DATA_LENGTH ) ;
ghes_gen_err_data_uncorrectable_recoverable ( block , guid , data_length ) ;
/* Build the memory section CPER for above new generic error data entry */
acpi_ghes_build_append_mem_cper ( block , physical_address ) ;
/* Report the error */
ghes_record_cper_errors ( block - > data , block - > len , source_id , & errp ) ;
g_array_free ( block , true ) ;
if ( errp ) {
error_report_err ( errp ) ;
return - 1 ;
}
return ret ;
return 0 ;
}
bool acpi_ghes_present ( void )