FreeCalypso > hg > freecalypso-tools
diff loadtools/flamdsec.c @ 977:511e2b85c115
fc-loadtool: implement flash lock-state command
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 01 Dec 2023 07:51:01 +0000 |
parents | |
children | c5133c3c11b1 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flamdsec.c Fri Dec 01 07:51:01 2023 +0000 @@ -0,0 +1,170 @@ +/* + * This module is a place to implement commands that are specific to + * security features (OTP, sector locking) of AMD-style flash chips. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include "flash.h" + +extern struct flash_bank_info flash_bank_info[2]; + +static +issue_read_id(base_addr) + uint32_t base_addr; +{ + if (do_w16(base_addr + 0xAAA, 0xAA)) { +bad_w16: fprintf(stderr, + "unexpected response to w16 in read ID cmd sequence - aborting\n"); + return(-1); + } + if (do_w16(base_addr + 0x554, 0x55)) + goto bad_w16; + if (do_w16(base_addr + 0xAAA, 0x90)) + goto bad_w16; + return(0); +} + +static +issue_reset_cmd(base_addr) + uint32_t base_addr; +{ + if (do_w16(base_addr + 0xAAA, 0xF0)) { + fprintf(stderr, + "unexpected response to w16 when resetting flash to read mode!\n"); + return(-1); + } + return(0); +} + +static +read_mode_lock_word(base_addr, word_offset, retp) + uint32_t base_addr, word_offset; + uint16_t *retp; +{ + if (do_w16(base_addr + 0xAAA, 0xAA)) { +bad_w16: fprintf(stderr, + "unexpected response to w16 in mode lock query sequence - aborting\n"); + return(-1); + } + if (do_w16(base_addr + 0x554, 0x55)) + goto bad_w16; + if (do_w16(base_addr + 0xAAA, 0x60)) + goto bad_w16; + if (do_w16(base_addr + word_offset, 0x48)) + goto bad_w16; + if (do_r16(base_addr + word_offset, retp) < 0) + return(-1); + return(0); +} + +static +pln_special_mode_entry(base_addr, mode_opc) + uint32_t base_addr; + uint16_t mode_opc; +{ + if (do_w16(base_addr + 0xAAA, 0xAA)) { +bad_w16: fprintf(stderr, +"unexpected response to w16 in PL-N special mode entry sequence - aborting\n"); + return(-1); + } + if (do_w16(base_addr + 0x554, 0x55)) + goto bad_w16; + if (do_w16(base_addr + 0xAAA, mode_opc)) + goto bad_w16; + return(0); +} + +static +pln_special_mode_exit(base_addr) + uint32_t base_addr; +{ + if (do_w16(base_addr, 0x90)) { +bad_w16: fprintf(stderr, +"unexpected response to w16 in PL-N special mode exit sequence - aborting\n"); + return(-1); + } + if (do_w16(base_addr, 0x00)) + goto bad_w16; + return(0); +} + +flashcmd_lock_state(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + struct amd_lock_info *li; + struct lock_group_desc *grp; + uint32_t offset, part_addr; + uint16_t word; + unsigned ng, nb; + + if (argc > 2) { + fprintf(stderr, "error: too many arguments\n"); + return(-1); + } + if (flash_detect(bank, 0) < 0) + return(-1); + bi = flash_bank_info + bank; + li = bi->amd_lock; + if (!li) { + fprintf(stderr, + "Operation not supported for this flash chip type\n"); + return(-1); + } + offset = 0; + for (ng = 0; ng < li->ngroups; ng++) { + grp = li->groups + ng; + if (grp->part_begin) { + part_addr = bi->base_addr + offset; + if (issue_read_id(part_addr) < 0) + return(-1); + } + if (offset == 0 && li->have_status_word_3) { + if (do_r16(bi->base_addr + 6, &word) < 0) + return(-1); + printf("Global status word 3: %04X\n", word); + } + if (offset == 0 && li->have_status_word_7) { + if (do_r16(bi->base_addr + 0xE, &word) < 0) + return(-1); + printf("Global status word 7: %04X\n", word); + } + for (nb = 0; nb < grp->nblocks; nb++) { + if (do_r16(bi->base_addr + offset + 4, &word) < 0) + return(-1); + printf("Sector%s at 0x%X: %s\n", + grp->is_group ? " group" : "", offset, + (word & 1) ? "locked" : "unlocked"); + offset += grp->block_size; + } + if (grp->part_end) { + if (issue_reset_cmd(part_addr) < 0) + return(-1); + } + } + if (li->have_mode_lock_bits) { + if (read_mode_lock_word(bi->base_addr, 0x14, &word) < 0) + return(-1); + printf("Password Protection Mode lock: %04X\n", word); + if (issue_reset_cmd(bi->base_addr) < 0) + return(-1); + if (read_mode_lock_word(bi->base_addr, 0x24, &word) < 0) + return(-1); + printf("Persistent Protection Mode lock: %04X\n", word); + if (issue_reset_cmd(bi->base_addr) < 0) + return(-1); + } + if (li->have_pln_lock_reg) { + if (pln_special_mode_entry(bi->base_addr, 0x40) < 0) + return(-1); + if (do_r16(bi->base_addr, &word) < 0) + return(-1); + printf("PL-N Lock Register: %04X\n", word); + if (pln_special_mode_exit(bi->base_addr) < 0) + return(-1); + } + return(0); +}