Beispiel #1
0
int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
                                 uint32_t size)
{
    struct armv7a_common *armv7a = target_to_armv7a(target);
    struct arm_dpm *dpm = armv7a->arm.dpm;
    struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
    uint32_t linelen = armv7a_cache->dminline;
    uint32_t va_line, va_end;
    int retval;

    retval = armv7a_l1_d_cache_sanity_check(target);
    if (retval != ERROR_OK)
        return retval;

    retval = dpm->prepare(dpm);
    if (retval != ERROR_OK)
        goto done;

    va_line = virt & (-linelen);
    va_end = virt + size;

    /* handle unaligned start */
    if (virt != va_line) {
        /* DCCIMVAC */
        retval = dpm->instr_write_data_r0(dpm,
                                          ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
        if (retval != ERROR_OK)
            goto done;
        va_line += linelen;
    }

    /* handle unaligned end */
    if ((va_end & (linelen-1)) != 0) {
        va_end &= (-linelen);
        /* DCCIMVAC */
        retval = dpm->instr_write_data_r0(dpm,
                                          ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end);
        if (retval != ERROR_OK)
            goto done;
    }

    while (va_line < va_end) {
        /* DCIMVAC - Invalidate data cache line by VA to PoC. */
        retval = dpm->instr_write_data_r0(dpm,
                                          ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
        if (retval != ERROR_OK)
            goto done;
        va_line += linelen;
    }

    dpm->finish(dpm);
    return retval;

done:
    LOG_ERROR("d-cache invalidate failed");
    dpm->finish(dpm);

    return retval;
}
Beispiel #2
0
static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl)
{
    int retval = ERROR_OK;
    int32_t c_way, c_index = size->index;

    LOG_DEBUG("cl %" PRId32, cl);
    do {
        c_way = size->way;
        do {
            uint32_t value = (c_index << size->index_shift)
                             | (c_way << size->way_shift) | (cl << 1);
            /*
             * DCCISW - Clean and invalidate data cache
             * line by Set/Way.
             */
            retval = dpm->instr_write_data_r0(dpm,
                                              ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
                                              value);
            if (retval != ERROR_OK)
                goto done;
            c_way -= 1;
        } while (c_way >= 0);
        c_index -= 1;
    } while (c_index >= 0);

done:
    return retval;
}
Beispiel #3
0
int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
                                 uint32_t size)
{
    struct armv7a_common *armv7a = target_to_armv7a(target);
    struct arm_dpm *dpm = armv7a->arm.dpm;
    struct armv7a_cache_common *armv7a_cache =
            &armv7a->armv7a_mmu.armv7a_cache;
    uint32_t linelen = armv7a_cache->iminline;
    uint32_t va_line, va_end;
    int retval;

    retval = armv7a_l1_i_cache_sanity_check(target);
    if (retval != ERROR_OK)
        return retval;

    retval = dpm->prepare(dpm);
    if (retval != ERROR_OK)
        goto done;

    va_line = virt & (-linelen);
    va_end = virt + size;

    while (va_line < va_end) {
        /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
        retval = dpm->instr_write_data_r0(dpm,
                                          ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
        if (retval != ERROR_OK)
            goto done;
        /* BPIMVA */
        retval = dpm->instr_write_data_r0(dpm,
                                          ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line);
        if (retval != ERROR_OK)
            goto done;
        va_line += linelen;
    }
    return retval;

done:
    LOG_ERROR("i-cache invalidate failed");
    dpm->finish(dpm);

    return retval;
}
Beispiel #4
0
/* just read the register -- rely on the core mode being right */
static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
{
	uint32_t value;
	int retval;

	switch (regnum) {
		case 0 ... 14:
			/* return via DCC:  "MCR p14, 0, Rnum, c0, c5, 0" */
			retval = dpm->instr_read_data_dcc(dpm,
				ARMV4_5_MCR(14, 0, regnum, 0, 5, 0),
				&value);
			break;
		case 15:/* PC
			 * "MOV r0, pc"; then return via DCC */
			retval = dpm->instr_read_data_r0(dpm, 0xe1a0000f, &value);

			/* NOTE: this seems like a slightly awkward place to update
			 * this value ... but if the PC gets written (the only way
			 * to change what we compute), the arch spec says subsequent
			 * reads return values which are "unpredictable".  So this
			 * is always right except in those broken-by-intent cases.
			 */
			switch (dpm->arm->core_state) {
				case ARM_STATE_ARM:
					value -= 8;
					break;
				case ARM_STATE_THUMB:
				case ARM_STATE_THUMB_EE:
					value -= 4;
					break;
				case ARM_STATE_JAZELLE:
					/* core-specific ... ? */
					LOG_WARNING("Jazelle PC adjustment unknown");
					break;
			}
			break;
		default:
			/* 16: "MRS r0, CPSR"; then return via DCC
			 * 17: "MRS r0, SPSR"; then return via DCC
			 */
			retval = dpm->instr_read_data_r0(dpm,
				ARMV4_5_MRS(0, regnum & 1),
				&value);
			break;
	}

	if (retval == ERROR_OK) {
		buf_set_u32(r->value, 0, 32, value);
		r->valid = true;
		r->dirty = false;
		LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned) value);
	}

	return retval;
}
Beispiel #5
0
int armv7a_l1_i_cache_inval_all(struct target *target)
{
    struct armv7a_common *armv7a = target_to_armv7a(target);
    struct arm_dpm *dpm = armv7a->arm.dpm;
    int retval;

    retval = armv7a_l1_i_cache_sanity_check(target);
    if (retval != ERROR_OK)
        return retval;

    retval = dpm->prepare(dpm);
    if (retval != ERROR_OK)
        goto done;

    if (target->smp) {
        /* ICIALLUIS */
        retval = dpm->instr_write_data_r0(dpm,
                                          ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
    } else {
        /* ICIALLU */
        retval = dpm->instr_write_data_r0(dpm,
                                          ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
    }

    if (retval != ERROR_OK)
        goto done;

    dpm->finish(dpm);
    return retval;

done:
    LOG_ERROR("i-cache invalidate failed");
    dpm->finish(dpm);

    return retval;
}
Beispiel #6
0
static int arm920t_mcr(struct target *target, int cpnum,
	uint32_t op1, uint32_t op2,
	uint32_t CRn, uint32_t CRm,
	uint32_t value)
{
	if (cpnum != 15) {
		LOG_ERROR("Only cp15 is supported");
		return ERROR_FAIL;
	}

	/* write "from" r0 */
	return arm920t_write_cp15_interpreted(target,
		ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2),
		0, value);
}
Beispiel #7
0
int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
                                 unsigned int size)
{
    struct armv7a_common *armv7a = target_to_armv7a(target);
    struct arm_dpm *dpm = armv7a->arm.dpm;
    struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
    uint32_t linelen = armv7a_cache->dminline;
    uint32_t va_line, va_end;
    int retval;

    retval = armv7a_l1_d_cache_sanity_check(target);
    if (retval != ERROR_OK)
        return retval;

    retval = dpm->prepare(dpm);
    if (retval != ERROR_OK)
        goto done;

    va_line = virt & (-linelen);
    va_end = virt + size;

    while (va_line < va_end) {
        /* DCCIMVAC */
        retval = dpm->instr_write_data_r0(dpm,
                                          ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
        if (retval != ERROR_OK)
            goto done;
        va_line += linelen;
    }

    dpm->finish(dpm);
    return retval;

done:
    LOG_ERROR("d-cache invalidate failed");
    dpm->finish(dpm);

    return retval;
}
Beispiel #8
0
static int dpm_mcr(struct target *target, int cpnum,
	uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
	uint32_t value)
{
	struct arm *arm = target_to_arm(target);
	struct arm_dpm *dpm = arm->dpm;
	int retval;

	retval = dpm->prepare(dpm);
	if (retval != ERROR_OK)
		return retval;

	LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum,
		(int) op1, (int) CRn,
		(int) CRm, (int) op2);

	/* read DCC into r0; then write coprocessor register from R0 */
	retval = dpm->instr_write_data_r0(dpm,
			ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2),
			value);

	/* (void) */ dpm->finish(dpm);
	return retval;
}
Beispiel #9
0
/** Writes a buffer, in the specified word size, with current MMU settings. */
int arm920t_write_memory(struct target *target, uint32_t address,
		uint32_t size, uint32_t count, uint8_t *buffer)
{
	int retval;
	const uint32_t cache_mask = ~0x1f; /* cache line size : 32 byte */
	struct arm920t_common *arm920t = target_to_arm920(target);

	/* FIX!!!! this should be cleaned up and made much more general. The
	 * plan is to write up and test on arm920t specifically and
	 * then generalize and clean up afterwards.
	 *
	 * Also it should be moved to the callbacks that handle breakpoints
	 * specifically and not the generic memory write fn's. See XScale code.
	 */
	if (arm920t->armv4_5_mmu.mmu_enabled && (count == 1) &&
			((size==2) || (size==4)))
	{
		/* special case the handling of single word writes to
		 * bypass MMU, to allow implementation of breakpoints
		 * in memory marked read only
		 * by MMU
		 */
		uint32_t cb;
		uint32_t pa;

		/*
		 * We need physical address and cb
		 */
		retval = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu,
				address, &cb, &pa);
		if (retval != ERROR_OK)
			return retval;

		if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
		{
			if (cb & 0x1)
			{
				LOG_DEBUG("D-Cache buffered, "
						"drain write buffer");
				/*
				 * Buffered ?
				 * Drain write buffer - MCR p15,0,Rd,c7,c10,4
				 */

				retval = arm920t_write_cp15_interpreted(target,
					ARMV4_5_MCR(15, 0, 0, 7, 10, 4),
					0x0, 0);
				if (retval != ERROR_OK)
					return retval;
			}

			if (cb == 0x3)
			{
				/*
				 * Write back memory ? -> clean cache
				 *
				 * There is no way to clean cache lines using
				 * cp15 scan chain, so copy the full cache
				 * line from cache to physical memory.
				 */
				uint8_t data[32];

				LOG_DEBUG("D-Cache in 'write back' mode, "
						"flush cache line");

				retval = target_read_memory(target,
						address & cache_mask, 1,
						sizeof(data), &data[0]);
				if (retval != ERROR_OK)
					return retval;

				retval = armv4_5_mmu_write_physical(target,
						&arm920t->armv4_5_mmu,
						pa & cache_mask, 1,
						sizeof(data), &data[0]);
				if (retval != ERROR_OK)
					return retval;
			}

			/* Cached ? */
			if (cb & 0x2)
			{
				/*
				 * Cached ? -> Invalidate data cache using MVA
				 *
				 * MCR p15,0,Rd,c7,c6,1
				 */
				LOG_DEBUG("D-Cache enabled, "
					"invalidate cache line");

				retval = arm920t_write_cp15_interpreted(target,
					ARMV4_5_MCR(15, 0, 0, 7, 6, 1), 0x0,
					address & cache_mask);
				if (retval != ERROR_OK)
					return retval;
			}
		}

		/* write directly to physical memory,
		 * bypassing any read only MMU bits, etc.
		 */
		retval = armv4_5_mmu_write_physical(target,
				&arm920t->armv4_5_mmu, pa, size,
				count, buffer);
		if (retval != ERROR_OK)
			return retval;
	} else
	{
		if ((retval = arm7_9_write_memory(target, address,
					size, count, buffer)) != ERROR_OK)
			return retval;
	}

	/* If ICache is enabled, we have to invalidate affected ICache lines
	 * the DCache is forced to write-through,
	 * so we don't have to clean it here
	 */
	if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled)
	{
		if (count <= 1)
		{
			/* invalidate ICache single entry with MVA
			 *   mcr	15, 0, r0, cr7, cr5, {1}
			 */
			LOG_DEBUG("I-Cache enabled, "
				"invalidating affected I-Cache line");
			retval = arm920t_write_cp15_interpreted(target,
					ARMV4_5_MCR(15, 0, 0, 7, 5, 1),
					0x0, address & cache_mask);
			if (retval != ERROR_OK)
				return retval;
		}
		else
		{
			/* invalidate ICache
			 *  mcr	15, 0, r0, cr7, cr5, {0}
			 */
			retval = arm920t_write_cp15_interpreted(target,
					ARMV4_5_MCR(15, 0, 0, 7, 5, 0),
					0x0, 0x0);
			if (retval != ERROR_OK)
				return retval;
		}
	}

	return ERROR_OK;
}
static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t value)
{
	struct arm_dpm *dpm = &armv8->dpm;
	int retval;

	switch (regnum) {
	case ARMV8_R0 ... ARMV8_R14:
		/* load register from DCC:  "MRC p14, 0, Rnum, c0, c5, 0" */
		retval = dpm->instr_write_data_dcc(dpm,
				ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), value);
		break;
	case ARMV8_SP:
		retval = dpm->instr_write_data_dcc(dpm,
				ARMV4_5_MRC(14, 0, 13, 0, 5, 0), value);
			break;
	case ARMV8_PC:/* PC
		 * read r0 from DCC; then "MOV pc, r0" */
		retval = dpm->instr_write_data_r0(dpm,
				ARMV8_MCR_DLR(0), value);
		break;
	case ARMV8_xPSR: /* CPSR */
		/* read r0 from DCC, then "MCR r0, DSPSR" */
		retval = dpm->instr_write_data_r0(dpm,
				ARMV8_MCR_DSPSR(0), value);
		break;
	case ARMV8_ELR_EL1: /* mapped to LR_svc */
		retval = dpm->instr_write_data_dcc(dpm,
				ARMV4_5_MRC(14, 0, 14, 0, 5, 0),
				value);
		break;
	case ARMV8_ELR_EL2: /* mapped to ELR_hyp */
		retval = dpm->instr_write_data_r0(dpm,
				ARMV8_MSR_GP_T1(0, 14, 0, 1),
				value);
		break;
	case ARMV8_ELR_EL3: /* mapped to LR_mon */
		retval = dpm->instr_write_data_dcc(dpm,
				ARMV4_5_MRC(14, 0, 14, 0, 5, 0),
				value);
		break;
	case ARMV8_ESR_EL1: /* mapped to DFSR */
		retval = dpm->instr_write_data_r0(dpm,
				ARMV4_5_MCR(15, 0, 0, 5, 0, 0),
				value);
		break;
	case ARMV8_ESR_EL2: /* mapped to HSR */
		retval = dpm->instr_write_data_r0(dpm,
				ARMV4_5_MCR(15, 4, 0, 5, 2, 0),
				value);
		break;
	case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */
		retval = ERROR_FAIL;
		break;
	case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */
		retval = dpm->instr_write_data_r0(dpm,
				ARMV8_MSR_GP_xPSR_T1(1, 0, 15),
				value);
		break;
	case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */
		retval = dpm->instr_write_data_r0(dpm,
				ARMV8_MSR_GP_xPSR_T1(1, 0, 15),
				value);
		break;
	case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */
		retval = dpm->instr_write_data_r0(dpm,
				ARMV8_MSR_GP_xPSR_T1(1, 0, 15),
				value);
		break;
	default:
		retval = ERROR_FAIL;
		break;
	}

	return retval;

}
static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *regval)
{
	struct arm_dpm *dpm = &armv8->dpm;
	uint32_t value = 0;
	int retval;

	switch (regnum) {
	case ARMV8_R0 ... ARMV8_R14:
		/* return via DCC:  "MCR p14, 0, Rnum, c0, c5, 0" */
		retval = dpm->instr_read_data_dcc(dpm,
			ARMV4_5_MCR(14, 0, regnum, 0, 5, 0),
			&value);
		break;
	case ARMV8_SP:
		retval = dpm->instr_read_data_dcc(dpm,
			ARMV4_5_MCR(14, 0, 13, 0, 5, 0),
			&value);
		break;
	case ARMV8_PC:
		retval = dpm->instr_read_data_r0(dpm,
			ARMV8_MRC_DLR(0),
			&value);
		break;
	case ARMV8_xPSR:
		retval = dpm->instr_read_data_r0(dpm,
			ARMV8_MRC_DSPSR(0),
			&value);
		break;
	case ARMV8_ELR_EL1: /* mapped to LR_svc */
		retval = dpm->instr_read_data_dcc(dpm,
				ARMV4_5_MCR(14, 0, 14, 0, 5, 0),
				&value);
		break;
	case ARMV8_ELR_EL2: /* mapped to ELR_hyp */
		retval = dpm->instr_read_data_r0(dpm,
				ARMV8_MRS_T1(0, 14, 0, 1),
				&value);
		break;
	case ARMV8_ELR_EL3: /* mapped to LR_mon */
		retval = dpm->instr_read_data_dcc(dpm,
				ARMV4_5_MCR(14, 0, 14, 0, 5, 0),
				&value);
		break;
	case ARMV8_ESR_EL1: /* mapped to DFSR */
		retval = dpm->instr_read_data_r0(dpm,
				ARMV4_5_MRC(15, 0, 0, 5, 0, 0),
				&value);
		break;
	case ARMV8_ESR_EL2: /* mapped to HSR */
		retval = dpm->instr_read_data_r0(dpm,
				ARMV4_5_MRC(15, 4, 0, 5, 2, 0),
				&value);
		break;
	case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */
		retval = ERROR_FAIL;
		break;
	case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */
		retval = dpm->instr_read_data_r0(dpm,
				ARMV8_MRS_xPSR_T1(1, 0),
				&value);
		break;
	case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */
		retval = dpm->instr_read_data_r0(dpm,
				ARMV8_MRS_xPSR_T1(1, 0),
				&value);
		break;
	case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */
		retval = dpm->instr_read_data_r0(dpm,
				ARMV8_MRS_xPSR_T1(1, 0),
				&value);
		break;
	default:
		retval = ERROR_FAIL;
		break;
	}

	if (retval == ERROR_OK && regval != NULL)
		*regval = value;

	return retval;
}