| #!/usr/bin/env python3 | |
| # Copyright 2018 The ChromiumOS Authors | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| """Verify that RO cannot flash to wrong address.""" | |
| from __future__ import print_function | |
| import sys | |
| import time | |
| import common | |
| import hammerd_api # pylint: disable=import-error | |
| # These will fail in RO because hammer prevents current image from being | |
| # updated. It'll fail in RW as RO is protected. | |
| WRONG_ADDR_RO_OFFSET = "0x00000000" | |
| WRONG_ADDR_KEY_RO = "0x0000ac00" | |
| WRONG_ADDR_RO_FRID = "0x000000c4" | |
| WRONG_ADDR_RW_FWID = "0x0000c0c4" | |
| WRONG_ADDR_SIG_RW = "0x0001fc00" | |
| # This will fail because hammer never allows rollback to be updated | |
| WRONG_ADDR_RW_RBVER = "0x0000c0e8" | |
| # These will fail in RW because hammer prevents current image from being | |
| # updated. It'll fail in RO as RW must be write protected. | |
| WRONG_ADDR_RW_OFFSET = "0x0000c000" | |
| WRONG_ADDR_LIST = [ | |
| WRONG_ADDR_RO_OFFSET, | |
| WRONG_ADDR_KEY_RO, | |
| WRONG_ADDR_RO_FRID, | |
| WRONG_ADDR_RW_FWID, | |
| WRONG_ADDR_SIG_RW, | |
| WRONG_ADDR_RW_RBVER, | |
| WRONG_ADDR_RW_OFFSET, | |
| ] | |
| def main(argv): | |
| if argv: | |
| sys.exit("Test takes no args!") | |
| updater = common.get_firmware_updater() | |
| with open(common.IMAGE, "rb") as f: | |
| ec_image = f.read() | |
| updater.LoadEcImage(ec_image) | |
| common.disable_hammerd() | |
| common.connect_usb(updater) | |
| print("EC information:") | |
| pdu_resp = updater.GetFirstResponsePdu().contents | |
| print("PDU Response: %s" % pdu_resp) | |
| print("RO: %s" % updater.GetSectionVersion(hammerd_api.SectionName.RO)) | |
| print("RW: %s" % updater.GetSectionVersion(hammerd_api.SectionName.RW)) | |
| print("Is RW locked?: %s" % updater.IsSectionLocked(1)) | |
| assert updater.IsSectionLocked(1), "RW should be locked" | |
| updater.SendSubcommand(hammerd_api.UpdateExtraCommand.ImmediateReset) | |
| updater.CloseUsb() | |
| time.sleep(0.5) | |
| updater.TryConnectUsb() | |
| updater.SendSubcommand(hammerd_api.UpdateExtraCommand.StayInRO) | |
| time.sleep(1) | |
| assert updater.SendFirstPdu() is True, "Error sending first PDU" | |
| updater.SendDone() | |
| print("Current section after StayInRO cmd: %s" % updater.CurrentSection()) | |
| assert updater.CurrentSection() == 0, "Running section should be 0 (RO)" | |
| init_transfer(updater) | |
| # First test that RW can't update anything | |
| flash_invalid_address(updater, True) | |
| # Uncommenting these line will make the test fail (RO will be able to write | |
| # to WRONG_ADDR_RW_OFFSET) | |
| # common.connect_usb(updater) | |
| # unlock_rw(updater) | |
| # updater.CloseUsb() | |
| # Then test that RO can't update anything | |
| flash_invalid_address(updater, False) | |
| # Sleep for some time to ensure the kernel and base keyboard become ready as | |
| # a restoration, so we can hand the control back for any following tests. | |
| time.sleep(5) | |
| def get_wp_status(updater): | |
| wp_rw = (get_flash_protection(updater) & common.EC_FLASH_PROTECT_RW_NOW) > 0 | |
| return wp_rw | |
| def flash_invalid_address(updater, rw): | |
| # Using TransferTouchpadFirmware method for now as API lacks equivalent. | |
| for address in WRONG_ADDR_LIST: | |
| common.connect_usb(updater) | |
| if rw: | |
| updater.SendSubcommand(hammerd_api.UpdateExtraCommand.JumpToRW) | |
| updater.CloseUsb() | |
| time.sleep(0.5) | |
| updater.TryConnectUsb() | |
| assert updater.SendFirstPdu(), "Error sending first PDU" | |
| updater.SendDone() | |
| print("Current section: %s" % updater.CurrentSection()) | |
| if rw: | |
| assert ( | |
| updater.CurrentSection() == 1 | |
| ), "Running section should be 1 (RW)" | |
| else: | |
| assert ( | |
| updater.CurrentSection() == 0 | |
| ), "Running section should be 0 (RO)" | |
| wr = updater.TransferTouchpadFirmware(int(address, 0), 4096) | |
| assert wr == 0, "Should not be able to write to wrong address!" | |
| updater.SendSubcommand( | |
| hammerd_api.UpdateExtraCommand.ImmediateReset | |
| ) | |
| updater.CloseUsb() | |
| time.sleep(0.5) | |
| def init_transfer(updater): | |
| with open(common.TP, "rb") as f: | |
| ec_image = f.read() | |
| updater.LoadTouchpadImage(ec_image) | |
| assert updater.SendFirstPdu() is True, "Error sending first PDU" | |
| updater.SendDone() | |
| unlock_rw(updater) | |
| common.sim_disconnect_connect(updater) | |
| def unlock_rw(updater): | |
| # Check if RW is locked and unlock if needed. | |
| wp_rw = get_wp_status(updater) | |
| print("WP status: %s" % str(wp_rw)) | |
| if wp_rw: | |
| print("Need to unlock RW") | |
| unlocked = updater.UnlockRW() | |
| assert unlocked == 1, "Failed to unlock RW" | |
| def get_flash_protection(updater): | |
| pdu_resp = updater.GetFirstResponsePdu().contents | |
| return pdu_resp.flash_protection | |
| if __name__ == "__main__": | |
| sys.exit(main(sys.argv[1:])) |