aboutsummaryrefslogtreecommitdiff
path: root/libjava/classpath/java/security/Permission.java
blob: cf6399b1671527bc39df6d6bbfc587796e97792d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/* Permission.java -- The superclass for all permission objects
   Copyright (C) 1998, 2001, 2002, 2005  Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath 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 GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

package java.security;

import gnu.java.lang.CPStringBuilder;

import java.io.Serializable;

/**
 * This class is the abstract superclass of all classes that implement
 * the concept of a permission.  A permission consists of a permission name
 * and optionally a list of actions that relate to the permission.  The
 * actual meaning of the name of the permission is defined only in the
 * context of a subclass.  It may name a resource to which access permissions
 * are granted (for example, the name of a file) or it might represent
 * something else entirely.  Similarly, the action list only has meaning
 * within the context of a subclass.  Some permission names may have no
 * actions associated with them.  That is, you either have the permission
 * or you don't.
 *
 * <p>The most important method in this class is <code>implies</code>.  This
 * checks whether if one has this permission, then the specified
 * permission is also implied.  As a conceptual example, consider the
 * permissions "Read All Files" and "Read File foo".  The permission
 * "Read All Files" implies that the caller has permission to read the
 * file foo.
 *
 * <p><code>Permission</code>'s must be immutable - do not change their
 * state after creation.
 *
 * @author Aaron M. Renn (arenn@urbanophile.com)
 * @see Permissions
 * @see PermissionCollection
 * @since 1.1
 * @status updated to 1.4
 */
public abstract class Permission implements Guard, Serializable
{
  /**
   * Compatible with JDK 1.1+.
   */
  private static final long serialVersionUID = -5636570222231596674L;

  /**
   * This is the name assigned to this permission object.
   *
   * @serial the name of the permission
   */
  private String name;

  /**
   * Create an instance with the specified name.
   *
   * @param name the permission name
   */
  public Permission(String name)
  {
    this.name = name;
  }

  /**
   * This method implements the <code>Guard</code> interface for this class.
   * It calls the <code>checkPermission</code> method in
   * <code>SecurityManager</code> with this <code>Permission</code> as its
   * argument.  This method returns silently if the security check succeeds
   * or throws an exception if it fails.
   *
   * @param obj the <code>Object</code> being guarded - ignored by this class
   * @throws SecurityException if the security check fails
   * @see GuardedObject
   * @see SecurityManager#checkPermission(Permission)
   */
  public void checkGuard(Object obj)
  {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null)
      sm.checkPermission(this);
  }

  /**
   * This method tests whether this <code>Permission</code> implies that the
   * specified <code>Permission</code> is also granted.
   *
   * @param perm the <code>Permission</code> to test against
   * @return true if perm is implied by this
   */
  public abstract boolean implies(Permission perm);

  /**
   * Check to see if this object equals obj. Use <code>implies</code>, rather
   * than <code>equals</code>, when making access control decisions.
   *
   * @param obj the object to compare to
   */
  public abstract boolean equals(Object obj);

  /**
   * This method returns a hash code for this <code>Permission</code>. It
   * must satisfy the contract of <code>Object.hashCode</code>: it must be
   * the same for all objects that equals considers to be the same.
   *
   * @return a hash value
   */
  public abstract int hashCode();

  /**
   * Get the name of this <code>Permission</code>.
   *
   * @return the name
   */
  public final String getName()
  {
    return name;
  }

  /**
   * This method returns the list of actions for this <code>Permission</code>
   * as a <code>String</code>. The string should be in canonical order, for
   * example, both <code>new FilePermission(f, "write,read")</code> and
   * <code>new FilePermission(f, "read,write")</code> have the action list
   * "read,write".
   *
   * @return the action list for this <code>Permission</code>
   */
  public abstract String getActions();

  /**
   * This method returns an empty <code>PermissionCollection</code> object
   * that can store permissions of this type, or <code>null</code> if no
   * such collection is defined. Subclasses must override this to provide
   * an appropriate collection when one is needed to accurately calculate
   * <code>implies</code>.
   *
   * @return a new <code>PermissionCollection</code>
   */
  public PermissionCollection newPermissionCollection()
  {
    return null;
  }

  /**
   * This method returns a <code>String</code> representation of this
   * <code>Permission</code> object. This is in the format:
   * <code>'(' + getClass().getName() + ' ' + getName() + ' ' + getActions
   * + ')'</code>.
   *
   * @return this object as a <code>String</code>
   */
  public String toString()
  {
    CPStringBuilder string = new CPStringBuilder();

    string = string.append('(');
    string = string.append(getClass().getName());
    string = string.append(' ');
    string = string.append(getName());

    if (!(getActions().equals("")))
      {
        string = string.append(' ');
        string = string.append(getActions());
      }

    string = string.append(')');
    return string.toString();
  }
} // class Permission
'n741' href='#n741'>741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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-1307, USA.             *
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "flash.h"
#include "command.h"
#include "target.h"
#include "time_support.h"
#include "fileio.h"
#include "image.h"
#include "log.h"

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <inttypes.h>

