korena's blog

5. Low level init Debugging detour

As I mentioned in the introduction of the previous post, the iROM code always fails to load BL1, regardless of what is in it, the most comfortable way to go is to assume it's a hardware issue, and place the blame on someone other than your own grace, but I paid too much to give up on this development board. I could of course buy a windows licence, and use the tools Samsung and FriendlyARM make available to windows users, but I refuse to do so, not being stubborn or anything, but I need many and more reasons to spend a 100+ USD for an operating system, while Linux exists.

ANALYSIS

The buzzer that is connected to the XPWMTOUT0 pin of S5PV210 tells me that there is an issue with loading BL1, iROM application notes document shows a table that summarizes all possible error codes implemented in iROM code (Table5. ERROR Signal Description). The buzzing sound I get from the buzzer is not conclusive, the sound produced is a dreadful unintelligible noise regardless of the type of error. So I thought it necessary to hook the board to a logic analyzer, and take a look at the shape of the wave produced by the XPWMOUT0 pin. The main issue that concerned me is the lack of information about the produced signal, the table shows the duty cycle, but says nothing about the frequency or time period of the produced signal. The reason why this piece of information is important is the fact that my logic analyzer runs at a lousy maximum frequency of 24Mhz, so knowing the frequency of the to-be measured signal is important.
Since I have no way of finding out what the toggling frequency is, I thought I will just go ahead and try it out.
Hooking a channel from the analyzer to the XPWMTOUT0 pin, a mess of a signal was recorded as the buzzer went off, as expected, there is no pattern to follow.

I attempted this process multiple times, yet no conclusive results were obtained. So I moved on to a slower, but less complex way of figuring out whats wrong.

I started by putting aside the idea that the SD card reader module is broken (hardware issue), and assumed that the issue is caused by software, and since I rolled back to the simplest infinite loop BL1 code, I had no reason to doubt the contents of BL1 code itself, so the error, if it is indeed software caused, would either be in my ImageMake code, or in the process of formatting the MMC card, none of which had changed since I fused the first simple BL1 that does not work anymore. So I needed more insight, which required a peak into the hex data of the flashed MMC card, and what better tool to use for that than the great hexedit , in Linux, you'll probably find this package in the default package manager's repositories, on Debian-like distros:

# apt-get install hexedit

