|
|
|
#include <common.h>
|
|
|
|
#include <command.h>
|
|
|
|
#include "../disk/part_amiga.h"
|
|
|
|
#include <asm/cache.h>
|
|
|
|
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
|
|
|
|
#undef BOOTA_DEBUG
|
|
|
|
|
|
|
|
#ifdef BOOTA_DEBUG
|
|
|
|
#define PRINTF(fmt,args...) printf (fmt ,##args)
|
|
|
|
#else
|
|
|
|
#define PRINTF(fmt,args...)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct block_header {
|
|
|
|
u32 id;
|
|
|
|
u32 summed_longs;
|
|
|
|
s32 chk_sum;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern block_dev_desc_t *ide_get_dev (int dev);
|
|
|
|
extern struct bootcode_block *get_bootcode (block_dev_desc_t * dev_desc);
|
|
|
|
extern int sum_block (struct block_header *header);
|
|
|
|
|
|
|
|
struct bootcode_block bblk;
|
|
|
|
|
|
|
|
int do_boota (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
unsigned char *load_address = (unsigned char *) CFG_LOAD_ADDR;
|
|
|
|
unsigned char *base_address;
|
|
|
|
unsigned long offset;
|
|
|
|
|
|
|
|
unsigned long part_number = 0;
|
|
|
|
block_dev_desc_t *boot_disk;
|
|
|
|
char *s;
|
|
|
|
struct bootcode_block *boot_code;
|
|
|
|
|
|
|
|
/* Get parameters */
|
|
|
|
|
|
|
|
switch (argc) {
|
|
|
|
case 2:
|
|
|
|
load_address = (unsigned char *) simple_strtol (argv[1], NULL, 16);
|
|
|
|
part_number = 0;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
load_address = (unsigned char *) simple_strtol (argv[1], NULL, 16);
|
|
|
|
part_number = simple_strtol (argv[2], NULL, 16);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
base_address = load_address;
|
|
|
|
|
|
|
|
PRINTF ("Loading boot code from disk %d to %p\n", part_number,
|
|
|
|
load_address);
|
|
|
|
|
|
|
|
/* Find the appropriate disk device */
|
|
|
|
boot_disk = ide_get_dev (part_number);
|
|
|
|
if (!boot_disk) {
|
|
|
|
PRINTF ("Unknown disk %d\n", part_number);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the bootcode block */
|
|
|
|
boot_code = get_bootcode (boot_disk);
|
|
|
|
if (!boot_code) {
|
|
|
|
PRINTF ("Not a bootable disk %d\n", part_number);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only use the offset from the first block */
|
|
|
|
offset = boot_code->load_data[0];
|
|
|
|
memcpy (load_address, &boot_code->load_data[1], 122 * 4);
|
|
|
|
load_address += 122 * 4;
|
|
|
|
|
|
|
|
/* Setup for the loop */
|
|
|
|
bblk.next = boot_code->next;
|
|
|
|
boot_code = &bblk;
|
|
|
|
|
|
|
|
/* Scan the chain, and copy the loader succesively into the destination area */
|
|
|
|
while (0xffffffff != boot_code->next) {
|
|
|
|
PRINTF ("Loading block %d\n", boot_code->next);
|
|
|
|
|
|
|
|
/* Load block */
|
|
|
|
if (1 !=
|
|
|
|
boot_disk->block_read (boot_disk->dev, boot_code->next, 1,
|
|
|
|
(ulong *) & bblk)) {
|
|
|
|
PRINTF ("Read error\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check sum */
|
|
|
|
if (sum_block ((struct block_header *) (ulong *) & bblk) != 0) {
|
|
|
|
PRINTF ("Checksum error\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ok, concatenate it to the already loaded code */
|
|
|
|
memcpy (load_address, boot_code->load_data, 123 * 4);
|
|
|
|
load_address += 123 * 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf ("Bootcode loaded to %p (size %d)\n", base_address,
|
|
|
|
load_address - base_address);
|
|
|
|
printf ("Entry point at %p\n", base_address + offset);
|
|
|
|
|
|
|
|
flush_cache (base_address, load_address - base_address);
|
|
|
|
|
|
|
|
|
|
|
|
s = getenv ("autostart");
|
|
|
|
if (s && strcmp (s, "yes") == 0) {
|
|
|
|
void (*boot) (bd_t *, char *, block_dev_desc_t *);
|
|
|
|
char *args;
|
|
|
|
|
|
|
|
boot = (void (*)(bd_t *, char *, block_dev_desc_t *)) (base_address + offset);
|
|
|
|
boot (gd->bd, getenv ("amiga_bootargs"), boot_disk);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#if defined(CONFIG_AMIGAONEG3SE) && defined(CONFIG_CMD_BSP)
|
|
|
|
U_BOOT_CMD(
|
|
|
|
boota, 3, 1, do_boota,
|
|
|
|
"boota - boot an Amiga kernel\n",
|
|
|
|
"address disk"
|
|
|
|
);
|
|
|
|
#endif /* _CMD_BOOTA_H */
|