/* command handlers */
int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);

/* flash drivers
 */
extern flash_driver_t lpc2000_flash;
extern flash_driver_t cfi_flash;
extern flash_driver_t at91sam7_flash;
extern flash_driver_t str7x_flash;
extern flash_driver_t str9x_flash;
extern flash_driver_t stellaris_flash;
extern flash_driver_t str9xpec_flash;
extern flash_driver_t stm32x_flash;
extern flash_driver_t tms470_flash;
extern flash_driver_t ecosflash_flash;

flash_driver_t *flash_drivers[] =
{
	&lpc2000_flash,
	&cfi_flash,
	&at91sam7_flash,
	&str7x_flash,
	&str9x_flash,
	&stellaris_flash,
	&str9xpec_flash,
	&stm32x_flash,
	&tms470_flash,
	&ecosflash_flash,
	NULL,
};

flash_bank_t *flash_banks;
static 	command_t *flash_cmd;
static int auto_erase = 0;

/* wafer thin wrapper for invoking the flash driver */
static int flash_driver_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
{
	int retval;

	retval=bank->driver->write(bank, buffer, offset, count);
	if (retval!=ERROR_OK)
	{
		ERROR("error writing to flash at address 0x%08x at offset 0x%8.8x (%d)", bank->base, offset, retval);
	}

	return retval;
}

static int flash_driver_erase(struct flash_bank_s *bank, int first, int last)
{
	int retval;

	retval=bank->driver->erase(bank, first, last);
	if (retval!=ERROR_OK)
	{
		ERROR("failed erasing sectors %d to %d (%d)", first, last, retval);
	}

	return retval;
}

int flash_driver_protect(struct flash_bank_s *bank, int set, int first, int last)
{
	int retval;

	retval=bank->driver->protect(bank, set, first, last);
	if (retval!=ERROR_OK)
	{
		ERROR("failed setting protection for areas %d to %d (%d)", first, last, retval);
	}

	return retval;
}


int flash_register_commands(struct command_context_s *cmd_ctx)
{
	flash_cmd = register_command(cmd_ctx, NULL, "flash", NULL, COMMAND_ANY, NULL);

	register_command(cmd_ctx, flash_cmd, "bank", handle_flash_bank_command, COMMAND_CONFIG, "flash_bank <driver> <base> <size> <chip_width> <bus_width> <target> [driver_options ...]");
	register_command(cmd_ctx, flash_cmd, "auto_erase", handle_flash_auto_erase_command, COMMAND_ANY,
						 "auto erase flash sectors <on|off>");
	return ERROR_OK;
}

int flash_init_drivers(struct command_context_s *cmd_ctx)
{
	if (flash_banks)
	{
		register_command(cmd_ctx, flash_cmd, "banks", handle_flash_banks_command, COMMAND_EXEC,
						 "list configured flash banks ");
		register_command(cmd_ctx, flash_cmd, "info", handle_flash_info_command, COMMAND_EXEC,
						 "print info about flash bank <num>");
		register_command(cmd_ctx, flash_cmd, "probe", handle_flash_probe_command, COMMAND_EXEC,
						 "identify flash bank <num>");
		register_command(cmd_ctx, flash_cmd, "erase_check", handle_flash_erase_check_command, COMMAND_EXEC,
						 "check erase state of sectors in flash bank <num>");
		register_command(cmd_ctx, flash_cmd, "protect_check", handle_flash_protect_check_command, COMMAND_EXEC,
						 "check protection state of sectors in flash bank <num>");
		register_command(cmd_ctx, flash_cmd, "erase_sector", handle_flash_erase_command, COMMAND_EXEC,
						 "erase sectors at <bank> <first> <last>");
		register_command(cmd_ctx, flash_cmd, "erase_address", handle_flash_erase_address_command, COMMAND_EXEC,
						 "erase address range <address> <length>");
		register_command(cmd_ctx, flash_cmd, "write_bank", handle_flash_write_bank_command, COMMAND_EXEC,
						 "write binary data to <bank> <file> <offset>");
		register_command(cmd_ctx, flash_cmd, "write_image", handle_flash_write_image_command, COMMAND_EXEC,
						 "write_image <file> [offset] [type]");
		register_command(cmd_ctx, flash_cmd, "protect", handle_flash_protect_command, COMMAND_EXEC,
						 "set protection of sectors at <bank> <first> <last> <on|off>");
	}

	return ERROR_OK;
}

flash_bank_t *get_flash_bank_by_num_noprobe(int num)
{
	flash_bank_t *p;
	int i = 0;

	for (p = flash_banks; p; p = p->next)
	{
		if (i++ == num)
		{
			return p;
		}
	}
	ERROR("flash bank %d does not exist", num);
	return NULL;
}

int flash_get_bank_count()
{
	flash_bank_t *p;
	int i = 0;
	for (p = flash_banks; p; p = p->next)
	{
		i++;
	}
	return i;
}

flash_bank_t *get_flash_bank_by_num(int num)
{
	flash_bank_t *p = get_flash_bank_by_num_noprobe(num);
	int retval;

	if (p == NULL)
		return NULL;

	retval = p->driver->auto_probe(p);

	if (retval != ERROR_OK)
	{
		ERROR("auto_probe failed %d\n", retval);
		return NULL;
	}
	return p;
}

int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	int i;
	int found = 0;
	target_t *target;

	if (argc < 6)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	if ((target = get_target_by_num(strtoul(args[5], NULL, 0))) == NULL)
	{
		ERROR("target %lu not defined", strtoul(args[5], NULL, 0));
		return ERROR_OK;
	}

	for (i = 0; flash_drivers[i]; i++)
	{
		if (strcmp(args[0], flash_drivers[i]->name) == 0)
		{
			flash_bank_t *p, *c;

			/* register flash specific commands */
			if (flash_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
			{
				ERROR("couldn't register '%s' commands", args[0]);
				exit(-1);
			}

			c = malloc(sizeof(flash_bank_t));
			c->target = target;
			c->driver = flash_drivers[i];
			c->driver_priv = NULL;
			c->base = strtoul(args[1], NULL, 0);
			c->size = strtoul(args[2], NULL, 0);
			c->chip_width = strtoul(args[3], NULL, 0);
			c->bus_width = strtoul(args[4], NULL, 0);
			c->num_sectors = 0;
			c->sectors = NULL;
			c->next = NULL;

			if (flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c) != ERROR_OK)
			{
				ERROR("'%s' driver rejected flash bank at 0x%8.8x", args[0], c->base);
				free(c);
				return ERROR_OK;
			}

			/* put flash bank in linked list */
			if (flash_banks)
			{
				/* find last flash bank */
				for (p = flash_banks; p && p->next; p = p->next);
				if (p)
					p->next = c;
			}
			else
			{
				flash_banks = c;
			}

			found = 1;
		}
	}

	/* no matching flash driver found */
	if (!found)
	{
		ERROR("flash driver '%s' not found", args[0]);
		exit(-1);
	}

	return ERROR_OK;
}

int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int i = 0;

	if (!flash_banks)
	{
		command_print(cmd_ctx, "no flash banks configured");
		return ERROR_OK;
	}

	for (p = flash_banks; p; p = p->next)
	{
		command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
					  i++, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
	}

	return ERROR_OK;
}

int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int i = 0;
	int j = 0;
	int retval;

	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	for (p = flash_banks; p; p = p->next, i++)
	{
		if (i == strtoul(args[0], NULL, 0))
		{
			char buf[1024];

			/* attempt auto probe */
			p->driver->auto_probe(p);

			command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
						i, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
			for (j = 0; j < p->num_sectors; j++)
			{
				char *erase_state, *protect_state;

				if (p->sectors[j].is_erased == 0)
					erase_state = "not erased";
				else if (p->sectors[j].is_erased == 1)
					erase_state = "erased";
				else
					erase_state = "erase state unknown";

				if (p->sectors[j].is_protected == 0)
					protect_state = "not protected";
				else if (p->sectors[j].is_protected == 1)
					protect_state = "protected";
				else
					protect_state = "protection state unknown";

				command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%x %ikB) %s, %s",
							j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size>>10,
							erase_state, protect_state);
			}

			*buf = '\0'; /* initialize buffer, otherwise it migh contain garbage if driver function fails */
			retval = p->driver->info(p, buf, sizeof(buf));
			command_print(cmd_ctx, "%s", buf);
			if (retval != ERROR_OK)
				ERROR("error retrieving flash info (%d)", retval);
		}
	}

	return ERROR_OK;
}

int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int retval;

	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	p = get_flash_bank_by_num_noprobe(strtoul(args[0], NULL, 0));
	if (p)
	{
		if ((retval = p->driver->probe(p)) == ERROR_OK)
		{
			command_print(cmd_ctx, "flash '%s' found at 0x%8.8x", p->driver->name, p->base);
		}
		else if (retval == ERROR_FLASH_BANK_INVALID)
		{
			command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8x",
						  args[0], p->base);
		}
		else
		{
			command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8x",
						  args[0], p->base);
		}
	}
	else
	{
		command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
	}

	return ERROR_OK;
}

int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int retval;

	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
	if (p)
	{
		if ((retval = p->driver->erase_check(p)) == ERROR_OK)
		{
			command_print(cmd_ctx, "successfully checked erase state", p->driver->name, p->base);
		}
		else
		{
			command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8x",
				args[0], p->base);
		}
	}

	return ERROR_OK;
}

int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int retval;
	int address;
	int length;
	duration_t duration;
	char *duration_text;

	target_t *target = get_current_target(cmd_ctx);

	if (argc != 2)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	address = strtoul(args[0], NULL, 0);
	length = strtoul(args[1], NULL, 0);
	if (length <= 0)
	{
		command_print(cmd_ctx, "Length must be >0");
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	p = get_flash_bank_by_addr(target, address);
	if (p == NULL)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	/* We can't know if we did a resume + halt, in which case we no longer know the erased state */
	flash_set_dirty();

	duration_start_measure(&duration);

	if ((retval = flash_erase_address_range(target, address, length)) == ERROR_OK)
	{
		duration_stop_measure(&duration, &duration_text);
		command_print(cmd_ctx, "erased address 0x%8.8x length %i in %s", address, length, duration_text);
		free(duration_text);
	}

	return retval;
}

int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int retval;

	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
	if (p)
	{
		if ((retval = p->driver->protect_check(p)) == ERROR_OK)
		{
			command_print(cmd_ctx, "successfully checked protect state");
		}
		else if (retval == ERROR_FLASH_OPERATION_FAILED)
		{
			command_print(cmd_ctx, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8x", args[0], p->base);
		}
		else
		{
			command_print(cmd_ctx, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8x", args[0], p->base);
		}
	}
	else
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	return ERROR_OK;
}

int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	if (argc > 2)
	{
		int first = strtoul(args[1], NULL, 0);
		int last = strtoul(args[2], NULL, 0);
		int retval;
		flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
		duration_t duration;
		char *duration_text;

		duration_start_measure(&duration);

		if (!p)
		{
			return ERROR_COMMAND_SYNTAX_ERROR;
		}

		if ((retval = flash_driver_erase(p, first, last)) == ERROR_OK)
		{
			duration_stop_measure(&duration, &duration_text);

			command_print(cmd_ctx, "erased sectors %i through %i on flash bank %i in %s", first, last, strtoul(args[0], 0, 0), duration_text);
			free(duration_text);
		}
	}
	else
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	return ERROR_OK;
}

