mirror of
https://github.com/86Box/bios-tools.git
synced 2026-02-26 14:03:17 -07:00
Sort out the Intel AMI/Phoenix mess
This commit is contained in:
@@ -333,7 +333,6 @@ class AMIAnalyzer(Analyzer):
|
|||||||
self._check_pattern = re.compile(b'''American Megatrends Inc|AMIBIOSC| Access Methods Inc\\.|AMI- ([0-9]{2}/[0-9]{2}/[0-9]{2}) (?:IBM is a TM of IBM|[\\x00-\\xFF]{2} AMI-[^-]+-BIOS )''')
|
self._check_pattern = re.compile(b'''American Megatrends Inc|AMIBIOSC| Access Methods Inc\\.|AMI- ([0-9]{2}/[0-9]{2}/[0-9]{2}) (?:IBM is a TM of IBM|[\\x00-\\xFF]{2} AMI-[^-]+-BIOS )''')
|
||||||
self._date_pattern = re.compile(b'''([0-9]{2}/[0-9]{2}/[0-9]{2})[^0-9]''')
|
self._date_pattern = re.compile(b'''([0-9]{2}/[0-9]{2}/[0-9]{2})[^0-9]''')
|
||||||
self._uefi_csm_pattern = re.compile('''63-0100-000001-00101111-[0-9]{6}-Chipset-0AAAA000$''')
|
self._uefi_csm_pattern = re.compile('''63-0100-000001-00101111-[0-9]{6}-Chipset-0AAAA000$''')
|
||||||
self._intel_86_pattern = re.compile('''[0-9A-Z]{8}\\.86[0-9A-Z]\\.[0-9A-Z]{3,4}\\.[0-9A-Z]{1,4}\\.[0-9]{10}$''')
|
|
||||||
# The "All Rights Reserved" is important to not catch the same header on other files.
|
# The "All Rights Reserved" is important to not catch the same header on other files.
|
||||||
# "All<Rights Reserved" (Tatung TCS-9850 9600x9, corrupted during production?)
|
# "All<Rights Reserved" (Tatung TCS-9850 9600x9, corrupted during production?)
|
||||||
# AMIBIOS 6+ version corner cases:
|
# AMIBIOS 6+ version corner cases:
|
||||||
@@ -370,23 +369,15 @@ class AMIAnalyzer(Analyzer):
|
|||||||
'WinBIOS': re.compile(b''' Wait----''')
|
'WinBIOS': re.compile(b''' Wait----''')
|
||||||
}
|
}
|
||||||
|
|
||||||
self.register_check_list([
|
|
||||||
(self._signon_intel, RegexChecker),
|
|
||||||
])
|
|
||||||
|
|
||||||
def can_handle(self, file_path, file_data, header_data):
|
def can_handle(self, file_path, file_data, header_data):
|
||||||
check_match = self._check_pattern.search(file_data)
|
check_match = self._check_pattern.search(file_data)
|
||||||
if not check_match:
|
if not check_match:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Some Intel BIOSes may fail to decompress, in which case, we have to
|
# Extract Intel data in a preliminary manner in case extraction failed.
|
||||||
# rely on the header version data to get the Intel version sign-on.
|
is_intel = AMIIntelAnalyzer.can_handle(self, file_path, file_data, header_data)
|
||||||
if header_data:
|
if is_intel:
|
||||||
is_intel = AMIIntelAnalyzer.can_handle(self, file_path, file_data, header_data)
|
self.debug_print('Intel data found')
|
||||||
if is_intel:
|
|
||||||
self.debug_print('Intel data found')
|
|
||||||
else:
|
|
||||||
is_intel = False
|
|
||||||
|
|
||||||
# Check post-Color identification block.
|
# Check post-Color identification block.
|
||||||
match = self._id_block_pattern.search(file_data)
|
match = self._id_block_pattern.search(file_data)
|
||||||
@@ -580,19 +571,6 @@ class AMIAnalyzer(Analyzer):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _signon_intel(self, line, match):
|
|
||||||
'''^(?:(?:BIOS (?:Release|Version) )?([0-9]\\.[0-9]{2}\\.[0-9]{2}\\.[A-Z][0-9A-Z]{1,})|(?:\\$IBIOSI\\$)?([0-9A-Z]{8}\\.([0-9A-Z]{3})\\.[0-9A-Z]{3,4}\\.[0-9A-Z]{1,4}\\.[0-9]{10}|(?:\\.[0-9]{4}){3}))'''
|
|
||||||
|
|
||||||
# If this is Intel's second AMI run, check if this is not a generic
|
|
||||||
# (86x) version string overwriting an OEM version string.
|
|
||||||
oem = match.group(3)
|
|
||||||
intel_version = match.group(1) or match.group(2)
|
|
||||||
if (not oem or oem[:2] != '86' or not self._intel_86_pattern.match(self.signon)) and intel_version not in self.signon:
|
|
||||||
# Extract the version string as a sign-on.
|
|
||||||
self.signon = intel_version
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class AMIDellAnalyzer(AMIAnalyzer):
|
class AMIDellAnalyzer(AMIAnalyzer):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -685,47 +663,57 @@ class AMIIntelAnalyzer(Analyzer):
|
|||||||
_ami_pattern = re.compile(b'''AMIBIOS''')
|
_ami_pattern = re.compile(b'''AMIBIOS''')
|
||||||
_ami_version_pattern = re.compile(b'''AMIBIOSC(0[1-9][0-9]{2})''')
|
_ami_version_pattern = re.compile(b'''AMIBIOSC(0[1-9][0-9]{2})''')
|
||||||
_phoenix_pattern = re.compile(b'''PhoenixBIOS(?:\\(TM\\))? ''')
|
_phoenix_pattern = re.compile(b'''PhoenixBIOS(?:\\(TM\\))? ''')
|
||||||
|
_version_pattern = re.compile(b'''(?:BIOS (?:Release|Version) )?([0-9]\\.[0-9]{2}\\.[0-9]{2}\\.[A-Z][0-9A-Z]{1,})|(?:\\$IBIOSI\\$)?([0-9A-Z]{8}\\.([0-9A-Z]{3})\\.[0-9A-Z]{3,4}\\.[0-9A-Z]{1,4}\\.[0-9]{10}|(?:\\.[0-9]{4}){3})''')
|
||||||
|
_86_pattern = re.compile('''[0-9A-Z]{8}\\.86[0-9A-Z]\\.[0-9A-Z]{3,4}\\.[0-9A-Z]{1,4}\\.[0-9]{10}$''')
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__('Intel', *args, **kwargs)
|
super().__init__('Intel', *args, **kwargs)
|
||||||
|
|
||||||
def can_handle(self, file_path, file_data, header_data):
|
def can_handle(self, file_path, file_data, header_data):
|
||||||
# Handle Intel AMI BIOSes that could not be decompressed.
|
# Handle header on Intel AMI (and sometimes Phoenix) BIOSes that could not be decompressed.
|
||||||
|
ret = header_data and header_data[90:95] == b'FLASH' and header_data[112:126] != b'User Data Area'
|
||||||
# Stop if there is no header data or if this file is just the header data.
|
if ret:
|
||||||
# Note that headers with a 512-byte offset are converted by the extractor.
|
|
||||||
if not header_data:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Stop if this is an User Data Area file.
|
|
||||||
if header_data[112:126] == b'User Data Area':
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Extract the Intel version from the flash header.
|
|
||||||
if header_data[90:95] == b'FLASH':
|
|
||||||
# Start by assuming this is an unknown BIOS.
|
# Start by assuming this is an unknown BIOS.
|
||||||
if self.vendor_id == 'Intel':
|
if self.vendor_id == 'Intel':
|
||||||
self.vendor = 'Intel'
|
self.vendor = 'Intel'
|
||||||
self.version = 'Unknown Intel'
|
self.version = '?'
|
||||||
|
|
||||||
# Extract AMI version from compressed data.
|
# Apply the version string as a sign-on.
|
||||||
# (0632 fork which bios_extract can't handle)
|
self.signon = util.read_string(header_data[112:])
|
||||||
|
else:
|
||||||
|
# No header found, attempt to manually extract version string from data.
|
||||||
|
for match in AMIIntelAnalyzer._version_pattern.finditer(file_data):
|
||||||
|
self.debug_print('Raw Intel version:', match.group(0))
|
||||||
|
|
||||||
|
# If this is Intel's second AMI run, check if this is not a generic
|
||||||
|
# (86x) version string overwriting an OEM-customized version string.
|
||||||
|
oem = util.read_string(match.group(3) or b'')
|
||||||
|
intel_version = util.read_string(match.group(1) or match.group(2))
|
||||||
|
if (not oem or oem[:2] != '86' or not AMIIntelAnalyzer._86_pattern.match(self.signon)) and intel_version not in self.signon:
|
||||||
|
# Extract the version string as a sign-on.
|
||||||
|
if self.vendor_id == 'Intel':
|
||||||
|
self.version = '?'
|
||||||
|
self.signon = intel_version
|
||||||
|
ret = True
|
||||||
|
|
||||||
|
if ret:
|
||||||
|
# Extract AMI version from compressed data. (0632 fork which bios_extract can't handle)
|
||||||
match = AMIIntelAnalyzer._ami_pattern.search(file_data)
|
match = AMIIntelAnalyzer._ami_pattern.search(file_data)
|
||||||
if match:
|
if match:
|
||||||
match = AMIIntelAnalyzer._ami_version_pattern.search(file_data[match.start(0):])
|
match = AMIIntelAnalyzer._ami_version_pattern.search(file_data[match.start(0):])
|
||||||
if match:
|
if match:
|
||||||
if self.vendor_id == 'Intel':
|
if self.vendor_id == 'Intel':
|
||||||
self.vendor = 'AMI'
|
self.vendor = 'AMI'
|
||||||
|
elif self.vendor != 'AMI':
|
||||||
|
return False
|
||||||
self.version = match.group(1).decode('cp437', 'ignore') + '00'
|
self.version = match.group(1).decode('cp437', 'ignore') + '00'
|
||||||
elif self.vendor_id == 'Intel' and AMIIntelAnalyzer._phoenix_pattern.search(file_data):
|
elif AMIIntelAnalyzer._phoenix_pattern.search(file_data):
|
||||||
self.vendor = 'Phoenix'
|
if self.vendor_id == 'Intel':
|
||||||
|
self.vendor = 'Phoenix'
|
||||||
|
elif self.vendor_id != 'Phoenix':
|
||||||
|
return False
|
||||||
|
|
||||||
# Apply the version as a sign-on.
|
return ret
|
||||||
self.signon = util.read_string(header_data[112:])
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class AMIUEFIAnalyzer(AMIAnalyzer):
|
class AMIUEFIAnalyzer(AMIAnalyzer):
|
||||||
@@ -1887,7 +1875,6 @@ class PhoenixAnalyzer(Analyzer):
|
|||||||
self._rombios_signon_dec_pattern = re.compile(b'''Copyright \\(C\\) [0-9]{4} Digital Equipment Corporation''')
|
self._rombios_signon_dec_pattern = re.compile(b'''Copyright \\(C\\) [0-9]{4} Digital Equipment Corporation''')
|
||||||
self._segment_pattern = re.compile('''segment_([0-9A-F]{4})\\.rom$''')
|
self._segment_pattern = re.compile('''segment_([0-9A-F]{4})\\.rom$''')
|
||||||
self._strings_pattern = re.compile('''strings_[0-9A-F_]+\\.rom$''')
|
self._strings_pattern = re.compile('''strings_[0-9A-F_]+\\.rom$''')
|
||||||
self._intel_86_pattern = re.compile('''[0-9A-Z]{8}\\.86[0-9A-Z]\\.[0-9A-Z]{3,4}\\.[0-9A-Z]{1,4}\\.[0-9]{10}$''')
|
|
||||||
self._date_pattern = re.compile(b'''((?:0[1-9]|1[0-2])/(?:0[1-9]|[12][0-9]|3[01])/[0-9]{2}|(?:0{2}[1-9]{2}|1{2}[0-2]{2})/(?:0{2}[1-9]{2}|[12]{2}[0-9]{2}|3{2}[01]{2})/[0-9]{4})[^0-9]''')
|
self._date_pattern = re.compile(b'''((?:0[1-9]|1[0-2])/(?:0[1-9]|[12][0-9]|3[01])/[0-9]{2}|(?:0{2}[1-9]{2}|1{2}[0-2]{2})/(?:0{2}[1-9]{2}|[12]{2}[0-9]{2}|3{2}[01]{2})/[0-9]{4})[^0-9]''')
|
||||||
|
|
||||||
# Reverse engineered from Phoenix BIOS Editor Pro.
|
# Reverse engineered from Phoenix BIOS Editor Pro.
|
||||||
@@ -2489,16 +2476,15 @@ class PhoenixAnalyzer(Analyzer):
|
|||||||
self._regtable_entries[0] = self._regtable_entries[1]
|
self._regtable_entries[0] = self._regtable_entries[1]
|
||||||
|
|
||||||
self.register_check_list([
|
self.register_check_list([
|
||||||
((self._signon_nec_precheck, self._signon_nec), AlwaysRunChecker),
|
((self._signon_nec_precheck, self._signon_nec), AlwaysRunChecker),
|
||||||
(self._version_sct, RegexChecker),
|
(self._version_sct, RegexChecker),
|
||||||
(self._version_sct_preboot, SubstringChecker, SUBSTRING_FULL_STRING | SUBSTRING_CASE_SENSITIVE),
|
(self._version_sct_preboot, SubstringChecker, SUBSTRING_FULL_STRING | SUBSTRING_CASE_SENSITIVE),
|
||||||
(self._version_tandy, SubstringChecker, SUBSTRING_FULL_STRING | SUBSTRING_CASE_SENSITIVE),
|
(self._version_tandy, SubstringChecker, SUBSTRING_FULL_STRING | SUBSTRING_CASE_SENSITIVE),
|
||||||
(self._signon_ast, SubstringChecker, SUBSTRING_BEGINNING | SUBSTRING_CASE_SENSITIVE),
|
(self._signon_ast, SubstringChecker, SUBSTRING_BEGINNING | SUBSTRING_CASE_SENSITIVE),
|
||||||
(self._signon_commodore, RegexChecker),
|
(self._signon_commodore, RegexChecker),
|
||||||
(self._signon_hp, RegexChecker),
|
(self._signon_hp, RegexChecker),
|
||||||
(self._signon_intel, RegexChecker),
|
(self._signon_nec_trigger, RegexChecker),
|
||||||
(self._signon_nec_trigger, RegexChecker),
|
(self._signon_tandy, RegexChecker),
|
||||||
(self._signon_tandy, RegexChecker),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
@@ -2539,6 +2525,11 @@ class PhoenixAnalyzer(Analyzer):
|
|||||||
if self._ignore_pattern.search(file_data):
|
if self._ignore_pattern.search(file_data):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Extract Intel data in a preliminary manner in case extraction failed.
|
||||||
|
is_intel = AMIIntelAnalyzer.can_handle(self, file_path, file_data, header_data)
|
||||||
|
if is_intel:
|
||||||
|
self.debug_print('Intel data found')
|
||||||
|
|
||||||
# Skip BCP parsing if this is not 4.0x or newer.
|
# Skip BCP parsing if this is not 4.0x or newer.
|
||||||
raw_data = b''
|
raw_data = b''
|
||||||
bios_maj = bios_min = code_segment = None
|
bios_maj = bios_min = code_segment = None
|
||||||
@@ -2857,7 +2848,7 @@ class PhoenixAnalyzer(Analyzer):
|
|||||||
self.metadata.append(('ID', version_string))
|
self.metadata.append(('ID', version_string))
|
||||||
self.debug_print('Raw ROM BIOS version:', repr(version_string))
|
self.debug_print('Raw ROM BIOS version:', repr(version_string))
|
||||||
else:
|
else:
|
||||||
self.debug_print('No version found!', file_path)
|
self.debug_print('No version found!')
|
||||||
|
|
||||||
# Save post-version sign-on to be restored later.
|
# Save post-version sign-on to be restored later.
|
||||||
post_version = self.signon
|
post_version = self.signon
|
||||||
@@ -3145,22 +3136,6 @@ class PhoenixAnalyzer(Analyzer):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _signon_intel(self, line, match):
|
|
||||||
'''^(?:\\$IBIOSI\\$)?([0-9]\\.[0-9]{2}\\.[0-9]{2}\\.[0-9A-Z]{2,}|[0-9A-Z]{8}\\.([0-9A-Z]{3})\\.[0-9A-Z]{3,4}\\.[0-9A-Z]{1,4}\\.([0-9]{10}))'''
|
|
||||||
|
|
||||||
# This is an Intel BIOS.
|
|
||||||
if not self.version:
|
|
||||||
self.version = 'Intel'
|
|
||||||
|
|
||||||
# If this is Intel's second Phoenix run, check if this is not a generic
|
|
||||||
# (86x) version string overwriting an OEM version string.
|
|
||||||
oem = match.group(2)
|
|
||||||
if not oem or oem[:2] != '86' or not self._intel_86_pattern.match(self.signon):
|
|
||||||
# Extract the version string as a sign-on.
|
|
||||||
self.signon = match.group(1)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _signon_nec_trigger(self, line, match):
|
def _signon_nec_trigger(self, line, match):
|
||||||
'''^..(NEC Corporation)$'''
|
'''^..(NEC Corporation)$'''
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user