You've already forked open-source-firmware-validation
mirror of
https://github.com/Dasharo/open-source-firmware-validation.git
synced 2026-06-13 10:16:18 -07:00
557c63b32b
Signed-off-by: Filip Gołaś <filip.golas@3mdeb.com>
365 lines
16 KiB
Plaintext
365 lines
16 KiB
Plaintext
*** Settings ***
|
|
Resource ../keywords.robot
|
|
Resource custom_bootentries.robot
|
|
|
|
|
|
*** Keywords ***
|
|
Flash Via Internal Programmer With Args
|
|
[Documentation] Execute flashrom write operation on the given binary,
|
|
... using extra arguments.
|
|
[Arguments] ${fw_file_path} ${args} ${timeout}=5m
|
|
IF '${OPTIONS_LIB}' == 'options-lib_dcu'
|
|
# Then the platform configuration depends on the bootorder to stay the same.
|
|
# We must copy the current smmstore to the target binary in order to prevent
|
|
# it being overwritten.
|
|
VAR ${smm_file}= /tmp/smmstore.rom
|
|
VAR ${replaced_bootorder_file}= replaced_bootorder_coreboot.rom
|
|
${custom_bootname}= Get Custom Bootentry Name ${DEFAULT_BOOT_OS_ID}
|
|
@{custom_bootid}= Get Bootnums For Label ${custom_bootname}
|
|
Should Not Be Empty
|
|
... ${custom_bootid}
|
|
... Basic Platform Setup was not run, Custom DEFAULT_BOOT bootentry does not exist.
|
|
Execute Command In Terminal flashrom -p internal -r ${smm_file} --fmap -i FMAP -i SMMSTORE
|
|
END
|
|
# Always flash FD first in case the layout changes
|
|
${out_flash}= Execute Command In Terminal
|
|
... flashrom -p internal -c "${INTERNAL_PROGRAMMER_CHIPNAME}" -w ${fw_file_path} --ifd -i fd
|
|
... timeout=${timeout}
|
|
|
|
${out_flash}= Execute Command In Terminal
|
|
... flashrom -p internal -c "${INTERNAL_PROGRAMMER_CHIPNAME}" -w ${fw_file_path} ${args}
|
|
... timeout=${timeout}
|
|
IF "Warning: Chip content is identical to the requested image." in """${out_flash}"""
|
|
RETURN
|
|
END
|
|
Should Contain ${out_flash} VERIFIED
|
|
IF '${OPTIONS_LIB}' == 'options-lib_dcu'
|
|
# Then restore smmstore (UEFI variables)
|
|
${out_flash}= Execute Command In Terminal
|
|
... flashrom -p internal -c "${INTERNAL_PROGRAMMER_CHIPNAME}" -w ${smm_file} --fmap -i FMAP -i SMMSTORE
|
|
... timeout=${timeout}
|
|
END
|
|
|
|
Flash Via Internal Programmer
|
|
[Arguments] ${fw_file_path} @{regions}
|
|
${out_flashrom_probe}= Execute Command In Terminal flashrom -p internal
|
|
${read_only}= Run Keyword And Return Status
|
|
... Should Contain ${out_flashrom_probe} read-only
|
|
${filename}= Evaluate os.path.basename(r"${fw_file_path}")
|
|
Send File To DUT ${fw_file_path} /tmp/${filename}
|
|
# TODO: automatically check and seck locs - reuse keywords from this suite, but it does not exist it seems
|
|
IF ${read_only}
|
|
Fail Make sure that SPI locks are disabled prior flashing internally
|
|
END
|
|
|
|
# If no region is given, flash the whole binary
|
|
IF @{regions}
|
|
VAR ${args}= -N --ifd
|
|
FOR ${region} IN @{regions}
|
|
VAR ${args}= ${args} -i ${region}
|
|
END
|
|
ELSE
|
|
VAR ${args}= ${EMPTY}
|
|
END
|
|
Wait Until Keyword Succeeds 2x
|
|
... 1s
|
|
... Flash Via Internal Programmer With Args /tmp/${filename} ${args}
|
|
|
|
Check If RW SECTION B Is Present In A Firmware File
|
|
[Documentation] Parses ROM with cbfstool to check if A or A + B sections are there
|
|
[Arguments] ${fw_file_path}
|
|
${layout}= Execute Command In Terminal cbfstool ${fw_file_path} layout -w
|
|
${section_b_present}= Run Keyword And Return Status
|
|
... Should Contain ${layout} RW_SECTION_B
|
|
Should Contain ${layout} RW_SECTION_A msg=RW_SECTION_A is not present. Is the firmware image correct?
|
|
RETURN ${section_b_present}
|
|
|
|
Flash RW Sections Via Internal Programmer
|
|
[Documentation] Flash RW_SECTION_A and RW_SECTION_B (if possible) region
|
|
... of flash using internal programmer. Requires that vboot-enabled
|
|
... firmware is already flashed.
|
|
[Arguments] ${fw_file_path}
|
|
${section_b_present}= Check If RW SECTION B Is Present In A Firmware File ${fw_file_path}
|
|
IF ${section_b_present}
|
|
Flash Via Internal Programmer With Args ${fw_file_path} -N --fmap -i RW_SECTION_A -i RW_SECTION_B
|
|
ELSE
|
|
Flash Via Internal Programmer With Args ${fw_file_path} -N --fmap -i RW_SECTION_A
|
|
END
|
|
|
|
# TODO: below keywords are simply copied from keywords.robot. They might require some
|
|
# more cleanup/reduction.
|
|
|
|
Flash Firmware
|
|
[Documentation] Flash platform with firmware file specified in the
|
|
... argument. Keyword fails if file size doesn't match target
|
|
... chip size.
|
|
[Arguments] ${fw_file}
|
|
IF '${FLASHING_METHOD}'=='none' RETURN
|
|
|
|
${file_size}= Run ls -l ${fw_file} | awk '{print $5}'
|
|
IF '''${file_size}''' != '''${FLASH_SIZE}'''
|
|
FAIL Image size doesn't match the flash chip's size!
|
|
END
|
|
|
|
IF '${FLASHING_METHOD}' == 'external'
|
|
Rte Flash Write ${fw_file}
|
|
ELSE IF '${FLASHING_METHOD}' == 'internal'
|
|
Make Sure That Flash Locks Are Disabled
|
|
Power On
|
|
Boot System Or From Connected Disk ${BOOTED_OS_ID}
|
|
Login To Linux
|
|
Switch To Root User
|
|
VAR @{regions}= bios
|
|
IF ${INTEL_CBNT_BOOTGUARD_FUSING_SUPPORT}
|
|
VAR @{regions}= @{regions} me
|
|
END
|
|
Flash Via Internal Programmer ${fw_file} @{regions}
|
|
END
|
|
|
|
IF '''${POWER_CTRL}''' == '''none'''
|
|
Power On
|
|
Boot System Or From Connected Disk ${BOOTED_OS_ID}
|
|
Login To Linux
|
|
Switch To Root User
|
|
Execute Reboot Command
|
|
Sleep 30s Additional sleep for RAM training etc. after flashing
|
|
END
|
|
|
|
# First boot after flashing may take longer than usual
|
|
Set DUT Response Timeout 300s
|
|
|
|
Replace Logo In Firmware
|
|
[Documentation] Swap to custom logo in firmware on DUT using cbfstool according
|
|
... to: https://docs.dasharo.com/guides/logo-customization
|
|
[Arguments] ${logo_file}
|
|
Execute Command In Terminal flashrom -p internal -r /tmp/firmware.rom
|
|
# Remove the existing logo from the firmware image
|
|
${out}= Execute Command In Terminal cbfstool /tmp/firmware.rom remove -r BOOTSPLASH -n logo.bmp
|
|
# Add your desired bootlogo to the firmware image
|
|
${out}= Execute Command In Terminal
|
|
... cbfstool /tmp/firmware.rom add -f ${logo_file} -r BOOTSPLASH -n logo.bmp -t raw -c lzma
|
|
Should Not Contain ${out} Image is missing 'BOOTSPLASH' region
|
|
Write BOOTSPLASH Region Internally /tmp/firmware.rom
|
|
|
|
Read FMAP And BOOTSPLASH Regions Internally
|
|
[Documentation] Read BOOTSPLASH firmware on DUT using flashrom.
|
|
[Arguments] ${fw_file}
|
|
${out}= Execute Linux Command flashrom -p internal --fmap -i FMAP -i BOOTSPLASH -r ${fw_file} 180
|
|
Should Contain ${out} Reading flash... done
|
|
|
|
Write BOOTSPLASH Region Internally
|
|
[Documentation] Flash BOOTSPLASH firmware region on DUT using flashrom.
|
|
[Arguments] ${fw_file}
|
|
${out}= Execute Linux Command flashrom -p internal --fmap -i BOOTSPLASH -N -w ${fw_file} 180
|
|
Should Contain Any ${out} VERIFIED Chip content is identical to the requested image
|
|
|
|
Check Write Protection Availability
|
|
[Documentation] Check whether it is possible to set Write Protection
|
|
... on the DUT.
|
|
${out}= Execute Linux Command ./flashrom -p internal --wp-list
|
|
Should Not Contain ${out} write protect support is not implemented for this flash chip
|
|
Should Contain ${out} Available write protection ranges:
|
|
Should Contain ${out} all
|
|
|
|
Erase Write Protection
|
|
[Documentation] Erase write protection from the flash chip.
|
|
${out}= Execute Linux Command ./flashrom -p internal --wp-disable 180
|
|
Should Contain ${out} Successfully set the requested mode
|
|
${out}= Execute Linux Command ./flashrom -p internal --wp-range=0,0 180
|
|
Should Contain ${out} Successfully set the requested protection range
|
|
|
|
Set Write Protection
|
|
[Documentation] Set protection range as defined by the parameters:
|
|
... `${start_adress}` - protection start address,
|
|
... `${length}` - flash protected range length.
|
|
[Arguments] ${start_adress} ${length}
|
|
${out}= Execute Linux Command ./flashrom -p internal --wp-range=${start_adress},${length} 180
|
|
Should Contain ${out} Successfully set the requested protection range
|
|
${out}= Execute Linux Command ./flashrom -p internal --wp-enable 180
|
|
Should Contain ${out} Successfully set the requested mode
|
|
|
|
Check Write Protection Status
|
|
[Documentation] Check whether Write Protection mechanism is active.
|
|
${out}= Execute Linux Command ./flashrom -p internal --wp-status 180
|
|
Should Contain ${out} Protection mode: hardware
|
|
|
|
Compare Write Protection Ranges
|
|
[Documentation] Allows to compare Protection Range: declared and
|
|
... currently set.
|
|
[Arguments] ${start_adress} ${length}
|
|
${out}= Execute Linux Command ./flashrom -p internal --wp-status 180
|
|
${protection_range}= Get Lines Containing String ${out} Protection range:
|
|
${protection_range}= Split String ${protection_range}
|
|
${set_start_adress}= Get From List ${protection_range} 2
|
|
${set_start_adress}= Fetch From Right ${set_start_adress} =
|
|
${set_length}= Get From List ${protection_range} 3
|
|
${set_length}= Fetch From Right ${set_length} =
|
|
IF ${set_start_adress}!=${start_adress}
|
|
FAIL Declared and currently set protection start addresses are not the same
|
|
END
|
|
IF ${set_length}!=${length}
|
|
FAIL Declared and currently set protection lengths are not the same
|
|
END
|
|
|
|
Read Firmware
|
|
[Documentation] Read platform firmware to file specified in the argument.
|
|
[Arguments] ${file}
|
|
|
|
IF '${FLASHING_METHOD}' == 'external'
|
|
IF '${APU_FLASH_WP_GPIO}' != '${TBD}'
|
|
Rte Gpio Set ${APU_FLASH_WP_GPIO} low
|
|
END
|
|
Rte Flash Read ${file}
|
|
IF '${APU_FLASH_WP_GPIO}' != '${TBD}'
|
|
Rte Gpio Set ${APU_FLASH_WP_GPIO} high-z
|
|
END
|
|
ELSE IF '${FLASHING_METHOD}' == 'internal'
|
|
# TODO
|
|
Power On
|
|
Boot System Or From Connected Disk ${DEFAULT_BOOT_OS_ID}
|
|
Login To Linux
|
|
Switch To Root User
|
|
Execute Command In Terminal flashrom -p internal --ifd -i fd -i bios -i me -r coreboot.rom
|
|
Get File From DUT coreboot.rom ${file}
|
|
ELSE
|
|
Fail Read firmware not implemented for platform config ${CONFIG}
|
|
END
|
|
|
|
Get Flashrom FMAP Regions
|
|
${output}= Execute Command In Terminal flashrom -p internal -r coreboot.rom timeout=300s
|
|
${output}= Execute Command In Terminal cbfstool coreboot.rom layout -w
|
|
${lines}= Split To Lines ${output}
|
|
VAR &{dict}= &{EMPTY}
|
|
FOR ${l} IN @{lines}
|
|
${m}= Get Regexp Matches
|
|
... ${l}
|
|
... ^'([A-Z_]+)' \\(([a-zA-Z_\-]+, )?size ([0-9]+), offset ([0-9]+)\\)$
|
|
... 1
|
|
... 2
|
|
... 3
|
|
... 4
|
|
|
|
IF ${m} != []
|
|
VAR ${name}= ${m}[0][0]
|
|
VAR ${type}= ${m}[0][1]
|
|
VAR ${size}= ${m}[0][2]
|
|
VAR ${offset}= ${m}[0][3]
|
|
${start}= Evaluate ${offset}
|
|
${end}= Evaluate ${start} + ${size}
|
|
|
|
VAR &{region}= start=${start} end=${end} type=${type}
|
|
Set To Dictionary ${dict} ${name}=${region}
|
|
END
|
|
END
|
|
RETURN ${dict}
|
|
|
|
Get Flashrom Regions
|
|
${output}= Execute Command In Terminal flashrom -p internal
|
|
${lines}= Split To Lines ${output}
|
|
VAR &{dict}= &{EMPTY}
|
|
FOR ${l} IN @{lines}
|
|
${m}= Get Regexp Matches
|
|
... ${l}
|
|
... FREG[0-9]+: (.+) region \\((0x[0-9a-f]+)-(0x[0-9a-f]+)\\) is (.+)
|
|
... 1
|
|
... 2
|
|
... 3
|
|
... 4
|
|
IF ${m} != []
|
|
VAR ${name}= ${m}[0][0]
|
|
VAR ${start}= ${m}[0][1]
|
|
VAR ${end}= ${m}[0][2]
|
|
VAR ${state}= ${m}[0][3]
|
|
${start}= Evaluate int(${start})
|
|
${end}= Evaluate int(${end})
|
|
VAR &{region}= start=${start} end=${end} state=${state}
|
|
Set To Dictionary ${dict} ${name}=${region}
|
|
END
|
|
END
|
|
RETURN ${dict}
|
|
|
|
Get Flashrom Readonly Offsets
|
|
${output}= Execute Command In Terminal flashrom -p internal
|
|
${lines}= Split To Lines ${output}
|
|
VAR @{list}= @{EMPTY}
|
|
FOR ${l} IN @{lines}
|
|
${m}= Get Regexp Matches ${l} Warning: (0x[0-9a-f]+)-(0x[0-9a-f]+) is read-only 1 2
|
|
IF ${m} != []
|
|
${start}= Evaluate int(${m[0][0]})
|
|
${end}= Evaluate int(${m[0][1]}) + 1 # inclusive
|
|
VAR &{region}= start=${start} end=${end}
|
|
Append To List ${list} ${region}
|
|
END
|
|
END
|
|
RETURN ${list}
|
|
|
|
Calculate Expected Flashrom Readonly Region
|
|
[Tags] robot:private
|
|
[Arguments] ${region_name} ${start_offset} ${end_offset}
|
|
${flashrom_regions}= Get Flashrom Regions
|
|
${bios_start}= Get From Dictionary ${flashrom_regions['${region_name}']} start
|
|
${bios_end}= Get From Dictionary ${flashrom_regions['${region_name}']} end
|
|
${expected_readonly_start}= Evaluate ${bios_start} + ${COREBOOT_REDUNDANT_BOOT_BOOTBLOCK_OFFSET.start}
|
|
${expected_readonly_end}= Evaluate ${bios_start} + ${COREBOOT_REDUNDANT_BOOT_BOOTBLOCK_OFFSET.end}
|
|
VAR &{expected_readonly}= start=${expected_readonly_start} end=${expected_readonly_end}
|
|
RETURN ${expected_readonly}
|
|
|
|
Verify Region Range Protected
|
|
[Arguments] ${region_name} ${expected_start} ${expected_end}
|
|
${readonly_regions}= Get Flashrom Readonly Offsets
|
|
IF len(${readonly_regions}) == 0
|
|
Fail No readonly regions found in flashrom output
|
|
END
|
|
|
|
${expected_readonly_bootblock}= Calculate Expected Flashrom Readonly Region
|
|
... region_name=${region_name}
|
|
... start_offset=${expected_start}
|
|
... end_offset=${expected_end}
|
|
|
|
VAR ${expected_readonly_found}= ${FALSE}
|
|
FOR ${region} IN @{readonly_regions}
|
|
Log To Console Found readonly region: ${region}
|
|
Log To Console Expected readonly region: ${expected_readonly_bootblock}
|
|
${start_matches}= Evaluate ${region['start']} == ${expected_readonly_bootblock['start']}
|
|
${end_matches}= Evaluate ${region['end']} == ${expected_readonly_bootblock['end']}
|
|
IF ${start_matches} and ${end_matches}
|
|
VAR ${expected_readonly_found}= ${TRUE}
|
|
BREAK
|
|
END
|
|
END
|
|
IF not ${expected_readonly_found}
|
|
Fail Expected readonly region ${expected_readonly_bootblock} not found in flashrom output
|
|
END
|
|
|
|
Flashrom Verify FMAP Regions Protected
|
|
[Arguments] @{region_names}
|
|
${fmap_regions}= Get Flashrom FMAP Regions
|
|
${protected_offsets}= Get Flashrom Readonly Offsets
|
|
VAR @{failed_regions}= @{EMPTY}
|
|
|
|
FOR ${region_name} IN @{region_names}
|
|
${region}= Get From Dictionary ${fmap_regions} ${region_name} default=${None}
|
|
IF $region is ${None}
|
|
Fail Region ${region_name} does not exist in the FMAP
|
|
END
|
|
VAR ${protected}= ${FALSE}
|
|
FOR ${offsets} IN @{protected_offsets}
|
|
IF ${offsets.start} <= ${region.start} and ${offsets.end} >= ${region.end}
|
|
VAR ${protected}= ${TRUE}
|
|
BREAK
|
|
END
|
|
END
|
|
IF not ${protected}
|
|
Set To Dictionary ${region} name=${region_name}
|
|
Append To List ${failed_regions} ${region}
|
|
END
|
|
END
|
|
|
|
IF len($failed_regions) > 0
|
|
FOR ${region} IN @{failed_regions}
|
|
Log To Console Region ${region.name}(${region.start}-${region.end}) is not protected!
|
|
END
|
|
Log To Console Protected ranges: ${protected_offsets}
|
|
Fail Not every region is protected.
|
|
END
|