Ok took a bit longer than waited, here is whats happened anyway:
What I wanted was a totally quieted (I'm very picky when coming to noise) file server, at least when not in use. Still wanted plenty of space without paying a ton of money (ie no ssd) and I didn't want to add an external drive either. So my plan was to bootup a b3 on usb instead of mechanical hdd.
1. Step one was to disassemble a b3 and trying to figure out how it booted.
After checking some datasheets for the marvell CPU
http://www.marvell.com/embedded-process ... Source.pdf
http://www.marvell.com/embedded-process ... Source.pdf
and checking pins sampled during startup I could see that b3 boots up on a serial flash on the board. Not suprising since I already spotted the flash
2. To be sure not to destroy anything the next step was to dump the SPI-flash. I know I could have done that in Linux, but where would the fun be with that, so I used a buspirate. Also, by dumping the flash by external hardware I knew I could restore it the same way. If I did something wrong Linux would definitely not bootup.
I lifted Vcc from its pad and soldered a couple of wires to the chip so I could attach the buspirate. Some pins I could access with the small clips on my testwire directly.
3. The first block contains the bootheader, so I did a small program (see end of post for code) to decode that and check the CRC. To see that I could trust the dump.
Code: Select all
Decoding file...
Boot from: SPI(0x5A)
ECC algorithm (valid for nand only):default, based on pagesize
NAND page size (valid for nand only): 0
block size to load into RAM: 210104(205kB)
image offset: 512
dest address in DDR: 134217728
execution address on DDR or SPI (incase of direct boot): 134217728
An extra header of 480bytes is appended directly after the main header
checksum correct
4. Ok so the dumped looked ok and I should be ok if I messed anything up. Next step was to solder an UART connection on the board. As you can see above post you can find the UART on a couple of testpoints on the board, I also found it in a couple of pinheader holes and the port on the back (for production test maybe??). I used a pinheader so I could deattach the cable if I wanted.
5. Ok ready to go. Booting into uboot and changing the configuration to boot on usb instead of SATA. I kept the SATA boot as backup. These was the environment variables that I changed:
setenv bootalt2 'run sataboot || reset'
setenv bootalt3 'run usbinstall || run usbflash || run sataboot || reset'
setenv bootalt1 'run usbroot || reset'
setenv setusbargs 'setenv bootargs root=/dev/sdb1 console=$console,$baudrate serial=${serial#} key=$key button=$button rootdelay=5'
setenv usbroot 'usb start; run setusbargs; ext2load $usbinstalldev $loadaddr /boot/$bootfile; bootm'
setenv bootcmd
The bootalt3 will never be used (without recompiling uboot), its just the old bootalt2 kept as a backup. For some reason I got very strange results with this. I had to save it twice, with a restart in between. Otherwise bootcmd was invalid (had traces of other variables in it). Also note the rootdelay to allow linux to found the usb memory.
6. Ok I need a usb stick with correct rfs and kernel. I kept it simpel and just copied my current RFS/kernel and changing root in fstab. Also played with the time options to allow spindown. Found a physically small usb-stick of 16Gb (to allow some wear levelling).
7. Configure the HDD to spin down when not used with hddparm and relax
Code: Select all
root@bubba:/home/thommy# mount
/dev/sdb1 on / type ext3 (rw,noatime)
tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
udev on /dev type tmpfs (rw,mode=0755)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620)
/dev/mapper/bubba-storage on /home type ext3 (rw,relatime)
usbfs on /proc/bus/usb type usbfs (rw)
root@bubba:/home/thommy#
root@bubba:/home/thommy# hdparm -C /dev/sda
/dev/sda:
drive state is: standby
Code for checking bootblock in flash:
Code: Select all
#include <stdio.h>
int main(int argc, char **argv)
{
FILE *f = NULL;
char unsigned buffer[32];
unsigned short *shortp;
unsigned long *longp;
unsigned char calc_checksum=0;
int i;
if(argc<2){
printf("usage: %s image\r\n",argv[0]);
return 0;
}
f = fopen(argv[1],"r");
if(!f){
perror("unable to open file: ");
return 0;
}
if(32 != fread(buffer,1,32,f)){
perror("unable to read from file: ");
return 0;
}
printf("Decoding file...\r\n");
printf("Boot from: ");
switch (buffer[0])
{
case 0x5A:
printf("SPI(0x5A)\r\n");
break;
case 0x8B:
printf("NAND(0x8B)\r\n");
break;
case 0x78:
printf("SATA(0x78)\r\n");
break;
case 0x9C:
printf("PEX(0x9C)\r\n");
break;
case 0x69:
printf("UART0(0x69)\r\n");
break;
default:
printf("unknown %u\r\n",buffer[0]);
break;
}
printf("ECC algorithm (valid for nand only):");
switch (buffer[1])
{
case 0x0:
printf("default, based on pagesize\r\n");
break;
case 0x1:
printf("force hamming\r\n");
break;
case 0x2:
printf("force RS\r\n");
break;
case 0x3:
printf("disabled\r\n");
break;
default:
printf("unknown\r\n");
break;
}
shortp = (short*)&buffer[2];
printf("NAND page size (valid for nand only): %d\r\n",*shortp);
longp = (long*)&buffer[4];
printf("block size to load into RAM: %lu(%lukB)\r\n",*longp,*longp/1024);
if(buffer[0x8]!=0 || buffer[0x9]!=0 || buffer[0xa]!=0 || buffer[0xb]!=0)
printf("warning, reserved fields not zero\r\n");
longp = (long*)&buffer[0xC];
printf("image offset: %lu\r\n",*longp);
longp = (long*)&buffer[0x10];
printf("dest address in DDR: %lu\r\n",*longp);
if(*longp == 0xFFFFFFFF){
printf("dest address is 0xFFFFFFFF, image booted directly from media\r\n");
}
longp = (long*)&buffer[0x14];
printf("execution address on DDR or SPI (incase of direct boot): %lu\r\n",*longp);
if(buffer[0x18]!=0 || buffer[0x19]!=0 || buffer[0x1a]!=0 || buffer[0x1b]!=0
|| buffer[0x1c]!=0 || buffer[0x1d]!=0 )
printf("warning, reserved fields not zero\r\n");
switch(buffer[0x1E])
{
case 0x0:
printf("No extra header\r\n");
break;
case 0x1:
printf("An extra header of 480bytes is appended directly after the main header\r\n");
break;
default:
printf("unknown value in header extension field\r\n");
break;
}
for(i=0;i<0x1F;i++){
calc_checksum += buffer[i];
}
if(calc_checksum == buffer[0x1F]){
printf("checksum correct\r\n");
}else{
printf("warning: checksum seems to be incorrect. Expected 0x%02X was 0x%02X\r\n",buffer[0x1F],calc_checksum);
}
}