int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	if (argc > 3)
	{
		int first = strtoul(args[1], NULL, 0);
		int last = strtoul(args[2], NULL, 0);
		int set;
		int retval;
		flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
		if (!p)
		{
			command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
			return ERROR_OK;
		}

		if (strcmp(args[3], "on") == 0)
			set = 1;
		else if (strcmp(args[3], "off") == 0)
			set = 0;
		else
		{
			return ERROR_COMMAND_SYNTAX_ERROR;
		}

		retval = flash_driver_protect(p, set, first, last);
		if (retval == ERROR_OK)
		{
			command_print(cmd_ctx, "%s protection for sectors %i through %i on flash bank %i", (set) ? "set" : "cleared", first, last, strtoul(args[0], 0, 0));
		}
	}
	else
	{
		return ERROR_COMMAND_SYNTAX_ERROR;

	}

	return ERROR_OK;
}

int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	target_t *target = get_current_target(cmd_ctx);

	image_t image;
	u32 written;

	duration_t duration;
	char *duration_text;

	int retval;

	if (argc < 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;

	}

	if (!target)
	{
		ERROR("no target selected");
		return ERROR_OK;
	}

	duration_start_measure(&duration);

	if (argc >= 2)
	{
		image.base_address_set = 1;
		image.base_address = strtoul(args[1], NULL, 0);
	}
	else
	{
		image.base_address_set = 0;
		image.base_address = 0x0;
	}

	image.start_address_set = 0;

	retval = image_open(&image, args[0], (argc == 3) ? args[2] : NULL);
	if (retval != ERROR_OK)
	{
		return retval;
	}

	retval = flash_write(target, &image, &written, auto_erase);

	if (retval != ERROR_OK)
	{
		image_close(&image);
		return retval;
	}

	duration_stop_measure(&duration, &duration_text);
	if (retval == ERROR_OK)
	{
	command_print(cmd_ctx, "wrote %u byte from file %s in %s (%f kb/s)",
		written, args[0], duration_text,
		(float)written / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
	}
	free(duration_text);

	image_close(&image);

	return retval;
}

int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	u32 offset;
	u8 *buffer;
	u32 buf_cnt;

	fileio_t fileio;

	duration_t duration;
	char *duration_text;

	int retval;
	flash_bank_t *p;

	if (argc != 3)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	duration_start_measure(&duration);

	offset = strtoul(args[2], NULL, 0);
	p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
	if (!p)
	{
		command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
		return ERROR_OK;
	}

	if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
	{
		return ERROR_OK;
	}

	buffer = malloc(fileio.size);
	if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK)
	{
		return ERROR_OK;
	}

	retval = flash_driver_write(p, buffer, offset, buf_cnt);

	free(buffer);

	duration_stop_measure(&duration, &duration_text);
	if (retval!=ERROR_OK)
	{
	command_print(cmd_ctx, "wrote  %"PRIi64" byte from file %s to flash bank %i at offset 0x%8.8x in %s (%f kb/s)",
		fileio.size, args[1], strtoul(args[0], NULL, 0), offset, duration_text,
		(float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
	}
	free(duration_text);

	fileio_close(&fileio);

	return retval;
}

void flash_set_dirty(void)
{
	flash_bank_t *c;
	int i;

	/* set all flash to require erasing */
	for (c = flash_banks; c; c = c->next)
	{
		for (i = 0; i < c->num_sectors; i++)
		{
			c->sectors[i].is_erased = 0;
		}
	}
}

/* lookup flash bank by address */
flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr)
{
	flash_bank_t *c;

	/* cycle through bank list */
	for (c = flash_banks; c; c = c->next)
	{
		int retval;
		retval = c->driver->auto_probe(c);

		if (retval != ERROR_OK)
		{
			ERROR("auto_probe failed %d\n", retval);
			return NULL;
		}
		/* check whether address belongs to this flash bank */
		if ((addr >= c->base) && (addr < c->base + c->size) && target == c->target)
			return c;
	}
	ERROR("No flash at address 0x%08x\n", addr);
	return NULL;
}

