Home | History | Annotate | Line # | Download | only in boot32
boot32.c revision 1.21
      1 /*	$NetBSD: boot32.c,v 1.21 2006/03/23 21:27:42 bjh21 Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2002 Reinoud Zandijk
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  *
     29  * Thanks a bunch for Ben's framework for the bootloader and its suporting
     30  * libs. This file tries to actually boot NetBSD/acorn32 !
     31  *
     32  * XXX eventually to be partly merged back with boot26 ? XXX
     33  */
     34 
     35 #include <lib/libsa/stand.h>
     36 #include <lib/libsa/loadfile.h>
     37 #include <lib/libkern/libkern.h>
     38 #include <riscoscalls.h>
     39 #include <srt0.h>
     40 #include <sys/boot_flag.h>
     41 #include <machine/vmparam.h>
     42 #include <arm/arm32/pte.h>
     43 #include <machine/bootconfig.h>
     44 
     45 extern char end[];
     46 
     47 /* debugging flags */
     48 int debug = 1;
     49 
     50 
     51 /* constants */
     52 #define PODRAM_START   (512*1024*1024)		/* XXX Kinetic cards XXX */
     53 
     54 #define MAX_RELOCPAGES	4096
     55 
     56 #define DEFAULT_ROOT	"/dev/wd0a"
     57 
     58 
     59 #define IO_BLOCKS	 16	/* move these to the bootloader structure? */
     60 #define ROM_BLOCKS	 16
     61 #define PODRAM_BLOCKS	 16
     62 
     63 
     64 /* booter variables */
     65 char	 scrap[80], twirl_cnt;		/* misc				*/
     66 char	 booted_file[80];
     67 
     68 struct bootconfig *bconfig;		/* bootconfig passing		*/
     69 u_long	 bconfig_new_phys;		/* physical address its bound	*/
     70 
     71 /* computer knowledge		*/
     72 u_int	 monitor_type, monitor_sync, ioeb_flags, lcd_flags;
     73 u_int	 superio_flags, superio_flags_basic, superio_flags_extra;
     74 
     75 /* sizes			*/
     76 int	 nbpp, memory_table_size, memory_image_size;
     77 /* relocate info		*/
     78 u_long	 reloc_tablesize, *reloc_instruction_table;
     79 u_long	*reloc_pos;			/* current empty entry		*/
     80 int	 reloc_entries;			/* number of relocations	*/
     81 int	 first_mapped_DRAM_page_index;	/* offset in RISC OS blob	*/
     82 int	 first_mapped_PODRAM_page_index;/* offset in RISC OS blob	*/
     83 
     84 struct page_info *mem_pages_info;	/* {nr, virt, phys}*		*/
     85 struct page_info *free_relocation_page;	/* points to the page_info chain*/
     86 struct page_info *relocate_table_pages;	/* points to seq. relocate info */
     87 struct page_info *relocate_code_page;	/* points to the copied code	*/
     88 struct page_info *bconfig_page;		/* page for passing on settings	*/
     89 
     90 unsigned char *memory_page_types;	/* packed array of 4 bit typeId	*/
     91 
     92 u_long	*initial_page_tables;		/* pagetables to be booted from	*/
     93 
     94 
     95 /* XXX rename *_BLOCKS to MEM_BLOCKS */
     96 /* DRAM/VRAM/ROM/IO info */
     97 /* where the display is		*/
     98 u_long	 videomem_start, videomem_pages, display_size;
     99 
    100 u_long	 pv_offset, top_physdram;	/* kernel_base - phys. diff	*/
    101 u_long	 top_1Mb_dram;			/* the lower mapped top 1Mb	*/
    102 u_long	 new_L1_pages_phys;		/* physical address of L1 pages	*/
    103 
    104 /* for bootconfig passing	*/
    105 u_long	 total_podram_pages, total_dram_pages, total_vram_pages;
    106 int	 dram_blocks, podram_blocks;	/* number of mem. objects/type  */
    107 int	 vram_blocks, rom_blocks, io_blocks;
    108 
    109 u_long	 DRAM_addr[DRAM_BLOCKS],     DRAM_pages[DRAM_BLOCKS];
    110 /* processor only RAM	*/
    111 u_long	 PODRAM_addr[PODRAM_BLOCKS], PODRAM_pages[PODRAM_BLOCKS];
    112 u_long	 VRAM_addr[VRAM_BLOCKS],     VRAM_pages[VRAM_BLOCKS];
    113 u_long	 ROM_addr[ROM_BLOCKS],       ROM_pages[ROM_BLOCKS];
    114 u_long	 IO_addr[IO_BLOCKS],         IO_pages[IO_BLOCKS];
    115 
    116 
    117 /* RISC OS memory pages we claimed */
    118 u_long	 firstpage, lastpage, totalpages; /* RISC OS pagecounters	*/
    119 /* RISC OS memory		*/
    120 char	*memory_image, *bottom_memory, *top_memory;
    121 
    122 u_long	 videomem_start_ro;		/* for debugging mainly		*/
    123 
    124 /* kernel info */
    125 u_long	 marks[MARK_MAX];		/* loader mark pointers 	*/
    126 u_long	 kernel_physical_start;		/* where does it get relocated	*/
    127 u_long	 kernel_free_vm_start;		/* where does the free VM start	*/
    128 /* some free space to mess with	*/
    129 u_long	 scratch_virtualbase, scratch_physicalbase;
    130 
    131 
    132 /* bootprogram identifiers */
    133 extern const char bootprog_rev[];
    134 extern const char bootprog_name[];
    135 extern const char bootprog_date[];
    136 extern const char bootprog_maker[];
    137 
    138 
    139 /* predefines / prototypes */
    140 void	 init_datastructures(void);
    141 void	 get_memory_configuration(void);
    142 void	 get_memory_map(void);
    143 void	 create_initial_page_tables(void);
    144 void	 add_pagetables_at_top(void);
    145 int	 page_info_cmp(const void *a, const void *);
    146 void	 add_initvectors(void);
    147 void	 create_configuration(int argc, char **argv, int start_args);
    148 void	 prepare_and_check_relocation_system(void);
    149 void	 twirl(void);
    150 int	 vdu_var(int);
    151 void	 process_args(int argc, char **argv, int *howto, char *file,
    152     int *start_args);
    153 
    154 char		 *sprint0(int width, char prefix, char base, int value);
    155 struct page_info *get_relocated_page(u_long destination, int size);
    156 
    157 extern void start_kernel(
    158 		int relocate_code_page,
    159 		int relocation_pv_offset,
    160 		int configuration_structure_in_flat_physical_space,
    161 		int physical_address_of_relocation_tables,
    162 		int physical_address_of_new_L1_pages,
    163 		int kernel_entry_point
    164 		);	/* asm */
    165 
    166 
    167 /* the loader itself */
    168 void init_datastructures(void) {
    169 	/* Get number of pages and the memorytablesize */
    170 	osmemory_read_arrangement_table_size(&memory_table_size, &nbpp);
    171 
    172 	/* Allocate 99% - (small fixed amount) of the heap for memory_image */
    173 	memory_image_size = (int)HIMEM - (int)end - 512 * 1024;
    174 	memory_image_size /= 100;
    175 	memory_image_size *= 99;
    176 	if (memory_image_size <= 256*1024)
    177 		panic("Insufficient memory");
    178 
    179 	memory_image = alloc(memory_image_size);
    180 	if (!memory_image)
    181 		panic("Can't alloc get my memory image ?");
    182 
    183 	bottom_memory = memory_image;
    184 	top_memory    = memory_image + memory_image_size;
    185 
    186 	firstpage  = ((int) bottom_memory / nbpp) + 1;	/* safety */
    187 	lastpage   = ((int) top_memory    / nbpp) - 1;
    188 	totalpages = lastpage - firstpage;
    189 
    190 	printf("Allocated %ld memory pages, each of %d kilobytes.\n\n",
    191 			totalpages, nbpp>>10 );
    192 
    193 	/*
    194 	 * Setup the relocation table. Its a simple array of 3 * 32 bit
    195 	 * entries. The first word in the array is the number of relocations
    196 	 * to be done
    197 	 */
    198 	reloc_tablesize = (MAX_RELOCPAGES+1)*3*sizeof(u_long);
    199 	reloc_instruction_table = alloc(reloc_tablesize);
    200 	if (!reloc_instruction_table)
    201 		panic("Can't alloc my relocate instructions pages");
    202 
    203 	reloc_entries = 0;
    204 	reloc_pos     = reloc_instruction_table;
    205 	*reloc_pos++  = 0;
    206 
    207 	/*
    208 	 * Set up the memory translation info structure. We need to allocate
    209 	 * one more for the end of list marker. See get_memory_map.
    210 	 */
    211 	mem_pages_info = alloc((totalpages + 1)*sizeof(struct page_info));
    212 	if (!mem_pages_info)
    213 		panic("Can't alloc my phys->virt page info");
    214 
    215 	/*
    216 	 * Allocate memory for the memory arrangement table. We use this
    217 	 * structure to retrieve memory page properties to clasify them.
    218 	 */
    219 	memory_page_types = alloc(memory_table_size);
    220 	if (!memory_page_types)
    221 		panic("Can't alloc my memory page type block");
    222 
    223 	/*
    224 	 * Initial page tables is 16 kb per definition since only sections are
    225 	 * used.
    226 	 */
    227 	initial_page_tables = alloc(16*1024);
    228 	if (!initial_page_tables)
    229 		panic("Can't alloc my initial page tables");
    230 }
    231 
    232 
    233 void prepare_and_check_relocation_system(void) {
    234 	int     relocate_size, relocate_pages;
    235 	int     bank, pages, found;
    236 	u_long  dst, src, base, destination, extend;
    237 	u_long *reloc_entry, last_src, length;
    238 
    239 	/* set the number of relocation entries in the 1st word */
    240 	*reloc_instruction_table = reloc_entries;
    241 
    242 	/*
    243 	 * The relocate information needs to be in one sequential physical
    244 	 * space in order to be able to access it as one stream when the MMU
    245 	 * is switched off later.
    246 	 */
    247 	relocate_size = (reloc_tablesize + nbpp-1) & ~(nbpp-1);  /* round up */
    248 	printf("\nPreparing for booting %s ... ", booted_file);
    249 	relocate_pages = relocate_size / nbpp;
    250 
    251 	relocate_table_pages = free_relocation_page;
    252 	pages = 0;
    253 	while (pages < relocate_pages) {
    254 		src = (u_long) reloc_instruction_table + pages*nbpp;
    255 		dst = (relocate_table_pages + pages)->logical;
    256 		memcpy((void *) dst, (void *) src, nbpp);
    257 
    258 		if (pages < relocate_pages-1) {
    259 			/* check if next page is sequential physically */
    260 			if ((relocate_table_pages+pages+1)->physical -
    261 			    (relocate_table_pages+pages)->physical != nbpp) {
    262 				/*
    263 				 * Non contigunous relocate area ->
    264 				 * try again
    265 				 */
    266 				printf("*");
    267 				relocate_table_pages += pages;
    268 				continue;	/* while */
    269 			};
    270 		};
    271 		pages++;
    272 	};
    273 	free_relocation_page = relocate_table_pages + pages;
    274 
    275 	/* copy the relocation code into this page in start_kernel */
    276 	relocate_code_page = free_relocation_page++;
    277 
    278 	/*
    279 	 * All relocations are pages allocated in one big strict increasing
    280 	 * physical DRAM address sequence. When the MMU is switched off all
    281 	 * code and data is in this increasing order but not at the right
    282 	 * place. This is where the relocation code kicks in; relocation is
    283 	 * done in flat physical memory without MMU.
    284 	 */
    285 
    286 	printf("shift and check ... ");
    287 	reloc_entry = reloc_instruction_table + 1;
    288 	last_src = -1;
    289 	while (reloc_entry < reloc_pos) {
    290 		src         = reloc_entry[0];
    291 		destination = reloc_entry[1];
    292 		length      = reloc_entry[2];
    293 
    294 		/* paranoia check */
    295 		if ((long) (src - last_src) <= 0)
    296 			printf("relocation sequence challenged -- "
    297 			    "booting might fail ");
    298 		last_src = src;
    299 
    300 		/* check if its gonna be relocated into (PO)DRAM ! */
    301 		extend = destination + length;
    302 		found = 0;
    303 		for (bank = 0; (bank < dram_blocks) && !found; bank++) {
    304 			base   = DRAM_addr[bank];
    305 			found = (destination >= base) &&
    306 			    (extend <= base + DRAM_pages[bank]*nbpp);
    307 		};
    308 		for (bank = 0; (bank < podram_blocks) && !found; bank++) {
    309 			base = PODRAM_addr[bank];
    310 			found = (destination >= base) &&
    311 			    (extend <= base + PODRAM_pages[bank]*nbpp);
    312 		};
    313 		if (!found || (extend > top_physdram)) {
    314 			panic( "Internal error: relocating range "
    315 			    "[%lx +%lx => %lx] outside (PO)DRAM banks!",
    316 			    src, length, destination
    317 			);
    318 		};
    319 
    320 		reloc_entry+=3;
    321 	};
    322 	if (reloc_entry != reloc_pos)
    323 		panic("Relocation instruction table is corrupted");
    324 
    325 	printf("OK!\n");
    326 }
    327 
    328 
    329 void get_memory_configuration(void) {
    330 	int loop, current_page_type, page_count, phys_page;
    331 	int page, count, bank, top_bank, video_bank;
    332 	int mapped_screen_memory;
    333 	int one_mb_pages;
    334 	u_long top;
    335 
    336 	printf("Getting memory configuration ");
    337 
    338 	osmemory_read_arrangement_table(memory_page_types);
    339 
    340 	/* init counters */
    341 	bank = vram_blocks = dram_blocks = rom_blocks = io_blocks =
    342 	    podram_blocks = 0;
    343 
    344 	current_page_type = -1;
    345 	phys_page = 0;			/* physical address in pages	*/
    346 	page_count = 0;			/* page counter in this block	*/
    347 	loop = 0;			/* loop variable over entries	*/
    348 
    349 	/* iterating over a packed array of 2 page types/byte i.e. 8 kb/byte */
    350 	while (loop < 2*memory_table_size) {
    351 		page = (memory_page_types[loop / 2]);	/* read	twice */
    352 		if (loop & 1) page >>= 4;		/* take other nibble */
    353 
    354 		/*
    355 		 * bits 0-2 give type, bit3 means the bit page is
    356 		 * allocatable
    357 		 */
    358 		page &= 0x7;			/* only take bottom 3 bits */
    359 		if (page != current_page_type) {
    360 			/* passed a boundary ... note this block	   */
    361 			/*
    362 			 * splitting in different vars is for
    363 			 * compatability reasons
    364 			 */
    365 			switch (current_page_type) {
    366 				case -1 :
    367 				case  0 :
    368 					break;
    369 				case osmemory_TYPE_DRAM :
    370 					if (phys_page < PODRAM_START) {
    371 						DRAM_addr[dram_blocks]  =
    372 						    phys_page * nbpp;
    373 						DRAM_pages[dram_blocks] =
    374 						    page_count;
    375 						dram_blocks++;
    376 					} else {
    377 						PODRAM_addr[podram_blocks]  =
    378 						    phys_page * nbpp;
    379 						PODRAM_pages[podram_blocks] =
    380 						    page_count;
    381 						podram_blocks++;
    382 					};
    383 					break;
    384 				case osmemory_TYPE_VRAM :
    385 					VRAM_addr[vram_blocks]  =
    386 					    phys_page * nbpp;
    387 					VRAM_pages[vram_blocks] = page_count;
    388 					vram_blocks++;
    389 					break;
    390 				case osmemory_TYPE_ROM :
    391 					ROM_addr[rom_blocks]  =
    392 					    phys_page * nbpp;
    393 					ROM_pages[rom_blocks] = page_count;
    394 					rom_blocks++;
    395 					break;
    396 				case osmemory_TYPE_IO :
    397 					IO_addr[io_blocks]  = phys_page * nbpp;
    398 					IO_pages[io_blocks] = page_count;
    399 					io_blocks++;
    400 					break;
    401 				default :
    402 					printf("WARNING : found unknown "
    403 					    "memory object %d ",
    404 					    current_page_type);
    405 					printf(" at 0x%s",
    406 					    sprint0(8,'0','x',
    407 						phys_page * nbpp));
    408 					printf(" for %s k\n",
    409 					    sprint0(5,' ','d',
    410 						(page_count*nbpp)>>10));
    411 					break;
    412 			};
    413 			current_page_type = page;
    414 			phys_page = loop;
    415 			page_count = 0;
    416 		};
    417 		/*
    418 		 * smallest unit we recognise is one page ... silly
    419 		 * could be upto 64 pages i.e. 256 kb
    420 		 */
    421 		page_count += 1;
    422 		loop       += 1;
    423 		if ((loop & 31) == 0) twirl();
    424 	};
    425 
    426 	printf(" \n\n");
    427 
    428 	if (VRAM_pages[0] == 0) {
    429 		/* map DRAM as video memory */
    430 		display_size	 = (vdu_var(os_VDUVAR_TOTAL_SCREEN_SIZE) &
    431 		    ~(nbpp-1));
    432 #if 0
    433 		mapped_screen_memory = 1024 * 1024; /* max allowed on RiscPC */
    434 		videomem_pages   = (mapped_screen_memory / nbpp);
    435 		videomem_start   = DRAM_addr[0];
    436 		DRAM_addr[0]	+= videomem_pages * nbpp;
    437 		DRAM_pages[0]	-= videomem_pages;
    438 #else
    439 		mapped_screen_memory = display_size;
    440 		videomem_pages   = (mapped_screen_memory / nbpp);
    441 		one_mb_pages	 = (1024*1024)/nbpp;
    442 
    443 		/*
    444 		 * OK... we need one Mb at the top for compliance with current
    445 		 * kernel structure. This ought to be abolished one day IMHO.
    446 		 * Also we have to take care that the kernel needs to be in
    447 		 * DRAM0a and even has to start there.
    448 		 * XXX one Mb simms are the smallest supported XXX
    449 		 */
    450 		top_bank = dram_blocks-1;
    451 		video_bank = top_bank;
    452 		if (DRAM_pages[top_bank] == one_mb_pages) video_bank--;
    453 
    454 		if (DRAM_pages[video_bank] < videomem_pages)
    455 			panic("Weird memory configuration found; please "
    456 			    "contact acorn32 portmaster.");
    457 
    458 		/* split off the top 1Mb */
    459 		DRAM_addr [top_bank+1]  = DRAM_addr[top_bank] +
    460 		    (DRAM_pages[top_bank] - one_mb_pages)*nbpp;
    461 		DRAM_pages[top_bank+1]  = one_mb_pages;
    462 		DRAM_pages[top_bank  ] -= one_mb_pages;
    463 		dram_blocks++;
    464 
    465 		/* Map video memory at the end of the choosen DIMM */
    466 		videomem_start          = DRAM_addr[video_bank] +
    467 		    (DRAM_pages[video_bank] - videomem_pages)*nbpp;
    468 		DRAM_pages[video_bank] -= videomem_pages;
    469 
    470 		/* sanity */
    471 		if (DRAM_pages[top_bank] == 0) {
    472 			DRAM_addr [top_bank] = DRAM_addr [top_bank+1];
    473 			DRAM_pages[top_bank] = DRAM_pages[top_bank+1];
    474 			dram_blocks--;
    475 		};
    476 #endif
    477 	} else {
    478 		/* use VRAM */
    479 		mapped_screen_memory = 0;
    480 		videomem_start	 = VRAM_addr[0];
    481 		videomem_pages	 = VRAM_pages[0];
    482 		display_size	 = videomem_pages * nbpp;
    483 	};
    484 
    485 	if (mapped_screen_memory) {
    486 		printf("Used %d kb DRAM ", (mapped_screen_memory)/1024);
    487 		printf("at 0x%s for video memory\n",
    488 		    sprint0(8,'0','x', videomem_start));
    489 	};
    490 
    491 	/* find top of (PO)DRAM pages */
    492 	top_physdram = 0;
    493 	for (loop = 0; loop < podram_blocks; loop++) {
    494 		top = PODRAM_addr[loop] + PODRAM_pages[loop]*nbpp;
    495 		if (top > top_physdram) top_physdram = top;
    496 	};
    497 	for (loop = 0; loop < dram_blocks; loop++) {
    498 		top = DRAM_addr[loop] + DRAM_pages[loop]*nbpp;
    499 		if (top > top_physdram) top_physdram = top;
    500 	};
    501 	if (top_physdram == 0)
    502 		panic("reality check: No DRAM in this machine?");
    503 	if (((top_physdram >> 20) << 20) != top_physdram)
    504 		panic("Top is not not aligned on a Mb; "
    505 		    "remove very small DIMMS?");
    506 
    507 	videomem_start_ro = vdu_var(os_VDUVAR_DISPLAY_START);
    508 
    509 	/* pretty print the individual page types */
    510 	for (count = 0; count < rom_blocks; count++) {
    511 		printf("Found ROM  (%d)", count);
    512 		printf(" at 0x%s", sprint0(8,'0','x', ROM_addr[count]));
    513 		printf(" for %s k\n",
    514 		    sprint0(5,' ','d', (ROM_pages[count]*nbpp)>>10));
    515 	};
    516 
    517 	for (count = 0; count < io_blocks; count++) {
    518 		printf("Found I/O  (%d)", count);
    519 		printf(" at 0x%s", sprint0(8,'0','x', IO_addr[count]));
    520 		printf(" for %s k\n",
    521 		    sprint0(5,' ','d', (IO_pages[count]*nbpp)>>10));
    522 	};
    523 
    524 	/* for DRAM/VRAM also count the number of pages */
    525 	total_dram_pages = 0;
    526 	for (count = 0; count < dram_blocks; count++) {
    527 		total_dram_pages += DRAM_pages[count];
    528 		printf("Found DRAM (%d)", count);
    529 		printf(" at 0x%s", sprint0(8,'0','x', DRAM_addr[count]));
    530 		printf(" for %s k\n",
    531 		    sprint0(5,' ','d', (DRAM_pages[count]*nbpp)>>10));
    532 	};
    533 
    534 	total_vram_pages = 0;
    535 	for (count = 0; count < vram_blocks; count++) {
    536 		total_vram_pages += VRAM_pages[count];
    537 		printf("Found VRAM (%d)", count);
    538 		printf(" at 0x%s", sprint0(8,'0','x', VRAM_addr[count]));
    539 		printf(" for %s k\n",
    540 		    sprint0(5,' ','d', (VRAM_pages[count]*nbpp)>>10));
    541 	};
    542 
    543 	total_podram_pages = 0;
    544 	for (count = 0; count < podram_blocks; count++) {
    545 		total_podram_pages += PODRAM_pages[count];
    546 		printf("Found Processor only (S)DRAM (%d)", count);
    547 		printf(" at 0x%s", sprint0(8,'0','x', PODRAM_addr[count]));
    548 		printf(" for %s k\n",
    549 		    sprint0(5,' ','d', (PODRAM_pages[count]*nbpp)>>10));
    550 	};
    551 }
    552 
    553 
    554 void get_memory_map(void) {
    555 	struct page_info *page_info;
    556 	int	page, inout;
    557 	int	phys_addr;
    558 
    559 	printf("\nGetting actual memorymapping");
    560 	for (page = 0, page_info = mem_pages_info;
    561 	     page < totalpages;
    562 	     page++, page_info++) {
    563 		page_info->pagenumber = 0;	/* not used */
    564 		page_info->logical    = (firstpage + page) * nbpp;
    565 		page_info->physical   = 0;	/* result comes here */
    566 		/* to avoid triggering a `bug' in RISC OS 4, page it in */
    567 		*((int *) page_info->logical) = 0;
    568 	};
    569 	/* close list */
    570 	page_info->pagenumber = -1;
    571 
    572 	inout = osmemory_GIVEN_LOG_ADDR | osmemory_RETURN_PAGE_NO |
    573 	    osmemory_RETURN_PHYS_ADDR;
    574 	osmemory_page_op(inout, mem_pages_info, totalpages);
    575 
    576 	printf(" ; sorting ");
    577 	qsort(mem_pages_info, totalpages, sizeof(struct page_info),
    578 	    &page_info_cmp);
    579 	printf(".\n");
    580 
    581 	/*
    582 	 * get the first DRAM index and show the physical memory
    583 	 * fragments we got
    584 	 */
    585 	printf("\nFound physical memory blocks :\n");
    586 	first_mapped_DRAM_page_index = -1;
    587 	first_mapped_PODRAM_page_index = -1;
    588 	for (page=0; page < totalpages; page++) {
    589 		phys_addr = mem_pages_info[page].physical;
    590 		printf("[0x%x", phys_addr);
    591 		while (mem_pages_info[page+1].physical - phys_addr == nbpp) {
    592 			if ((first_mapped_DRAM_page_index<0) &&
    593 			    (phys_addr >= DRAM_addr[0])) {
    594 				first_mapped_DRAM_page_index = page;
    595 			};
    596 			if ((first_mapped_PODRAM_page_index<0) &&
    597 			    (phys_addr >= PODRAM_addr[0])) {
    598 				first_mapped_PODRAM_page_index = page;
    599 			};
    600 			page++;
    601 			phys_addr = mem_pages_info[page].physical;
    602 		};
    603 		printf("-0x%x]  ", (phys_addr + nbpp -1));
    604 	};
    605 	printf("\n\n");
    606 	if (first_mapped_PODRAM_page_index < 0) {
    607 		if (PODRAM_addr[0])
    608 			panic("Found no (S)DRAM mapped in the bootloader");
    609 	};
    610 	if (first_mapped_DRAM_page_index < 0)
    611 		panic("No DRAM mapped in the bootloader");
    612 }
    613 
    614 
    615 void create_initial_page_tables(void) {
    616 	u_long page, section, addr, kpage;
    617 
    618 	/* mark a section by the following bits and domain 0, AP=01, CB=0 */
    619 	/*         A         P         C        B        section
    620 	           domain		*/
    621 	section = (0<<11) | (1<<10) | (0<<3) | (0<<2) | (1<<4) | (1<<1) |
    622 	    (0) | (0 << 5);
    623 
    624 	/* first of all a full 1:1 mapping */
    625 	for (page = 0; page < 4*1024; page++) {
    626 		initial_page_tables[page] = (page<<20) | section;
    627 	};
    628 
    629 	/*
    630 	 * video memory is mapped 1:1 in the DRAM section or in VRAM
    631 	 * section
    632 	 *
    633 	 * map 1Mb from top of DRAM memory to bottom 1Mb of virtual memmap
    634 	 */
    635 	top_1Mb_dram = (((top_physdram - 1024*1024) >> 20) << 20);
    636 
    637 	initial_page_tables[0] = top_1Mb_dram | section;
    638 
    639 	/*
    640 	 * map 16 Mb of kernel space to KERNEL_BASE
    641 	 * i.e. marks[KERNEL_START]
    642 	 */
    643 	for (page = 0; page < 16; page++) {
    644 		addr  = (kernel_physical_start >> 20) + page;
    645 		kpage = (marks[MARK_START]     >> 20) + page;
    646 		initial_page_tables[kpage] = (addr << 20) | section;
    647 	};
    648 }
    649 
    650 
    651 void add_pagetables_at_top(void) {
    652 	int page;
    653 	u_long src, dst, fragaddr;
    654 
    655 	/* Special : destination must be on a 16 Kb boundary */
    656 	/* get 4 pages on the top of the physical memory and copy PT's in it */
    657 	new_L1_pages_phys = top_physdram - 4*nbpp;
    658 
    659 	/*
    660 	 * If the L1 page tables are not 16 kb aligned, adjust base
    661 	 * until it is
    662 	 */
    663 	while (new_L1_pages_phys & (16*1024-1)) {
    664 		new_L1_pages_phys -= nbpp;
    665 	};
    666 	if (new_L1_pages_phys & (16*1024-1))
    667 		panic("Paranoia : L1 pages not on 16Kb boundary");
    668 
    669 	dst = new_L1_pages_phys;
    670 	src = (u_long) initial_page_tables;
    671 
    672 	for (page = 0; page < 4; page++) {
    673 		/* get a page for a fragment */
    674 		fragaddr = get_relocated_page(dst, nbpp)->logical;
    675 		memcpy((void *) fragaddr, (void *) src, nbpp);
    676 
    677 		src += nbpp;
    678 		dst += nbpp;
    679 	};
    680 }
    681 
    682 
    683 void add_initvectors(void) {
    684 	u_long *pos;
    685 	u_long  vectoraddr, count;
    686 
    687 	/* the top 1Mb of the physical DRAM pages is mapped at address 0 */
    688 	vectoraddr = get_relocated_page(top_1Mb_dram, nbpp)->logical;
    689 
    690 	/* fill the vectors with `movs pc, lr' opcodes */
    691 	pos = (u_long *) vectoraddr; memset(pos, 0, nbpp);
    692 	for (count = 0; count < 128; count++) *pos++ = 0xE1B0F00E;
    693 }
    694 
    695 
    696 void create_configuration(int argc, char **argv, int start_args) {
    697 	int   i, root_specified, id_low, id_high;
    698 	char *pos;
    699 
    700 	bconfig_new_phys = kernel_free_vm_start - pv_offset;
    701 	bconfig_page = get_relocated_page(bconfig_new_phys, nbpp);
    702 	bconfig = (struct bootconfig *) (bconfig_page->logical);
    703 	kernel_free_vm_start += nbpp;
    704 
    705 	/* get some miscelanious info for the bootblock */
    706 	os_readsysinfo_monitor_info(NULL, &monitor_type, &monitor_sync);
    707 	os_readsysinfo_chip_presence(&ioeb_flags, &superio_flags, &lcd_flags);
    708 	os_readsysinfo_superio_features(&superio_flags_basic,
    709 	    &superio_flags_extra);
    710 	os_readsysinfo_unique_id(&id_low, &id_high);
    711 
    712 	/* fill in the bootconfig *bconfig structure : generic version II */
    713 	memset(bconfig, 0, sizeof(bconfig));
    714 	bconfig->magic		= BOOTCONFIG_MAGIC;
    715 	bconfig->version	= BOOTCONFIG_VERSION;
    716 	strcpy(bconfig->kernelname, booted_file);
    717 
    718 	/*
    719 	 * get the kernel base name and update the RiscOS name to a
    720 	 * Unix name
    721 	 */
    722 	i = strlen(booted_file);
    723 	while ((i >= 0) && (booted_file[i] != '.')) i--;
    724 	if (i) {
    725 		strcpy(bconfig->kernelname, "/");
    726 		strcat(bconfig->kernelname, booted_file+i+1);
    727 	};
    728 
    729 	pos = bconfig->kernelname+1;
    730 	while (*pos) {
    731 		if (*pos == '/') *pos = '.';
    732 		pos++;
    733 	};
    734 
    735 	/* set the machine_id */
    736 	memcpy(&(bconfig->machine_id), &id_low, 4);
    737 
    738 	/* check if the `root' is specified */
    739 	root_specified = 0;
    740 	strcpy(bconfig->args, "");
    741 	for (i = start_args; i < argc; i++) {
    742 		if (strncmp(argv[i], "root=",5) ==0) root_specified = 1;
    743 		strcat(bconfig->args, argv[i]);
    744 	};
    745 	if (!root_specified) {
    746 		strcat(bconfig->args, "root=");
    747 		strcat(bconfig->args, DEFAULT_ROOT);
    748 	};
    749 
    750 	/* mark kernel pointers */
    751 	bconfig->kernvirtualbase	= marks[MARK_START];
    752 	bconfig->kernphysicalbase	= kernel_physical_start;
    753 	bconfig->kernsize		= kernel_free_vm_start -
    754 					    marks[MARK_START];
    755 	bconfig->ksym_start		= marks[MARK_SYM];
    756 	bconfig->ksym_end		= marks[MARK_SYM] + marks[MARK_NSYM];
    757 
    758 	/* setup display info */
    759 	bconfig->display_phys		= videomem_start;
    760 	bconfig->display_start		= videomem_start;
    761 	bconfig->display_size		= display_size;
    762 	bconfig->width			= vdu_var(os_MODEVAR_XWIND_LIMIT);
    763 	bconfig->height			= vdu_var(os_MODEVAR_YWIND_LIMIT);
    764 	bconfig->log2_bpp		= vdu_var(os_MODEVAR_LOG2_BPP);
    765 	/* XXX why? better guessing possible? XXX */
    766 	bconfig->framerate		= 56;
    767 
    768 	/* fill in memory info */
    769 	bconfig->pagesize		= nbpp;
    770 	bconfig->drampages		= total_dram_pages +
    771 					    total_podram_pages;	/* XXX */
    772 	bconfig->vrampages		= total_vram_pages;
    773 	bconfig->dramblocks		= dram_blocks + podram_blocks; /*XXX*/
    774 	bconfig->vramblocks		= vram_blocks;
    775 
    776 	for (i = 0; i < dram_blocks; i++) {
    777 		bconfig->dram[i].address = DRAM_addr[i];
    778 		bconfig->dram[i].pages   = DRAM_pages[i];
    779 		bconfig->dram[i].flags   = PHYSMEM_TYPE_GENERIC;
    780 	};
    781 	for (; i < dram_blocks + podram_blocks; i++) {
    782 		bconfig->dram[i].address = PODRAM_addr[i];
    783 		bconfig->dram[i].pages   = PODRAM_pages[i];
    784 		bconfig->dram[i].flags   = PHYSMEM_TYPE_PROCESSOR_ONLY;
    785 	};
    786 	for (i = 0; i < vram_blocks; i++) {
    787 		bconfig->vram[i].address = VRAM_addr[i];
    788 		bconfig->vram[i].pages   = VRAM_pages[i];
    789 		bconfig->vram[i].flags   = PHYSMEM_TYPE_GENERIC;
    790 	};
    791 }
    792 
    793 
    794 int main(int argc, char **argv) {
    795 	int howto, start_args, ret;
    796 
    797 	printf("\n\n");
    798 	printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
    799 	printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
    800 	printf(">> Booting NetBSD/acorn32 on a RiscPC/A7000/NC\n");
    801 	printf("\n");
    802 
    803 	process_args(argc, argv, &howto, booted_file, &start_args);
    804 
    805 	printf("Booting %s (howto = 0x%x)\n", booted_file, howto);
    806 
    807 	init_datastructures();
    808 	get_memory_configuration();
    809 	get_memory_map();
    810 
    811 	/*
    812 	 * point to the first free DRAM page guaranteed to be in
    813 	 * strict order up
    814 	 */
    815 	if (first_mapped_PODRAM_page_index) {
    816 		free_relocation_page =
    817 		    mem_pages_info + first_mapped_PODRAM_page_index;
    818 		kernel_physical_start = PODRAM_addr[0];
    819 	} else {
    820 		free_relocation_page =
    821 		    mem_pages_info + first_mapped_DRAM_page_index;
    822 		kernel_physical_start = DRAM_addr[0];
    823 	};
    824 
    825 	printf("\nLoading %s ", booted_file);
    826 
    827 	/* first count the kernel to get the markers */
    828 	ret = loadfile(booted_file, marks, COUNT_KERNEL);
    829 	if (ret == -1) panic("Kernel load failed"); /* lie to the user ... */
    830 	close(ret);
    831 
    832 	/*
    833 	 * calculate how much the difference is between physical and
    834 	 * virtual space for the kernel
    835 	 */
    836 	pv_offset = ((u_long) marks[MARK_START] - kernel_physical_start);
    837 	/* round on a page	*/
    838 	kernel_free_vm_start = (marks[MARK_END] + nbpp-1) & ~(nbpp-1);
    839 
    840 	/* we seem to be forced to clear the marks[] ? */
    841 	bzero(marks, sizeof(marks[MARK_MAX]));
    842 
    843 	/* really load it ! */
    844 	ret = loadfile(booted_file, marks, LOAD_KERNEL);
    845 	if (ret == -1) panic("Kernel load failed");
    846 	close(ret);
    847 
    848 	/* finish off the relocation information */
    849 	create_initial_page_tables();
    850 	add_initvectors();
    851 	add_pagetables_at_top();
    852 	create_configuration(argc, argv, start_args);
    853 
    854 	/*
    855 	 * done relocating and creating information, now update and
    856 	 * check the relocation mechanism
    857 	 */
    858 	prepare_and_check_relocation_system();
    859 
    860 	printf("\nStarting at 0x%lx\n", marks[MARK_ENTRY]);
    861 	printf("Will boot in a few secs due to relocation....\n"
    862 	    "bye bye from RISC OS!");
    863 
    864 	/* dismount all filesystems */
    865 	xosfscontrol_shutdown();
    866 
    867 	/* reset devices, well they try to anyway */
    868 	service_pre_reset();
    869 
    870 	start_kernel(
    871 		/* r0 relocation code page (V)	*/ relocate_code_page->logical,
    872 		/* r1 relocation pv offset	*/
    873 		relocate_code_page->physical-relocate_code_page->logical,
    874 		/* r2 configuration structure	*/ bconfig_new_phys,
    875 		/* r3 relocation table (P)	*/
    876 		relocate_table_pages->physical,	/* one piece! */
    877 		/* r4 L1 page descriptor (P)	*/ new_L1_pages_phys,
    878 		/* r5 kernel entry point	*/ marks[MARK_ENTRY]
    879 	);
    880 	return 0;
    881 }
    882 
    883 
    884 ssize_t boot32_read(int f, void *addr, size_t size) {
    885 	caddr_t fragaddr;
    886 	size_t fragsize;
    887 	ssize_t bytes_read, total;
    888 
    889 	/* printf("read at %p for %ld bytes\n", addr, size); */
    890 	total = 0;
    891 	while (size > 0) {
    892 		fragsize = nbpp;		/* select one page	*/
    893 		if (size < nbpp) fragsize = size;/* clip to size left	*/
    894 
    895 		/* get a page for a fragment */
    896 		fragaddr = (caddr_t) get_relocated_page((u_long) addr -
    897 		    pv_offset, fragsize)->logical;
    898 
    899 		bytes_read = read(f, fragaddr, fragsize);
    900 		if (bytes_read < 0) return bytes_read;	/* error!	*/
    901 		total += bytes_read;		/* account read bytes	*/
    902 
    903 		if (bytes_read < fragsize)
    904 			return total;		/* does this happen?	*/
    905 
    906 		size -= fragsize;		/* advance		*/
    907 		addr += fragsize;
    908 	};
    909 	return total;
    910 }
    911 
    912 
    913 void *boot32_memcpy(void *dst, const void *src, size_t size) {
    914 	caddr_t fragaddr;
    915 	size_t fragsize;
    916 
    917 	/* printf("memcpy to %p from %p for %ld bytes\n", dst, src, size); */
    918 	while (size > 0) {
    919 		fragsize = nbpp;		/* select one page	*/
    920 		if (size < nbpp) fragsize = size;/* clip to size left	*/
    921 
    922 		/* get a page for a fragment */
    923 		fragaddr = (caddr_t) get_relocated_page((u_long) dst -
    924 		    pv_offset, fragsize)->logical;
    925 		memcpy(fragaddr, src, size);
    926 
    927 		src += fragsize;		/* account copy		*/
    928 		dst += fragsize;
    929 		size-= fragsize;
    930 	};
    931 	return dst;
    932 };
    933 
    934 
    935 void *boot32_memset(void *dst, int c, size_t size) {
    936 	caddr_t fragaddr;
    937 	size_t fragsize;
    938 
    939 	/* printf("memset %p for %ld bytes with %d\n", dst, size, c); */
    940 	while (size > 0) {
    941 		fragsize = nbpp;		/* select one page	*/
    942 		if (size < nbpp) fragsize = size;/* clip to size left	*/
    943 
    944 		/* get a page for a fragment */
    945 		fragaddr = (caddr_t) get_relocated_page((u_long) dst - pv_offset, fragsize)->logical;
    946 		memset(fragaddr, c, fragsize);
    947 
    948 		dst += fragsize;		/* account memsetting	*/
    949 		size-= fragsize;
    950 
    951 	};
    952 	return dst;
    953 }
    954 
    955 
    956 /* We can rely on the fact that two entries never have identical ->physical */
    957 int page_info_cmp(const void *a, const void *b) {
    958 	return (((struct page_info *)a)->physical <
    959 	    ((struct page_info *)b)->physical) ? -1 : 1;
    960 }
    961 
    962 struct page_info *get_relocated_page(u_long destination, int size) {
    963 	struct page_info *page;
    964 
    965 	/* get a page for a fragment */
    966 	page = free_relocation_page;
    967 	if (free_relocation_page->pagenumber < 0) panic("\n\nOut of pages");
    968 	reloc_entries++;
    969 	if (reloc_entries >= MAX_RELOCPAGES)
    970 		panic("\n\nToo many relocations! What are you loading ??");
    971 
    972 	/* record the relocation */
    973 	*reloc_pos++ = free_relocation_page->physical;
    974 	*reloc_pos++ = destination;
    975 	*reloc_pos++ = size;
    976 	free_relocation_page++;			/* advance 		*/
    977 
    978 	return page;
    979 }
    980 
    981 
    982 int vdu_var(int var) {
    983 	int varlist[2], vallist[2];
    984 
    985 	varlist[0] = var;
    986 	varlist[1] = -1;
    987 	os_read_vdu_variables(varlist, vallist);
    988 	return vallist[0];
    989 }
    990 
    991 
    992 void twirl(void) {
    993 	printf("%c%c", "|/-\\"[(int) twirl_cnt], 8);
    994 	twirl_cnt++;
    995 	twirl_cnt &= 3;
    996 }
    997 
    998 
    999 void process_args(int argc, char **argv, int *howto, char *file,
   1000     int *start_args) {
   1001 	int i, j;
   1002 	static char filename[80];
   1003 
   1004 	*howto = 0;
   1005 	*file = NULL; *start_args = 1;
   1006 	for (i = 1; i < argc; i++) {
   1007 		if (argv[i][0] == '-')
   1008 			for (j = 1; argv[i][j]; j++)
   1009 				BOOT_FLAG(argv[i][j], *howto);
   1010 		else {
   1011 			if (*file)
   1012 				*start_args = i;
   1013 			else {
   1014 				strcpy(file, argv[i]);
   1015 				*start_args = i+1;
   1016 			};
   1017 			break;
   1018 		};
   1019 	};
   1020 	if (*file == NULL) {
   1021 		if (*howto & RB_ASKNAME) {
   1022 			printf("boot: ");
   1023 			gets(filename);
   1024 			strcpy(file, filename);
   1025 		} else
   1026 			strcpy(file, "netbsd");
   1027 	};
   1028 }
   1029 
   1030 
   1031 char *sprint0(int width, char prefix, char base, int value) {
   1032 	static char format[50], scrap[50];
   1033 	char *pos;
   1034 	int length;
   1035 
   1036 	for (pos = format, length = 0; length<width; length++) *pos++ = prefix;
   1037 	*pos++ = '%';
   1038 	*pos++ = base;
   1039 	*pos++ = (char) 0;
   1040 
   1041 	sprintf(scrap, format, value);
   1042 	length = strlen(scrap);
   1043 
   1044 	return scrap+length-width;
   1045 }
   1046 
   1047