| #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 */ |