/* erase given flash region, selects proper bank according to target and address */
int flash_erase_address_range(target_t *target, u32 addr, u32 length)
{
	flash_bank_t *c;
	int first = -1;
	int last = -1;
	int i;

	if ((c = get_flash_bank_by_addr(target, addr)) == NULL)
		return ERROR_FLASH_DST_OUT_OF_BANK; /* no corresponding bank found */

	if (c->size == 0 || c->num_sectors == 0)
		return ERROR_FLASH_BANK_INVALID;

	if (length == 0)
	{
		/* special case, erase whole bank when length is zero */
		if (addr != c->base)
			return ERROR_FLASH_DST_BREAKS_ALIGNMENT;

		return flash_driver_erase(c, 0, c->num_sectors - 1);
	}

	/* check whether it fits */
	if (addr + length > c->base + c->size)
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;

	addr -= c->base;

	for (i = 0; i < c->num_sectors; i++)
	{
		/* check whether sector overlaps with the given range and is not yet erased */
		if (addr < c->sectors[i].offset + c->sectors[i].size && addr + length > c->sectors[i].offset && c->sectors[i].is_erased != 1) {
			/* if first is not set yet then this is the first sector */
			if (first == -1)
				first = i;
			last = i; /* and it is the last one so far in any case */
		}
	}

	if( first == -1 || last == -1 )
		return ERROR_OK;

	return flash_driver_erase(c, first, last);
}

/* write (optional verify) an image to flash memory of the given target */
int flash_write(target_t *target, image_t *image, u32 *written, int erase)
{
	int retval;

	int section;
	u32 section_offset;
	flash_bank_t *c;

	section = 0;
	section_offset = 0;

	if (written)
		*written = 0;

	if (erase)
	{
		/* assume all sectors need erasing - stops any problems
		 * when flash_write is called multiple times */

		flash_set_dirty();
	}

	/* loop until we reach end of the image */
	while (section < image->num_sections)
	{
		u32 buffer_size;
		u8 *buffer;
		int section_first;
		int section_last;
		u32 run_address = image->sections[section].base_address + section_offset;
		u32 run_size = image->sections[section].size - section_offset;

		if (image->sections[section].size ==  0)
		{
			WARNING("empty section %d", section);
			section++;
			section_offset = 0;
			continue;
		}

		/* find the corresponding flash bank */
		if ((c = get_flash_bank_by_addr(target, run_address)) == NULL)
		{
			section++; /* and skip it */
			section_offset = 0;
			continue;
		}

		/* collect consecutive sections which fall into the same bank */
		section_first = section;
		section_last = section;
		while ((run_address + run_size < c->base + c->size)
				&& (section_last + 1 < image->num_sections))
		{
			if (image->sections[section_last + 1].base_address < (run_address + run_size))
			{
				DEBUG("section %d out of order(very slightly surprising, but supported)", section_last + 1);
				break;
			}
			if (image->sections[section_last + 1].base_address != (run_address + run_size))
				break;
			run_size += image->sections[++section_last].size;
		}

		/* fit the run into bank constraints */
		if (run_address + run_size > c->base + c->size)
			run_size = c->base + c->size - run_address;

		/* allocate buffer */
		buffer = malloc(run_size);
		buffer_size = 0;

		/* read sections to the buffer */
		while (buffer_size < run_size)
		{
			u32 size_read;

			if (buffer_size - run_size <= image->sections[section].size - section_offset)
				size_read = buffer_size - run_size;
			else
				size_read = image->sections[section].size - section_offset;

			if ((retval = image_read_section(image, section, section_offset,
					size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
			{
				free(buffer);

				return retval;
			}

			buffer_size += size_read;
			section_offset += size_read;

			if (section_offset >= image->sections[section].size)
			{
				section++;
				section_offset = 0;
			}
		}

		retval = ERROR_OK;

		if (erase)
		{
			/* calculate and erase sectors */
			retval = flash_erase_address_range( target, run_address, run_size );
		}

		if (retval == ERROR_OK)
		{
			/* write flash sectors */
			retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
		}

		free(buffer);

		if (retval != ERROR_OK)
		{
				return retval; /* abort operation */
			}

		if (written != NULL)
			*written += run_size; /* add run size to total written counter */
	}

	return ERROR_OK;
}

int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	if (strcmp(args[0], "on") == 0)
		auto_erase = 1;
	else if (strcmp(args[0], "off") == 0)
		auto_erase = 0;
	else
		return ERROR_COMMAND_SYNTAX_ERROR;

	return ERROR_OK;
}