📄 jtagprog.cc
字号:
/* * avarice - The "avarice" program. * Copyright (C) 2001 Scott Finneran * Copyright (C) 2002 Intel Corporation * * File format support using BFD contributed and copyright 2003 * Nils Kr. Strom * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * * This file contains functions for interfacing with the JTAG box. */#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/stat.h>#include <termios.h>#include <fcntl.h>#include <string.h>#include <math.h>#include <bfd.h>#include "avarice.h"#include "jtag.h"// The API changed for this in bfd.h. This is a work around.#ifndef bfd_get_section_size# define bfd_get_section_size bfd_get_section_size_before_reloc#endif// Allocate 1 meg for image buffer. This is where the file data is// stored before writing occurs.#define MAX_IMAGE_SIZE 1000000// This flag is used to select the address space values for the// jtagRead() and jtagWrite() commands.bool programmingEnabled = false;// Enumerations for target memory type.typedef enum { MEM_FLASH = 0, MEM_EEPROM = 1, MEM_RAM = 2,} BFDmemoryType;const char *BFDmemoryTypeString[] = { "FLASH", "EEPROM", "RAM",};const int BFDmemorySpaceOffset[] = { FLASH_SPACE_ADDR_OFFSET, EEPROM_SPACE_ADDR_OFFSET, DATA_SPACE_ADDR_OFFSET,};typedef struct { uchar val; bool used;} AVRMemoryByte;// Struct that holds the memory image. We read from file using BFD// into this struct, then pass the entire struct to the target writer.typedef struct { AVRMemoryByte image[MAX_IMAGE_SIZE]; int last_address; int first_address; bool first_address_ok; bool has_data; const char *name;} BFDimage;static void initImage(BFDimage *image){ unsigned int i; image->last_address = 0; image->first_address = 0; image->first_address_ok = false; image->has_data = false; for (i=0;i<MAX_IMAGE_SIZE;i++) { image->image[i].val = 0x00; image->image[i].used = false; }}static bool pageIsEmpty(BFDimage *image, unsigned int addr, unsigned int size, BFDmemoryType memtype){ bool emptyPage = true; // Check if page is used for (unsigned int idx=addr; idx<addr+size; idx++) { if (idx >= image->last_address) break; // 1. If this address existed in input file, mark as ! empty. // 2. If we are programming FLASH, and contents == 0xff, we need // not program (is 0xff after erase). if (image->image[idx].used) { if (!((memtype == MEM_FLASH) && (image->image[idx].val == 0xff))) { emptyPage = false; break; } } } return emptyPage;}void enableProgramming(void){ programmingEnabled = true; check(doSimpleJtagCommand(0xa3, 1), "JTAG ICE: Failed to enable programming");}void disableProgramming(void){ programmingEnabled = false; check(doSimpleJtagCommand(0xa4, 1), "JTAG ICE: Failed to disable programming");}// This is really a chip-erase which erases flash, lock-bits and eeprom// (unless the save-eeprom fuse is set).void eraseProgramMemory(void){ check(doSimpleJtagCommand(0xa5, 1), "JTAG ICE: Failed to erase program memory");}void eraseProgramPage(unsigned long address){ uchar *response = NULL; uchar command[] = { 0xa1, 0, 0, 0, JTAG_EOM }; command[1] = address >> 8; command[2] = address; response = doJtagCommand(command, sizeof(command), 1); check(response[0] == JTAG_R_OK, "Page erase failed\n"); delete [] response;}// Check if file format is supported.// return nonzero on errors.static int check_file_format(bfd *file){ char **matching; int done = 0; int err = 1; // Check if archive, not plain file. if (bfd_check_format(file, bfd_archive) == true) { fprintf(stderr, "Input file is archive\n"); } else if (bfd_check_format_matches (file, bfd_object, &matching)) err = 0; else if (bfd_get_error () == bfd_error_file_ambiguously_recognized) { fprintf(stderr, "File format ambiguous: %s\n", bfd_errmsg(bfd_get_error())); } else if (bfd_get_error () != bfd_error_file_not_recognized) { fprintf(stderr, "File format not supported: %s\n", bfd_errmsg(bfd_get_error())); } else if (bfd_check_format_matches (file, bfd_core, &matching)) err = 0; return err;}unsigned int get_page_size(BFDmemoryType memtype){ unsigned int page_size; switch( memtype ) { case MEM_FLASH: page_size = global_p_device_def->flash_page_size; break; case MEM_EEPROM: page_size = global_p_device_def->eeprom_page_size; break; default: page_size = 1; break; } return page_size;}// Return page address of static inline unsigned int page_addr(unsigned int addr, BFDmemoryType memtype){ unsigned int page_size = get_page_size( memtype ); return (unsigned int)(addr & (~(page_size - 1)));}// Get address of section.// We have two different scenarios (both with same result).// 1. vma == lma : Normal section// Return real address (mask gcc-hacked MSB's away).//// 2. vma != lma : For sections to be relocated (e.g. .data)// lma is the address where the duplicate initialized data is stored.// vma is the destination address after relocation.// Return real address (mask gcc-hacked MSB's away).//// 3. Not correct memory type: return 0x800000.// static unsigned int get_section_addr(asection *section, BFDmemoryType memtype){ BFDmemoryType sectmemtype; unsigned int addr = section->lma; if ((section->flags & SEC_HAS_CONTENTS) && ((section->flags & SEC_ALLOC) || (section->flags & SEC_LOAD))) { if (section->lma < DATA_SPACE_ADDR_OFFSET) // < 0x80... sectmemtype = MEM_FLASH; else if (section->lma < EEPROM_SPACE_ADDR_OFFSET) // < 0x81... sectmemtype = MEM_RAM; else if (section->lma < FUSE_SPACE_ADDR_OFFSET) // < 0x82... sectmemtype = MEM_EEPROM; if (memtype == sectmemtype) { if (sectmemtype == MEM_FLASH) { /* Don't mask the lma or you will not be able to handle more than 64K of flash. */ return (section->lma); } return (section->lma &~ ADDR_SPACE_MASK); } else return 0xffffff; } else return 0xffffff;}// Add section of memtype BFDmemoryType to image.static void jtag_create_image(bfd *file, asection *section, BFDimage *image, BFDmemoryType memtype){ const char *name; unsigned int addr; unsigned int size; static uchar buf[MAX_IMAGE_SIZE]; unsigned int i; // If section is empty (although unexpected) return if (! section) return; // Get information about section name = bfd_get_section_name(file, section); size = bfd_get_section_size(section); if ((addr = get_section_addr(section, memtype)) != 0xffffff) { debugOut("Getting section contents, addr=0x%lx size=0x%lx\n", addr, size); // Read entire section into buffer, at correct byte address. bfd_get_section_contents(file, section, buf, 0, size); // Copy section into memory struct. Mark as used. for (i=0; i<size; i++) { unsigned int c = i+addr; image->image[c].val = buf[i]; image->image[c].used = true; } // Remember last address in image if (addr+size > image->last_address) image->last_address = addr+size; // Remember first address in image if ((! image->first_address_ok) || (addr < image->first_address)) { image->first_address = addr; image->first_address_ok = true; } debugOut("%s Image create: Adding %s at addr 0x%lx size %d (0x%lx)\n", BFDmemoryTypeString[memtype], name, addr, size, size); // Indicate image has data image->has_data = true; }}static void jtag_flash_image(BFDimage *image, BFDmemoryType memtype, bool program, bool verify){ unsigned int page_size = get_page_size(memtype); static uchar buf[MAX_IMAGE_SIZE]; unsigned int i; uchar *response = NULL; bool emptyPage = true; unsigned int addr; if (! image->has_data) { fprintf(stderr, "File contains no data.\n"); exit(-1); } if (program) { // First address must start on page boundary. addr = page_addr(image->first_address, memtype); statusOut("Downloading %s image to target.", image->name); statusFlush(); while (addr < image->last_address) { if (!pageIsEmpty(image, addr, page_size, memtype)) { // Must also convert address to gcc-hacked addr for jtagWrite debugOut("Writing page at addr 0x%.4lx size 0x%lx\n", addr, page_size); // Create raw data buffer for (i=0; i<page_size; i++) buf[i] = image->image[i+addr].val; check(jtagWrite(BFDmemorySpaceOffset[memtype] + addr, page_size, buf), "Error writing to target"); // No need for statusOut here, since jtagWrite does it. } addr += page_size; statusOut("."); statusFlush(); } statusOut("\n"); statusFlush(); } if (verify) { bool is_verified = true; // First address must start on page boundary. addr = page_addr(image->first_address, memtype); statusOut("\nVerifying %s", image->name); statusFlush(); while (addr < image->last_address) { // Must also convert address to gcc-hacked addr for jtagWrite debugOut("Verifying page at addr 0x%.4lx size 0x%lx\n", addr, page_size); response = jtagRead(BFDmemorySpaceOffset[memtype] + addr, page_size); // Verify buffer, but only addresses in use. for (i=0; i < page_size; i++) { unsigned int c = i + addr; if (image->image[c].used ) { if (image->image[c].val != response[i]) { statusOut("\nError verifying target addr %.4x. " "Expect [0x%02x] Got [0x%02x]", c, image->image[c].val, response[i]); statusFlush(); is_verified = false; } } } addr += page_size; statusOut("."); statusFlush(); } delete [] response; statusOut("\n"); statusFlush(); check(is_verified, "\nVerification failed!"); }}void downloadToTarget(const char* filename, bool program, bool verify){ // Basically, we just open the file and copy blocks over to the JTAG // box. struct stat ifstat; char *target = NULL; char *default_target = "binary"; unsigned int page_size; bool done = 0; bfd *file; asection *p; static BFDimage flashimg, eepromimg; initImage(&flashimg); initImage(&eepromimg); flashimg.name = BFDmemoryTypeString[MEM_FLASH]; eepromimg.name = BFDmemoryTypeString[MEM_EEPROM]; unixCheck(stat(filename, &ifstat), "Can't stat() file %s", filename); // Open the input file. bfd_init(); // Auto detect file format by a loop iterated at most two times. // 1. Auto-detect file format. // 2. If auto-detect failed, assume binary and iterate once more over // loop. while (! done) { file = bfd_openr(filename, target); if (! file) { fprintf( stderr, "Could not open input file %s:%s\n", filename, bfd_errmsg(bfd_get_error()) ); exit(-1); } // Check if file format is supported. If not, go for binary mode. else if (check_file_format(file)) { // File format detection failed. Assuming binary file // BFD section flags are CONTENTS,ALLOC,LOAD,DATA // We must force CODE in stead of DATA fprintf(stderr, "Warning: File format unknown, assuming " "binary.\n"); target = default_target; } else done = 1; } // Configure for JTAG download/programming // Set the flash page and eeprom page sizes (These are device dependent) page_size = get_page_size(MEM_FLASH); debugOut("Flash page size: 0x%0x\nEEPROM page size: 0x%0x\n", page_size, get_page_size(MEM_EEPROM)); setJtagParameter(JTAG_P_FLASH_PAGESIZE_LOW, page_size & 0xff); setJtagParameter(JTAG_P_FLASH_PAGESIZE_HIGH, page_size >> 8); setJtagParameter(JTAG_P_EEPROM_PAGESIZE, get_page_size(MEM_EEPROM)); // Create RAM image by reading all sections in file p = file->sections; while (p) { jtag_create_image(file, p, &flashimg, MEM_FLASH); jtag_create_image(file, p, &eepromimg, MEM_EEPROM); p = p->next; } enableProgramming(); // Write the complete FLASH/EEPROM images to the device. if (flashimg.has_data) jtag_flash_image(&flashimg, MEM_FLASH, program, verify); if (eepromimg.has_data) jtag_flash_image(&eepromimg, MEM_EEPROM, program, verify); disableProgramming(); unixCheck(bfd_close(file), "Error closing %s", filename); statusOut("\nDownload complete.\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -