FreeCalypso > hg > freecalypso-tools
view 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 source
/* * 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); }