This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Hard Fault Handler

Hi

I am trying to implement a lightweight algorithm on nRF52832 Development Kit. When I try to debug the code, it shows "unknown function at address "0x00000A60".  I am attaching the code.

#include "ascon_api.h"
#include "ascon_endian.h"
#include "ascon_permutations.h"
#include "nrf_log.h"

#define RATE (128 / 8)
#define PA_ROUNDS 12
#define PB_ROUNDS 8
#define IV                                                        \
  ((u64)(8 * (CRYPTO_KEYBYTES)) << 56 | (u64)(8 * (RATE)) << 48 | \
   (u64)(PA_ROUNDS) << 40 | (u64)(PB_ROUNDS) << 32)

int ascon_crypto_aead_encrypt(unsigned char* c, unsigned long long* clen,
                        const unsigned char* m, unsigned long long mlen,
                        const unsigned char* ad, unsigned long long adlen,
                        const unsigned char* nsec, const unsigned char* npub,
                        const unsigned char* k) {
                       u32_2 K0, K1, N0, N1;
  u32_2 x0, x1, x2, x3, x4;
  u32_2 t0, t1;
  u64 tmp0, tmp1;
  u32 i;
  (void)nsec;

  // set ciphertext size
  *clen = mlen + CRYPTO_ABYTES;

  // load key and nonce
  to_bit_interleaving(K0, U64BIG(*(u64*)k));
  to_bit_interleaving(K1, U64BIG(*(u64*)(k + 8)));
  to_bit_interleaving(N0, U64BIG(*(u64*)npub));
  to_bit_interleaving(N1, U64BIG(*(u64*)(npub + 8)));

  // initialization
  to_bit_interleaving(x0, IV);
  x1.o = K0.o;
  x1.e = K0.e;
  x2.e = K1.e;
  x2.o = K1.o;
  x3.e = N0.e;
  x3.o = N0.o;
  x4.e = N1.e;
  x4.o = N1.o;
  P12();
  x3.e ^= K0.e;
  x3.o ^= K0.o;
  x4.e ^= K1.e;
  x4.o ^= K1.o;

  // process associated data
  if (adlen) {
    while (adlen >= RATE) {
      to_bit_interleaving(t0, U64BIG(*(u64*)ad));
      x0.e ^= t0.e;
      x0.o ^= t0.o;
      to_bit_interleaving(t1, U64BIG(*(u64*)(ad + 8)));
      x1.e ^= t1.e;
      x1.o ^= t1.o;
      P8();
      adlen -= RATE;
      ad += RATE;
    }
    tmp0 = 0;
    tmp1 = 0;
    for (i = 0; i < adlen; ++i, ++ad)
      if (i < 8)
        tmp0 ^= INS_BYTE64(*ad, i);
      else
        tmp1 ^= INS_BYTE64(*ad, i % 8);
    if (adlen < 8)
      tmp0 ^= INS_BYTE64(0x80, adlen);
    else
      tmp1 ^= INS_BYTE64(0x80, adlen % 8);
    to_bit_interleaving(t0, tmp0);
    x0.e ^= t0.e;
    x0.o ^= t0.o;
    to_bit_interleaving(t1, tmp1);
    x1.e ^= t1.e;
    x1.o ^= t1.o;
    P8();
  }
  x4.e ^= 1;

  // process plaintext
  while (mlen >= RATE) {
    to_bit_interleaving(t0, U64BIG(*(u64*)m));
    x0.e ^= t0.e;
    x0.o ^= t0.o;
    to_bit_interleaving(t1, U64BIG(*(u64*)(m + 8)));
    x1.e ^= t1.e;
    x1.o ^= t1.o;
    from_bit_interleaving(tmp0, x0);
    *(u64*)c = U64BIG(tmp0);
    from_bit_interleaving(tmp1, x1);
    *(u64*)(c + 8) = U64BIG(tmp1);
    P8();
    mlen -= RATE;
    m += RATE;
    c += RATE;
  }
  tmp0 = 0;
  tmp1 = 0;
  for (i = 0; i < mlen; ++i, ++m)
    if (i < 8)
      tmp0 ^= INS_BYTE64(*m, i);
    else
      tmp1 ^= INS_BYTE64(*m, i % 8);
  if (mlen < 8)
    tmp0 ^= INS_BYTE64(0x80, mlen);
  else
    tmp1 ^= INS_BYTE64(0x80, mlen % 8);
  to_bit_interleaving(t0, tmp0);
  x0.e ^= t0.e;
  x0.o ^= t0.o;
  to_bit_interleaving(t1, tmp1);
  x1.e ^= t1.e;
  x1.o ^= t1.o;
  from_bit_interleaving(tmp0, x0);
  from_bit_interleaving(tmp1, x1);
  for (i = 0; i < mlen; ++i, ++c)
    if (i < 8)
      *c = EXT_BYTE64(tmp0, i);
    else
      *c = EXT_BYTE64(tmp1, i % 8);

  // finalization
  x2.e ^= K0.e;
  x2.o ^= K0.o;
  x3.e ^= K1.e;
  x3.o ^= K1.o;
  P12();
  x3.e ^= K0.e;
  x3.o ^= K0.o;
  x4.e ^= K1.e;
  x4.o ^= K1.o;

  // set tag
  from_bit_interleaving(tmp0, x3);
  *(u64*)c = U64BIG(tmp0);
  from_bit_interleaving(tmp1, x4);
 *(u64*)(c + 8) = U64BIG(tmp1);

  return 0;
}

The error comes in the last lines:

" from_bit_interleaving(tmp0, x3);
*(u64*)c = U64BIG(tmp0);
from_bit_interleaving(tmp1, x4);
*(u64*)(c + 8) = U64BIG(tmp1);"

When I try to run further, it shows me "Hard Fault Handler." Here is the apsr register value:

Parents Reply Children
  • In the disassembler, here is the exact instruction: ldr r3, [PC, #4]. PC = 0x00000a60. I am not quite clear on what you mean by checking char* pointer arguments. Should I check that the values these pointers hold are word-aligned? I have checked the value of 'c' in the code. It stores the address where the resultant cipher text has to be placed. It's value is 0x20003cd7. So it is not dividable by 4. How do I change that?

  • That's probably not the exact instruction that triggered the fault. More likely that's the first instruction of the hardfault handler at address 0xa60.

    You are trying to store a 64-bit value to an address pointed to by a char * pointer. You shouldn't do that. You're forcing the compiler to do it with casts. But to store a 64-bit quantity to RAM, the compiler will generate an STRD (STorRe Doubleword) instruction. And there is a restriction with the Cortex-M4 processor that LDRD/STRD instructions can't be misaligned:

    https://developer.arm.com/docs/dui0553/a/the-cortex-m4-instruction-set/about-the-instruction-descriptions/address-alignment

    Note that according to the documentation above, full word loads and stores (LDR/STR) and halfword loads and stores (LDRH/STRH) can handle unaligned accesses, but double-word loads/store can not.

    So if you really need to store the a 64-bit value in your char * array, you have two choices:

    1) Allocate your char * array "c" such that it always starts on an 8-byte aligned address

    2) use a memcpy() to copy the 64-bit value from tmp to the array.

    Oh, also, the reason you're getting a HardFault instead of a UsageFault is that you probably don't have a UsageFault handler installed. There is also a SCB->SHCSR register where you can specifically enable usage fault, bus fault and memory manager faults. If you don't, all of those things will just trigger as a hard fault.

    -Bill

  • Thanks Bill. Will try doing whatever you told.

Related