After compiling ridiculouslySimpleStartup.s into BL1.boot, which contains nothing but a useless endless loop, I took a peak inside the resulting hex file (it's actually an ARM executable binary file), so I would know what to look for when peaking inside the MMC card after flashing.

$ hexedit ./BL1.boot

FIGURE 1: hex data of BL1.boot

then I flashed the MMC card with the newly created BL1.boot, using the fuseBin.sh script we wrote a couple of posts back.

$ ./fuseBin.sh
 
mkfs.vfat -F 32 /dev/mmcblk0p1
 
mkfs.vfat 3.0.13 (30 Jun 2012)
 
/dev/mmcblk0p1: Permission denied
 
writing BL1 ...
 
0+1 records in
 
0+1 records out
 
40 bytes (40 B) copied, 0.00887905 s, 4.5 kB/s

had I not been so convinced that it's a hardware issue, the above shell listing should have been enough for me to figure out what was causing the problem (can you?)
When the flashing process was finished, I took a look at the insides of the MMC card using hexedit:

$ sudo hexedit /dev/mmcblk0

FIGURE 2: hexedit of /dev/mmcblk0

The blue box contains the recently flashed BL1.boot (compare it to figure 1), the rest of the MMC memory contains garbage residue data from previous flashes, If the processor actually gets to the point of running the newly flashed BL1.boot code, then there wont be any problem, so long as the code execution through BL1.boot is kept in check, and no out of bounds PC jumps are performed. However, iROM code does not allow the execution of any piece of code within BL1 without checking the integrity of the code using Checksum. As explained in MILESTONE 1, the Checksum value has to be provided (by the system programmer, the one who writes BL1.boot and flashes it) at the third word from the first address of the first physical block (sector) of the SD/MMC card (46060000 in FIGURE 2), the Checksum is calculated by iROM code at boot up, and compared to the value passed, if the two values do not match, an error code will be produced, and BL1 code will not be copied to SRAM for execution, which is precisely whats happening with me here.

FIX

Having figured out what the cause of the issue is, all I had to do is add lines 101 to 105 in the imageMaker.c file. These lines will basically zero out all memory locations covering the whole SRAM memory space dedicated to BL1, so the Checksum calculated by iROM code would not be affected by garbage data residue from previous flashes, simple enough!

#include<stdio.h>
#include<stdint.h>
 
/*=========complimentary defines=========*/
#define REDTEXT  "\x1B[31m"
#define YELLOWTEXT  "\x1B[33m"
 
/*===========Macro defines==============*/
#define max_BL1_length 16384
 
 
#define INPUT  "BL1.bin"
#define OUTPUT  "BL1.boot"
#define BL1_LENGTH (16*1024)
#define DEBUG  1
 
/*===========Prototypes================*/
void checksum_calc(uint32_t *checksum,uint32_t *length);
int makeImage(uint32_t *checksum,uint32_t *length);
void showResults(char *inputFileName,char *outputFileName);
 
 
 
 
int main(int argc,char** argv){
 
  FILE *input = NULL;
  uint32_t checksum = 0;
  uint32_t length = 0;
 
    /*read in BL1.bin,calculate checksum, and get the length while you're at it ...*/
    checksum_calc(&checksum,&length);
  /*check if the file is too big to fit ...*/
  if(length > BL1_LENGTH){
   printf("dude, this thing wont fit! (Size is %d)\n\n",length); 
    return 2;
  }
  /*create the output image*/
  makeImage(&checksum,&length);
   
#ifdef DEBUG
showResults(INPUT,OUTPUT);  
#endif  
  return 0;
}
 
void checksum_calc(uint32_t *checksum,uint32_t *length){
  int guard = 1;
  uint32_t data = 0;
  FILE* file = fopen(INPUT, "rb");
   
  if(file == NULL){
    printf("error opening file\n");
    return;
  }
   
   while (guard = fread(&data, sizeof(uint32_t), 1, file))
 {
  *length += 4;
  *checksum += ((data >> 0) & 0xff);
  *checksum += ((data >> 8) & 0xff);
  *checksum += ((data >> 16) & 0xff);
  *checksum += ((data >> 24) & 0xff); 
 }
  printf("Input File Length: %d Bytes\n", *length);
  printf("Input File Checksum: %d\n", *checksum);
  if (file != NULL) fclose(file);
}
int makeImage(uint32_t *checksum,uint32_t *length){
  FILE *output = NULL;
  FILE *input = NULL;
  int guard = 1;
  uint32_t data = 0;
  uint32_t actualLength = 0;
   
  input=fopen(INPUT, "rb");
  output = fopen(OUTPUT,"wb");
   
  if(output == NULL || input == NULL){
    printf("Error reading file\n\n");
    return 1;
  }
 *length = BL1_LENGTH;
 fwrite(length, sizeof(uint32_t), 1, output);
 fwrite(&data, sizeof(uint32_t), 1, output);
 fwrite(checksum, sizeof(uint32_t), 1, output);
 fwrite(&data, sizeof(uint32_t), 1, output);
 printf("wrote BL1 expected header:\n");
 printf("BL1 length: %d\n",*length);
 printf("Reserved:   %d\n",data);
 printf("BL1 CS:     %d\n",*checksum);
 printf("Reserved:   %d\n",data);
 actualLength = 16;
 while (guard = fread(&data, sizeof(uint32_t), 1, input))
 {
  actualLength += 4;
  fwrite(&data, sizeof(uint32_t), 1, output);
 }
 printf("wrote BL1 data...\n");
  
 data = 0;
 for (; actualLength < (BL1_LENGTH); actualLength += 4)
 {
  fwrite(&data, sizeof(uint32_t), 1, output);
 }
 printf("padding inserted ...\n");
  
if (input != NULL) fclose(input);
if (output != NULL) fclose(output);
  
return 0;
}
 
void showResults(char *inputFileName,char *outputFileName){
   
 FILE *input = NULL;
 FILE *output = NULL;
  uint32_t data;
  int guard = 10;
  int lim = 1;
  input = fopen(inputFileName,"rb");
  output = fopen(outputFileName,"rb");
   
  if(input == NULL || output == NULL){
    printf("ERROR reading files from showResults function ...\n");
    return;
  }
   
  printf("showing the first 10 words of each file ...\n");
   
  printf("%s contents:\n",INPUT);
  while(guard && lim){
    lim = fread(&data,sizeof(uint32_t),1,input);
    printf("0x%08X\n",data);
    guard -= 1;
    }
    guard = 10;
    lim = 1;
  printf("%s contents:\n",OUTPUT);
  while(guard && lim){
    lim = fread(&data,sizeof(uint32_t),1,output);
    printf("0x%08X\n",data);
    guard -= 1;
    }
    fclose(input);
    fclose(output);
}

Conclusion

Having compiled imageMaker.c, using it to modify BL1.bin into BL1.boot gives out the following result in the stdout:

and fusing BL1.boot results in:

Notice the fused 16384 bytes? this is the effect of padding, so there were 40 bytes of actual data (ridiculouslySimpleStartup.s code) and 16344 bytes of zeros. As expected, this fixed the issue, and the annoying buzzer stopped bugging.

Reflecting on this bug we just fixed, the problem with the iROM code is that it asks for the length of the valid code, which can only mean that this length is used in calculating the checksum, so that the checksum calculating routine would not have to run off and sum data until the end of the BL1 designated area, but it does not seem like iROM code is using the length in any way, which is just weird.