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