wdenk | c7de829 | 2002-11-19 11:04:11 +0000 | [diff] [blame^] | 1 | #include <common.h> |
| 2 | #include <command.h> |
| 3 | #include <cmd_boota.h> |
| 4 | #include "../disk/part_amiga.h" |
| 5 | #include <asm/cache.h> |
| 6 | |
| 7 | |
| 8 | #undef BOOTA_DEBUG |
| 9 | |
| 10 | #ifdef BOOTA_DEBUG |
| 11 | #define PRINTF(fmt,args...) printf (fmt ,##args) |
| 12 | #else |
| 13 | #define PRINTF(fmt,args...) |
| 14 | #endif |
| 15 | |
| 16 | struct block_header { |
| 17 | u32 id; |
| 18 | u32 summed_longs; |
| 19 | s32 chk_sum; |
| 20 | }; |
| 21 | |
| 22 | extern block_dev_desc_t *ide_get_dev (int dev); |
| 23 | extern struct bootcode_block *get_bootcode (block_dev_desc_t * dev_desc); |
| 24 | extern int sum_block (struct block_header *header); |
| 25 | |
| 26 | struct bootcode_block bblk; |
| 27 | |
| 28 | int do_boota (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) |
| 29 | { |
| 30 | unsigned char *load_address = (unsigned char *) CFG_LOAD_ADDR; |
| 31 | unsigned char *base_address; |
| 32 | unsigned long offset; |
| 33 | |
| 34 | unsigned long part_number = 0; |
| 35 | block_dev_desc_t *boot_disk; |
| 36 | char *s; |
| 37 | struct bootcode_block *boot_code; |
| 38 | |
| 39 | /* Get parameters */ |
| 40 | |
| 41 | switch (argc) { |
| 42 | case 2: |
| 43 | load_address = (unsigned char *) simple_strtol (argv[1], NULL, 16); |
| 44 | part_number = 0; |
| 45 | break; |
| 46 | case 3: |
| 47 | load_address = (unsigned char *) simple_strtol (argv[1], NULL, 16); |
| 48 | part_number = simple_strtol (argv[2], NULL, 16); |
| 49 | break; |
| 50 | } |
| 51 | |
| 52 | base_address = load_address; |
| 53 | |
| 54 | PRINTF ("Loading boot code from disk %d to %p\n", part_number, |
| 55 | load_address); |
| 56 | |
| 57 | /* Find the appropriate disk device */ |
| 58 | boot_disk = ide_get_dev (part_number); |
| 59 | if (!boot_disk) { |
| 60 | PRINTF ("Unknown disk %d\n", part_number); |
| 61 | return 1; |
| 62 | } |
| 63 | |
| 64 | /* Find the bootcode block */ |
| 65 | boot_code = get_bootcode (boot_disk); |
| 66 | if (!boot_code) { |
| 67 | PRINTF ("Not a bootable disk %d\n", part_number); |
| 68 | return 1; |
| 69 | } |
| 70 | |
| 71 | /* Only use the offset from the first block */ |
| 72 | offset = boot_code->load_data[0]; |
| 73 | memcpy (load_address, &boot_code->load_data[1], 122 * 4); |
| 74 | load_address += 122 * 4; |
| 75 | |
| 76 | /* Setup for the loop */ |
| 77 | bblk.next = boot_code->next; |
| 78 | boot_code = &bblk; |
| 79 | |
| 80 | /* Scan the chain, and copy the loader succesively into the destination area */ |
| 81 | while (0xffffffff != boot_code->next) { |
| 82 | PRINTF ("Loading block %d\n", boot_code->next); |
| 83 | |
| 84 | /* Load block */ |
| 85 | if (1 != |
| 86 | boot_disk->block_read (boot_disk->dev, boot_code->next, 1, |
| 87 | (ulong *) & bblk)) { |
| 88 | PRINTF ("Read error\n"); |
| 89 | return 1; |
| 90 | } |
| 91 | |
| 92 | /* check sum */ |
| 93 | if (sum_block ((struct block_header *) (ulong *) & bblk) != 0) { |
| 94 | PRINTF ("Checksum error\n"); |
| 95 | return 1; |
| 96 | } |
| 97 | |
| 98 | /* Ok, concatenate it to the already loaded code */ |
| 99 | memcpy (load_address, boot_code->load_data, 123 * 4); |
| 100 | load_address += 123 * 4; |
| 101 | } |
| 102 | |
| 103 | printf ("Bootcode loaded to %p (size %d)\n", base_address, |
| 104 | load_address - base_address); |
| 105 | printf ("Entry point at %p\n", base_address + offset); |
| 106 | |
| 107 | flush_cache (base_address, load_address - base_address); |
| 108 | |
| 109 | |
| 110 | s = getenv ("autostart"); |
| 111 | if (s && strcmp (s, "yes") == 0) { |
| 112 | DECLARE_GLOBAL_DATA_PTR; |
| 113 | |
| 114 | void (*boot) (bd_t *, char *, block_dev_desc_t *); |
| 115 | char *args; |
| 116 | |
| 117 | boot = (void (*)(bd_t *, char *, block_dev_desc_t *)) (base_address + offset); |
| 118 | boot (gd->bd, getenv ("amiga_bootargs"), boot_disk); |
| 119 | } |
| 120 | |
| 121 | |
| 122 | return 0; |
| 123 | } |