Enscript Output

extractedLnx/linux/arch/m68k/boot/atari/bootstrap.c_main.c

int main(int argc, char *argv[])
{
    int debugflag = 0, ch, kfd, rfd = -1, i, ignore_ttram = 0;
    int load_to_stram = 0;
    char *ramdisk_name, *kernel_name, *memptr;
    u_long ST_ramsize, TT_ramsize, memreq;
    u_long cpu_type, fpu_type, mch_type, mint;
    struct exec kexec;
    int elf_kernel = 0;
    Elf32_Ehdr kexec_elf;
    Elf32_Phdr *kernel_phdrs = NULL;
    u_long start_mem, mem_size, rd_size, text_offset = 0, kernel_size;
    int prefer_bootp = 1, kname_set = 0, n_knames;
#ifdef USE_BOOTP
    int err;
#endif
    char kname_list[5][64];
    void *bi_ptr;

    ramdisk_name = NULL;
    kernel_name = "vmlinux";

    /* print the startup message */
    puts("\fLinux/68k Atari Bootstrap version 2.2"
#ifdef USE_BOOTP
	 " (with BOOTP)"
#endif
	 );
    puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries, Roman Hodek, Andreas Schwab\n");

	/* ++roman: If no arguments on the command line, read them from
	 * file */
	if (argc == 1)
		get_default_args( &argc, &argv );

    /* machine is Atari */
    bi.machtype = MACH_ATARI;

    /* check arguments */
    while ((ch = getopt(argc, argv, "bdtsk:r:")) != EOF)
	switch (ch) {
	  case 'd':
	    debugflag = 1;
	    break;
	  case 't':
	    ignore_ttram = 1;
	    break;
	  case 's':
	    load_to_stram = 1;
	    break;
	  case 'k':
	    kernel_name = optarg;
	    kname_set = 1;
	    break;
	  case 'r':
	    ramdisk_name = optarg;
	    break;
	  case 'b':
	    prefer_bootp = 0;
	    break;
	  case '?':
	  default:
	    usage();
	}

    argc -= optind;
    argv += optind;
  
    /* We have to access some system variables to get
     * the information we need, so we must switch to
     * supervisor mode first.
     */
    userstk = Super(0L);

    /* get the info we need from the cookie-jar */
    cookiejar = *_p_cookies;
    if(cookiejar == 0L) {
	/* if we find no cookies, it's probably an ST */
	fprintf(stderr, "Error: No cookiejar found. Is this an ST?\n");
	boot_exit(EXIT_FAILURE);
    }

    /* Exit if MiNT/MultiTOS is running.  */
    if(getcookie("MiNT", &mint) != -1)
    {
	puts("Warning: MiNT is running\n");
#if 0
	puts("Linux cannot be started when MiNT is running. Aborting...\n");
	boot_exit(EXIT_FAILURE);
#endif
    }

    /* get _CPU, _FPU and _MCH */
    getcookie("_CPU", &cpu_type);
    getcookie("_FPU", &fpu_type);
    getcookie("_MCH", &mch_type);

    /* check if we are on a 68030/40 with FPU */
    if ((cpu_type != 30 && cpu_type != 40 && cpu_type != 60))
    {
	puts("Machine type currently not supported. Aborting...");
	boot_exit(EXIT_FAILURE);
    }

    switch(cpu_type) {
      case  0:
      case 10: break;
      case 20: bi.cputype = CPU_68020; bi.mmutype = MMU_68851; break;
      case 30: bi.cputype = CPU_68030; bi.mmutype = MMU_68030; break;
      case 40: bi.cputype = CPU_68040; bi.mmutype = MMU_68040; break;
      case 60: bi.cputype = CPU_68060; bi.mmutype = MMU_68060; break;
      default:
	fprintf(stderr, "Error: Unknown CPU type. Aborting...\n");
	boot_exit(EXIT_FAILURE);
	break;
    }

    printf("CPU: %ld; ", cpu_type + 68000);
    printf("FPU: ");

    /* check for FPU; in case of a '040 or '060, don't look at _FPU itself,
     * some software may set it to wrong values (68882 or the like) */
	if (cpu_type == 40) {
		bi.fputype = FPU_68040;
		puts( "68040\n" );
	}
	else if (cpu_type == 60) {
		bi.fputype = FPU_68060;
		puts( "68060\n" );
	}
	else {
		switch ((fpu_type >> 16) & 7) {
		  case 0:
			puts("not present\n");
			break;
		  case 1:
			puts("SFP004 not supported. Assuming no FPU.");
			break;
		  case 2:
			/* try to determine real type */
			if (fpu_idle_frame_size () != 0x18)
				goto m68882;
			/* fall through */
		  case 4:
			bi.fputype = FPU_68881;
			puts("68881\n");
			break;
		  case 6:
		  m68882:
			bi.fputype = FPU_68882;
			puts("68882\n");
			break;
		  default:
			puts("Unknown FPU type. Assuming no FPU.");
			break;
		}
	}
	/* ++roman: If an FPU was announced in the cookie, test
	   whether it is a real hardware FPU or a software emulator!  */
	if (bi.fputype) {
		if (test_software_fpu()) {
			bi.fputype = 0;
			puts("FPU: software emulated. Assuming no FPU.");
		}
	}

    /* Get the amounts of ST- and TT-RAM. */
    /* The size must be a multiple of 1MB. */
    i = 0;
	
    if (!test_medusa()) {
	struct {
		unsigned short version;   /* version - currently 1 */
		unsigned long fr_start; /* start addr FastRAM */
		unsigned long fr_len;   /* length FastRAM */
	} *magn_cookie;
	struct {
		unsigned long version;
		unsigned long fr_start; /* start addr */
		unsigned long fr_len;   /* length */
	} *fx_cookie;

        TT_ramsize = 0;
        if (!ignore_ttram) {
	    /* "Original" or properly emulated TT-Ram */
	    if (*ramtop) {
		/* the 'ramtop' variable at 0x05a4 is not
		 * officially documented. We use it anyway
		 * because it is the only way to get the TTram size.
		 * (It is zero if there is no TTram.)
		 */
		bi.memory[i].addr = TT_RAM_BASE;
		bi.memory[i].size = (*ramtop - TT_RAM_BASE) & ~(MB - 1);
		TT_ramsize = bi.memory[i].size / MB;
		i++;
		printf("TT-RAM: %ld Mb; ", TT_ramsize);
	    }

	    /* test for MAGNUM alternate RAM
	     * added 26.9.1995 M. Schwingen, rincewind@discworld.oche.de
	     */
	    if (getcookie("MAGN", (u_long *)&magn_cookie) != -1) {
		bi.memory[i].addr = magn_cookie->fr_start;
		bi.memory[i].size = magn_cookie->fr_len & ~(MB - 1);
		TT_ramsize += bi.memory[i].size / MB;
		printf("MAGNUM alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
		i++;
	    }

	    /* BlowUps FX */
	    if (getcookie("BPFX", (u_long *)&fx_cookie) != -1 && fx_cookie) {
		/* if fx is set (cookie call above),
		 * we assume that BlowUps FX-card
		 * is installed. (Nat!)
		 */
		bi.memory[i].addr = fx_cookie->fr_start;
		bi.memory[i].size = fx_cookie->fr_len & ~(MB - 1);
		printf("FX alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
		i++;
	    }
	}

        bi.memory[i].addr = 0;
        bi.memory[i].size = *phystop & ~(MB - 1);
        ST_ramsize = bi.memory[i].size / MB;
        i++;
        printf("ST-RAM: %ld Mb\n", ST_ramsize );

        bi.num_memory = i;

	if (load_to_stram && i > 1) {
	    /* Put ST-RAM first in the list of mem blocks */
	    struct mem_info temp = bi.memory[i - 1];
	    bi.memory[i - 1] = bi.memory[0];
	    bi.memory[0] = temp;
	}
    }
    else {
        u_long	bank1, bank2, medusa_st_ram;

        get_medusa_bank_sizes( &bank1, &bank2 );
	medusa_st_ram = *phystop & ~(MB - 1);
        bank1 -= medusa_st_ram;
        TT_ramsize = 0;

        bi.memory[i].addr = 0;
        bi.memory[i].size = medusa_st_ram;
        ST_ramsize = bi.memory[i].size / MB;
        i++;
        printf("Medusa pseudo ST-RAM from bank 1: %ld Mb; ", ST_ramsize );

        if (!ignore_ttram && bank1 > 0) {
            bi.memory[i].addr = 0x20000000 + medusa_st_ram;
            bi.memory[i].size = bank1;
            TT_ramsize += bank1;
            i++;
            printf("TT-RAM bank 1: %ld Mb; ", bank1/MB );
        }
			
        if (!ignore_ttram && bank2 > 0) {
            bi.memory[i].addr = 0x24000000;
            bi.memory[i].size = bank2;
            TT_ramsize += bank2;
            i++;
            printf("TT-RAM bank 2: %ld Mb; ", bank2/MB );
        }
			
        bi.num_memory = i;
        printf("\n");
    }

    /* verify that there is enough RAM; ST- and TT-RAM combined */
    if (ST_ramsize + TT_ramsize < MIN_RAMSIZE) {
	puts("Not enough RAM. Aborting...");
	boot_exit(10);
    }

#if 0	
    /* Get language/keyboard info */
    /* TODO: do we need this ? */
    /* Could be used to auto-select keyboard map later on. (rdv) */
    if (getcookie("_AKP",&language) == -1)
    {
	/* Get the language info from the OS-header */
	os_header = *_sysbase;
	os_header = os_header->os_beg;
	lang = (os_header->os_conf) >> 1;
	printf("Language: ");
	switch(lang) {
	  case HOL: puts("Dutch"); break; /* Own country first :-) */
	  case USA: puts("American"); break;
	  case SWG: puts("Switzerland (German)"); break;
	  case FRG: puts("German"); break;
	  case FRA: puts("French"); break;
	  case SWF: puts("Switzerland (French)"); break;
	  case UK:  puts("English"); break;
	  case SPA: puts("Spanish"); break;
	  case ITA: puts("Italian"); break;
	  case SWE: puts("Swedish"); break;
	  case TUR: puts("Turkey"); break;
	  case FIN: puts("Finnish"); break;
	  case NOR: puts("Norwegian"); break;
	  case DEN: puts("Danish"); break;
	  case SAU: puts("Saudi-Arabian"); break;
	  default:  puts("Unknown"); break;
	}
    }
    else
    {
	printf("Language: ");
	switch(language & 0x0F)
	{
	  case 1: printf("German "); break;
	  case 2: printf("French "); break;
	  case 4: printf("Spanish "); break;
	  case 5: printf("Italian "); break;
	  case 7: printf("Swiss French "); break;
	  case 8: printf("Swiss German "); break;
	  default: printf("English ");
	}
	printf("Keyboard type :");
	switch(language >> 8)
	{
	  case 1: printf("German "); break;
	  case 2: printf("French "); break;
	  case 4: printf("Spanish "); break;
	  case 5: printf("Italian "); break;
	  case 7: printf("Swiss French "); break;
	  case 8: printf("Swiss German "); break;
	  default: printf("English ");
	}
	printf("\n");
    }
#endif
	
    /* Pass contents of the _MCH cookie to the kernel */
    bi.mch_cookie = mch_type;
    
    /*
     * Copy command line options into the kernel command line.
     */
    i = 0;
    while (argc--) {
	if ((i+strlen(*argv)+1) < CL_SIZE) {
	    i += strlen(*argv) + 1;
	    if (bi.command_line[0])
		strcat (bi.command_line, " ");
	    strcat (bi.command_line, *argv++);
	}
    }
    printf ("Command line is '%s'\n", bi.command_line);

    start_mem = bi.memory[0].addr;
    mem_size = bi.memory[0].size;

    /* tell us where the kernel will go */
    printf("\nThe kernel will be located at 0x%08lx\n", start_mem);

#ifdef TEST
    /*
    ** Temporary exit point for testing
    */
    boot_exit(-1);
#endif /* TEST */

    i = 0;
#ifdef USE_BOOTP
    if (!kname_set)
	kname_list[i++][0] = '\0'; /* default kernel which BOOTP server says */
#endif
#ifdef ZKERNEL
    strcpy( kname_list[i], kernel_name );
    strcat( kname_list[i], ".gz" );
    ++i;
#endif
    strcpy( kname_list[i++], kernel_name );
#ifdef ZKERNEL
    if (!kname_set)
	strcpy( kname_list[i++], "vmlinuz" );
#endif
    n_knames = i;

    kfd = -1;
#ifdef USE_BOOTP
    if (prefer_bootp) {
	for( i = 0; i < n_knames; ++i ) {
	    if ((err = get_remote_kernel( kname_list[i] )) >= 0)
		goto kernel_open;
	    if (err < -1) /* fatal error; retries don't help... */
		break;
	}
	printf( "\nremote boot failed; trying local kernel\n" );
    }
#endif
    for( i = 0; i < n_knames; ++i ) {
	if ((kfd = open( kname_list[i], O_RDONLY )) != -1)
	    goto kernel_open;
    }
#ifdef USE_BOOTP
    if (!prefer_bootp) {
	printf( "\nlocal kernel failed; trying remote boot\n" );
	for( i = 0; i < n_knames; ++i ) {
	    if ((err = get_remote_kernel( kname_list[i] )) >= 0)
		goto kernel_open;
	    if (err < -1) /* fatal error; retries don't help... */
		break;
	}
    }
#endif
    fprintf( stderr, "Unable to open any kernel file\n(Tried " );
    for( i = 0; i < n_knames; ++i ) {
	fprintf( stderr, "%s%s", kname_list[i],
		 i <  n_knames-2 ? ", " :
		 i == n_knames-2 ? ", and " :
		 ")\n" );
    }
    boot_exit( EXIT_FAILURE );
    
  kernel_open:

    if (kread (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec))
    {
	fprintf (stderr, "Unable to read exec header from %s\n", kernel_name);
	boot_exit (EXIT_FAILURE);
    }

#ifdef ZKERNEL
    if (((unsigned char *)&kexec)[0] == 037 &&
	(((unsigned char *)&kexec)[1] == 0213 ||
	 ((unsigned char *)&kexec)[1] == 0236)) {
	/* That's a compressed kernel */
	printf( "Kernel is compressed\n" );
	if (load_zkernel( kfd )) {
	    printf( "Decompression error -- aborting\n" );
	    boot_exit( EXIT_FAILURE );
	}
    }
#endif
    
    switch (N_MAGIC(kexec)) {
    case ZMAGIC:
	text_offset = N_TXTOFF(kexec);
	break;
    case QMAGIC:
	text_offset = sizeof(kexec);
	/* the text size includes the exec header; remove this */
	kexec.a_text -= sizeof(kexec);
	break;
    default:
	/* Try to parse it as an ELF header */
	klseek (kfd, 0, SEEK_SET);
	if (kread (kfd, (void *)&kexec_elf, sizeof (kexec_elf)) == sizeof (kexec_elf)
	    && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)
	  {
	    elf_kernel = 1;
	    /* A few plausibility checks */
	    if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K
		|| kexec_elf.e_version != EV_CURRENT)
	      {
		fprintf (stderr, "Invalid ELF header contents in kernel\n");
		boot_exit (EXIT_FAILURE);
	      }
	    /* Load the program headers */
	    kernel_phdrs = (Elf32_Phdr *) Malloc (kexec_elf.e_phnum * sizeof (Elf32_Phdr));
	    if (kernel_phdrs == NULL)
	      {
		fprintf (stderr, "Unable to allocate memory for program headers\n");
		boot_exit (EXIT_FAILURE);
	      }
	    klseek (kfd, kexec_elf.e_phoff, SEEK_SET);
	    if (kread (kfd, (void *) kernel_phdrs,
		      kexec_elf.e_phnum * sizeof (*kernel_phdrs))
		!= kexec_elf.e_phnum * sizeof (*kernel_phdrs))
	      {
		fprintf (stderr, "Unable to read program headers from %s\n",
			 kernel_name);
		boot_exit (EXIT_FAILURE);
	      }
	    break;
	  }
	fprintf (stderr, "Wrong magic number %lo in kernel header\n",
		 N_MAGIC(kexec));
	boot_exit (EXIT_FAILURE);
    }

    /* Load the kernel one page after start of mem */
    start_mem += PAGE_SIZE;
    mem_size -= PAGE_SIZE;
    /* Align bss size to multiple of four */
    if (!elf_kernel)
      kexec.a_bss = (kexec.a_bss + 3) & ~3;

    /* init ramdisk */
    if(ramdisk_name) {
	if((rfd = open(ramdisk_name, O_RDONLY)) == -1) {
	    fprintf(stderr, "Unable to open ramdisk file %s\n",
		    ramdisk_name);
	    boot_exit(EXIT_FAILURE);
	}
	bi.ramdisk.size = lseek(rfd, 0, SEEK_END);
    }
    else
	bi.ramdisk.size = 0;
 
    /* calculate the total required amount of memory */
    if (elf_kernel)
      {
	u_long min_addr = 0xffffffff, max_addr = 0;
	for (i = 0; i < kexec_elf.e_phnum; i++)
	  {
	    if (min_addr > kernel_phdrs[i].p_vaddr)
	      min_addr = kernel_phdrs[i].p_vaddr;
	    if (max_addr < kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz)
	      max_addr = kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz;
	  }
	/* This is needed for newer linkers that include the header in
	   the first segment.  */
	if (min_addr == 0)
	  {
	    min_addr = PAGE_SIZE;
	    kernel_phdrs[0].p_vaddr += PAGE_SIZE;
	    kernel_phdrs[0].p_offset += PAGE_SIZE;
	    kernel_phdrs[0].p_filesz -= PAGE_SIZE;
	    kernel_phdrs[0].p_memsz -= PAGE_SIZE;
	  }
	kernel_size = max_addr - min_addr;
      }
    else
      kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss;

    rd_size = bi.ramdisk.size;
    if (rd_size + kernel_size > mem_size - MB/2 && bi.num_memory > 1)
      /* If running low on ST ram load ramdisk into alternate ram.  */
      bi.ramdisk.addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size;
    else
      /* Else hopefully there is enough ST ram. */
      bi.ramdisk.addr = (u_long)start_mem + mem_size - rd_size;

    /* create the bootinfo structure */
    if (!create_bootinfo())
	boot_exit (EXIT_FAILURE);

    memreq = kernel_size + bi_size;
#ifdef BOOTINFO_COMPAT_1_0
    if (sizeof(compat_bootinfo) > bi_size)
	memreq = kernel_size+sizeof(compat_bootinfo);
#endif /* BOOTINFO_COMPAT_1_0 */
    /* align load address of ramdisk image, read() is sloooow on odd addr. */
    memreq = ((memreq + 3) & ~3) + rd_size;
	
    /* allocate RAM for the kernel */
    if (!(memptr = (char *)Malloc (memreq)))
    {
	fprintf (stderr, "Unable to allocate memory for kernel and ramdisk\n");
	boot_exit (EXIT_FAILURE);
    }
    else
	fprintf(stderr, "kernel at address %lx\n", (u_long) memptr);

    (void)memset(memptr, 0, memreq);

    /* read the text and data segments from the kernel image */
    if (elf_kernel)
      {
	for (i = 0; i < kexec_elf.e_phnum; i++)
	  {
	    if (klseek (kfd, kernel_phdrs[i].p_offset, SEEK_SET) == -1)
	      {
		fprintf (stderr, "Failed to seek to segment %d\n", i);
		boot_exit (EXIT_FAILURE);
	      }
	    if (kread (kfd, memptr + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
		      kernel_phdrs[i].p_filesz)
		!= kernel_phdrs[i].p_filesz)
	      {
		fprintf (stderr, "Failed to read segment %d\n", i);
		boot_exit (EXIT_FAILURE);
	      }
	  }
      }
    else
      {
	if (klseek (kfd, text_offset, SEEK_SET) == -1)
	{
	    fprintf (stderr, "Failed to seek to text\n");
	    Mfree ((void *)memptr);
	    boot_exit (EXIT_FAILURE);
	}

	if (kread (kfd, memptr, kexec.a_text) != kexec.a_text)
	{
	    fprintf (stderr, "Failed to read text\n");
	    Mfree ((void *)memptr);
	    boot_exit (EXIT_FAILURE);
	}

	/* data follows immediately after text */
	if (kread (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data)
	{
	    fprintf (stderr, "Failed to read data\n");
	    Mfree ((void *)memptr);
	    boot_exit (EXIT_FAILURE);
	}
      }
    kclose (kfd);

    /* Check kernel's bootinfo version */
    switch (check_bootinfo_version(memptr)) {
	case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION):
	    bi_ptr = &bi_union.record;
	    break;

#ifdef BOOTINFO_COMPAT_1_0
	case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION):
	    if (!create_compat_bootinfo()) {
		Mfree ((void *)memptr);
		boot_exit (EXIT_FAILURE);
	    }
	    bi_ptr = &compat_bootinfo;
	    bi_size = sizeof(compat_bootinfo);
	    break;
#endif /* BOOTINFO_COMPAT_1_0 */

	default:
	    Mfree ((void *)memptr);
	    boot_exit (EXIT_FAILURE);
    }

    /* copy the boot_info struct to the end of the kernel image */
    memcpy ((void *)(memptr + kernel_size), bi_ptr, bi_size);

    /* read the ramdisk image */
    if (rfd != -1)
    {
	if (lseek (rfd, 0, SEEK_SET) == -1)
	{
	    fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
	    Mfree ((void *)memptr);
	    boot_exit (EXIT_FAILURE);
	}
	if (read (rfd, memptr + memreq - rd_size,
		  rd_size) != rd_size)
	{
	    fprintf (stderr, "Failed to read ramdisk file\n");
	    Mfree ((void *)memptr);
	    boot_exit (EXIT_FAILURE);
	}
	close (rfd);
    }

    /* for those who want to debug */
    if (debugflag)
    {
	if (bi.ramdisk.size)
	    printf ("RAM disk at %#lx, size is %ld\n",
		    (u_long)(memptr + memreq - rd_size),
		    bi.ramdisk.size);

	if (elf_kernel)
	  {
	    for (i = 0; i < kexec_elf.e_phnum; i++)
	      {
		printf ("Kernel segment %d at %#lx, size %ld\n", i,
			start_mem + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
			kernel_phdrs[i].p_memsz);
	      }
	  }
	else
	  {
	    printf ("\nKernel text at %#lx, code size %d\n",
		    start_mem, kexec.a_text);
	    printf ("Kernel data at %#lx, data size %d\n",
		    start_mem + kexec.a_text, kexec.a_data );
	    printf ("Kernel bss  at %#lx, bss  size %d\n",
		    start_mem + kexec.a_text + kexec.a_data, kexec.a_bss );
	  }
	printf ("\nboot_info is at %#lx\n",
		start_mem + kernel_size);
	printf ("\nKernel entry is %#lx\n",
		elf_kernel ? kexec_elf.e_entry : kexec.a_entry);
	printf ("ramdisk dest top is %#lx\n", bi.ramdisk.addr + rd_size);
	printf ("ramdisk lower limit is %#lx\n",
		(u_long)(memptr + memreq - rd_size));
	printf ("ramdisk src top is %#lx\n", (u_long)(memptr + memreq));

	printf ("Type a key to continue the Linux boot...");
	fflush (stdout);
	getchar();
    }

    printf("Booting Linux...\n");

    sync ();

    /* turn off interrupts... */
    disable_interrupts();

    /* turn off caches... */
    disable_cache();

    /* ..and any MMU translation */
    disable_mmu();

    /* ++guenther: allow reset if launched with MiNT */
    *(long*)0x426 = 0;

    /* copy mover code to a safe place if needed */
    memcpy ((void *) 0x400, &copyall, &copyallend - &copyall);

    /* setup stack */
    change_stack ((void *) PAGE_SIZE);

    /*
     * On the Atari you can have two situations:
     * 1. One piece of contiguous RAM (Falcon)
     * 2. Two pieces of contiguous RAM (TT)
     * In case 2 you can load your program into ST-ram and load your data in
     * any old RAM you have left.
     * In case 1 you could overwrite your own program when copying the
     * kernel and ramdisk to their final positions.
     * To solve this the mover code is copied to a safe place first.
     * Then this program jumps to the mover code. After the mover code
     * has finished it jumps to the start of the kernel in its new position.
     * I thought the memory just after the interrupt vector table was a safe
     * place because it is used by TOS to store some system variables.
     * This range goes from 0x400 to approx. 0x5B0.
     * This is more than enough for the miniscule mover routine (16 bytes).
     */

    jump_to_mover((char *) start_mem, memptr,
		  (char *) bi.ramdisk.addr + rd_size, memptr + memreq,
		  kernel_size + bi_size, rd_size,
		  (void *) 0x400);

    for (;;);
    /* NOTREACHED */
}

Generated by GNU enscript 1.6.4.