diff options
Diffstat (limited to 'board/MAI/AmigaOneG3SE/cmd_boota.c')
-rw-r--r-- | board/MAI/AmigaOneG3SE/cmd_boota.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/board/MAI/AmigaOneG3SE/cmd_boota.c b/board/MAI/AmigaOneG3SE/cmd_boota.c new file mode 100644 index 0000000..140aaff --- /dev/null +++ b/board/MAI/AmigaOneG3SE/cmd_boota.c @@ -0,0 +1,123 @@ +#include <common.h> +#include <command.h> +#include <cmd_boota.h> +#include "../disk/part_amiga.h" +#include <asm/cache.h> + + +#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) { + DECLARE_GLOBAL_DATA_PTR; + + 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; +} |