Home | History | Annotate | Line # | Download | only in boot32
boot32.c revision 1.10
      1 /*	$NetBSD: boot32.c,v 1.10 2003/01/08 16:10:53 reinoud 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 
     46 /* debugging flags */
     47 int debug = 1;
     48 
     49 
     50 /* constants */
     51 #define PODRAM_START   (512*1024*1024)				/* XXX Kinetic cards XXX	*/
     52 
     53 #define MAX_RELOCPAGES	4096
     54 
     55 #define DEFAULT_ROOT	"/dev/wd0a"
     56 
     57 
     58 #define IO_BLOCKS	 16	/* move these to the bootloader structure? */
     59 #define ROM_BLOCKS	 16
     60 #define PODRAM_BLOCKS	 16
     61 
     62 
     63 /* booter variables */
     64 char	 scrap[80], twirl_cnt;					/* misc				*/
     65 char	 booted_file[80];
     66 
     67 struct bootconfig *bconfig;					/* bootconfig passing		*/
     68 u_long	 bconfig_new_phys;					/* physical address its bound	*/
     69 
     70 u_int	 monitor_type, monitor_sync, ioeb_flags, lcd_flags;	/* computer knowledge		*/
     71 u_int	 superio_flags, superio_flags_basic, superio_flags_extra;
     72 
     73 int	 nbpp, memory_table_size, memory_image_size;		/* sizes			*/
     74 u_long	 reloc_tablesize, *reloc_instruction_table;		/* relocate info		*/
     75 u_long	*reloc_pos;						/* current empty entry		*/
     76 int	 reloc_entries;						/* number of relocations	*/
     77 int	 first_mapped_DRAM_page_index;				/* offset in RISC OS blob	*/
     78 int	 first_mapped_PODRAM_page_index;			/* offset in RISC OS blob	*/
     79 
     80 struct page_info *mem_pages_info;				/* {nr, virt, phys}*		*/
     81 struct page_info *free_relocation_page;				/* points to the page_info chain*/
     82 struct page_info *relocate_table_pages;				/* points to seq. relocate info */
     83 struct page_info *relocate_code_page;				/* points to the copied code	*/
     84 struct page_info *bconfig_page;					/* page for passing on settings	*/
     85 
     86 unsigned char *memory_page_types;				/* packed array of 4 bit typeId	*/
     87 
     88 u_long	*initial_page_tables;					/* pagetables to be booted from	*/
     89 
     90 
     91 /* XXX rename *_BLOCKS to MEM_BLOCKS */
     92 /* DRAM/VRAM/ROM/IO info */
     93 u_long	 videomem_start, videomem_pages, display_size;		/* where the display is		*/
     94 
     95 u_long	 pv_offset, top_physdram;				/* kernel_base - phys. diff	*/
     96 u_long	 top_1Mb_dram;						/* the lower mapped top 1Mb	*/
     97 u_long	 new_L1_pages_phys;					/* physical address of L1 pages	*/
     98 
     99 u_long	 total_podram_pages, total_dram_pages, total_vram_pages;/* for bootconfig passing	*/
    100 int	 dram_blocks, podram_blocks;				/* number of mem. objects/type  */
    101 int	 vram_blocks, rom_blocks, io_blocks;
    102 
    103 u_long	 DRAM_addr[DRAM_BLOCKS],     DRAM_pages[DRAM_BLOCKS];
    104 u_long	 PODRAM_addr[PODRAM_BLOCKS], PODRAM_pages[PODRAM_BLOCKS];	/* processor only RAM	*/
    105 u_long	 VRAM_addr[VRAM_BLOCKS],     VRAM_pages[VRAM_BLOCKS];
    106 u_long	 ROM_addr[ROM_BLOCKS],       ROM_pages[ROM_BLOCKS];
    107 u_long	 IO_addr[IO_BLOCKS],         IO_pages[IO_BLOCKS];
    108 
    109 
    110 /* RISC OS memory pages we claimed */
    111 u_long	 firstpage, lastpage, totalpages;			/* RISC OS pagecounters		*/
    112 char	*memory_image, *bottom_memory, *top_memory;		/* RISC OS memory		*/
    113 
    114 u_long	 videomem_start_ro;					/* for debugging mainly		*/
    115 
    116 /* kernel info */
    117 u_long	 marks[MARK_MAX];					/* loader mark pointers 	*/
    118 u_long	 kernel_physical_start;					/* where does it get relocated	*/
    119 u_long	 kernel_free_vm_start;					/* where does the free VM start	*/
    120 u_long	 scratch_virtualbase, scratch_physicalbase;		/* some free space to mess with	*/
    121 
    122 
    123 /* bootprogram identifiers */
    124 extern const char bootprog_rev[];
    125 extern const char bootprog_name[];
    126 extern const char bootprog_date[];
    127 extern const char bootprog_maker[];
    128 
    129 
    130 /* predefines / prototypes */
    131 void	 init_datastructures(void);
    132 void	 get_memory_configuration(void);
    133 void	 get_memory_map(void);
    134 void	 create_initial_page_tables(void);
    135 void	 add_pagetables_at_top(void);
    136 void	 sort_memory_map(void);
    137 void	 add_initvectors(void);
    138 void	 create_configuration(int argc, char **argv, int start_args);
    139 void	 prepare_and_check_relocation_system(void);
    140 void	 twirl(void);
    141 int	 vdu_var(int);
    142 void	 process_args(int argc, char **argv, int *howto, char *file, int *start_args);
    143 
    144 char		 *sprint0(int width, char prefix, char base, int value);
    145 struct page_info *get_relocated_page(u_long destination, int size);
    146 
    147 extern void start_kernel(
    148 		int relocate_code_page,
    149 		int relocation_pv_offset,
    150 		int configuration_structure_in_flat_physical_space,
    151 		int physical_address_of_relocation_tables,
    152 		int physical_address_of_new_L1_pages,
    153 		int kernel_entry_point
    154 		);	/* asm */
    155 
    156 
    157 /* the loader itself */
    158 void init_datastructures(void) {
    159 	/* Get number of pages and the memorytablesize */
    160 	osmemory_read_arrangement_table_size(&memory_table_size, &nbpp);
    161 
    162 	/* reserve some space for heap etc... 512 might be bigish though */
    163 	memory_image_size = (int) HIMEM - 512*1024;
    164 	if (memory_image_size <= 256*1024) panic("I need more memory to boot up; increase Wimp slot");
    165 	memory_image = alloc(memory_image_size);
    166 	if (!memory_image) panic("Can't alloc get my memory image ?");
    167 
    168 	bottom_memory = memory_image;
    169 	top_memory    = memory_image + memory_image_size;
    170 
    171 	firstpage  = ((int) bottom_memory / nbpp) + 1;	/* safety */
    172 	lastpage   = ((int) top_memory    / nbpp) - 1;
    173 	totalpages = lastpage - firstpage;
    174 
    175 	printf("Got %ld memory pages each %d kilobytes to mess with.\n\n", totalpages, nbpp>>10);
    176 
    177 	/* allocate some space for the relocation table */
    178 	reloc_tablesize = (MAX_RELOCPAGES+1)*3*sizeof(u_long);	/* 3 entry table */
    179 	reloc_instruction_table = alloc(reloc_tablesize);
    180 	if (!reloc_instruction_table) panic("Can't alloc my relocate instructions pages");
    181 
    182 	/* set up relocation table. First word gives number of relocations to be done */
    183 	reloc_entries = 0;
    184 	reloc_pos     = reloc_instruction_table;
    185 	*reloc_pos++  = 0;
    186 
    187 	/* set up the memory translation info structure; alloc one more for	*
    188 	 * end of list marker; see get_memory_map				*/
    189 	mem_pages_info = alloc((totalpages + 1)*sizeof(struct page_info));
    190 	if (!mem_pages_info) panic("Can't alloc my phys->virt page info");
    191 
    192 	/* allocate memory for the memory arrangement table */
    193 	memory_page_types = alloc(memory_table_size);
    194 	if (!memory_page_types) panic("Can't alloc my memory page type block");
    195 
    196 	initial_page_tables = alloc(16*1024);			/* size is 16 kb per definition */
    197 	if (!initial_page_tables) panic("Can't alloc my initial page tables");
    198 }
    199 
    200 
    201 void prepare_and_check_relocation_system(void) {
    202 	int     relocate_size, relocate_pages;
    203 	int     bank, pages, found;
    204 	u_long  dst, src, base, destination, extend;
    205 	u_long *reloc_entry, last_src, length;
    206 
    207 	/* set the number of relocation entries in the 1st word */
    208 	*reloc_instruction_table = reloc_entries;
    209 
    210 	/* the relocate information needs to be in one sequential physical space	*/
    211 	relocate_size = (reloc_tablesize + nbpp-1) & ~(nbpp-1);	/* round space up	*/
    212 	printf("\nPreparing for booting %s ... ", booted_file);
    213 	relocate_pages = relocate_size / nbpp;
    214 
    215 	relocate_table_pages = free_relocation_page;
    216 	pages = 0;
    217 	while (pages < relocate_pages) {
    218 		src = (u_long) reloc_instruction_table + pages*nbpp;
    219 		dst = (relocate_table_pages + pages)->logical;
    220 		memcpy((void *) dst, (void *) src, nbpp);
    221 
    222 		if (pages < relocate_pages-1) {
    223 			/* check if next page is sequential physically */
    224 			if ((relocate_table_pages+pages+1)->physical - (relocate_table_pages+pages)->physical != nbpp) {
    225 				/* Ieee! non contigunous relocate area -> try again */
    226 				printf("*");
    227 				relocate_table_pages += pages;
    228 				pages = -1;			/* will be incremented till zero later */
    229 			};
    230 		};
    231 		pages++;
    232 	};
    233 	free_relocation_page = relocate_table_pages + pages;
    234 
    235 	/* copy the relocation code into this page in start_kernel */
    236 	relocate_code_page = free_relocation_page++;
    237 
    238 	/*
    239 	 * All relocations are pages allocated in one big strict increasing
    240 	 * physical DRAM address sequence. When the MMU is switched off all
    241 	 * code and data is in this increasing order but not at the right
    242 	 * place. This is where the relocation code kicks in; relocation is
    243 	 * done in flat physical memory without MMU.
    244 	 */
    245 
    246 	printf("shift and check ... ");
    247 	reloc_entry = reloc_instruction_table + 1;
    248 	last_src = -1;
    249 	while (reloc_entry < reloc_pos) {
    250 		src         = reloc_entry[0];
    251 		destination = reloc_entry[1];
    252 		length      = reloc_entry[2];
    253 
    254 		/* paranoia check */
    255 		if ((long) (src - last_src) <= 0) printf("relocation sequence challenged -- booting might fail ");
    256 		last_src = src;
    257 
    258 		/* check if its gonna be relocated into (PO)DRAM ! */
    259 		extend = destination + length;
    260 		found = 0;
    261 		for (bank = 0; (bank < dram_blocks) && !found; bank++) {
    262 			base   = DRAM_addr[bank];
    263 			found = (destination >= base) && (extend <= base + DRAM_pages[bank]*nbpp);
    264 		};
    265 		for (bank = 0; (bank < podram_blocks) && !found; bank++) {
    266 			base = PODRAM_addr[bank];
    267 			found = (destination >= base) && (extend <= base + PODRAM_pages[bank]*nbpp);
    268 		};
    269 		if (!found || (extend > top_physdram)) {
    270 			panic( "Internal error: relocating range [%lx +%lx => %lx] outside (PO)DRAM banks!",
    271 				src, length, destination
    272 			);
    273 		};
    274 
    275 		reloc_entry+=3;
    276 	};
    277 	if (reloc_entry != reloc_pos) panic("Relocation instruction table is corrupted");
    278 
    279 	printf("OK!\n");
    280 }
    281 
    282 
    283 void get_memory_configuration(void) {
    284 	int loop, current_page_type, page_count, phys_page;
    285 	int page, count, bank;
    286 	int mapped_screen_memory;
    287 
    288 	printf("Getting memory configuration ");
    289 
    290 	osmemory_read_arrangement_table(memory_page_types);
    291 
    292 	/* init counters */
    293 	vram_blocks = dram_blocks = rom_blocks = io_blocks = podram_blocks = 0;
    294 
    295 	current_page_type = -1;
    296 	phys_page = 0;			/* physical address in pages	*/
    297 	page_count = 0;			/* page counter in this block	*/
    298 	loop = 0;			/* loop variable over entries	*/
    299 
    300 	/* iterating over a packed array of 2 page types/byte i.e. 8 kb/byte */
    301 	while (loop < 2*memory_table_size) {
    302 		page = (memory_page_types[loop / 2]);	/* read	twice       	   */
    303 		if (loop & 1) page >>= 4;		/* take other nibble	   */
    304 
    305 		/* bits 0-2 give type, bit3 means the bit page is allocatable 	   */
    306 		page &= 0x7;				/* only take bottom 3 bits */
    307 		if (page != current_page_type) {
    308 			/* passed a boundary ... note this block		   */
    309 			/* splitting in different vars is for compatability reasons*/
    310 			switch (current_page_type) {
    311 				case -1 :
    312 				case  0 :
    313 					break;
    314 				case osmemory_TYPE_DRAM :
    315 					if (phys_page < PODRAM_START) {
    316 						DRAM_addr[dram_blocks]  = phys_page * nbpp;
    317 						DRAM_pages[dram_blocks] = page_count;
    318 						dram_blocks++;
    319 					} else {
    320 						PODRAM_addr[podram_blocks]  = phys_page * nbpp;
    321 						PODRAM_pages[podram_blocks] = page_count;
    322 						podram_blocks++;
    323 					};
    324 					break;
    325 				case osmemory_TYPE_VRAM :
    326 					VRAM_addr[vram_blocks]  = phys_page * nbpp;
    327 					VRAM_pages[vram_blocks] = page_count;
    328 					vram_blocks++;
    329 					break;
    330 				case osmemory_TYPE_ROM :
    331 					ROM_addr[rom_blocks]  = phys_page * nbpp;
    332 					ROM_pages[rom_blocks] = page_count;
    333 					rom_blocks++;
    334 					break;
    335 				case osmemory_TYPE_IO :
    336 					IO_addr[io_blocks]  = phys_page * nbpp;
    337 					IO_pages[io_blocks] = page_count;
    338 					io_blocks++;
    339 					break;
    340 				default :
    341 					printf("WARNING : found unknown memory object %d ", current_page_type);
    342 					printf(" at 0x%s", sprint0(8,'0','x', phys_page * nbpp));
    343 					printf(" for %s k\n", sprint0(5,' ','d', (page_count*nbpp)>>10));
    344 					break;
    345 			};
    346 			current_page_type = page;
    347 			phys_page = loop;
    348 			page_count = 0;
    349 		};
    350 		/* smallest unit we recognise is one page ... silly could be upto 64 pages i.e. 256 kb */
    351 		page_count += 1;
    352 		loop       += 1;
    353 		if ((loop & 31) == 0) twirl();
    354 	};
    355 
    356 	printf(" \n\n");
    357 
    358 	if (VRAM_pages[0] == 0) {
    359 		/* map bottom DRAM as video memory */
    360 		display_size	 = (vdu_var(os_VDUVAR_TOTAL_SCREEN_SIZE) & ~(nbpp-1));
    361 #if 0
    362 		mapped_screen_memory = 1024 * 1024;		/* max allowed on RiscPC	*/
    363 		videomem_pages   = (mapped_screen_memory / nbpp);
    364 		videomem_start   = DRAM_addr[0];
    365 		DRAM_addr[0]	+= videomem_pages * nbpp;
    366 		DRAM_pages[0]	-= videomem_pages;
    367 #else
    368 		mapped_screen_memory = display_size;
    369 		bank = dram_blocks-1;				/* pick last SIMM		*/
    370 		videomem_pages   = (mapped_screen_memory / nbpp);
    371 
    372 		/* Map video memory at the end of the SIMM	*/
    373 		videomem_start   = DRAM_addr[bank] + (DRAM_pages[bank] - videomem_pages)*nbpp;
    374 		DRAM_pages[bank]-= videomem_pages;
    375 #endif
    376 	} else {
    377 		/* use VRAM */
    378 		mapped_screen_memory = 0;
    379 		videomem_start	 = VRAM_addr[0];
    380 		videomem_pages	 = VRAM_pages[0];
    381 		display_size	 = videomem_pages * nbpp;
    382 	};
    383 
    384 	if (mapped_screen_memory) {
    385 		printf("Used %d kb DRAM ", (mapped_screen_memory)/1024);
    386 		printf("at 0x%s for video memory\n", sprint0(8,'0','x', videomem_start));
    387 	};
    388 
    389 	/* find top of DRAM pages */
    390 	top_physdram = 0;
    391 
    392 	for (loop = podram_blocks-1; (loop >= 0) && (PODRAM_addr[loop] == 0); loop++);
    393 	if (loop >= 0) top_physdram = PODRAM_addr[loop] + PODRAM_pages[loop]*nbpp;
    394 	if (top_physdram == 0) {
    395 		for (loop = dram_blocks-1; (loop >= 0) && (DRAM_addr[loop] == 0); loop++);
    396 		if (loop >= 0) top_physdram = DRAM_addr[loop] + DRAM_pages[loop]*nbpp;
    397 	};
    398 	if (top_physdram == 0) panic("reality check: No DRAM in this machine?");
    399 
    400 
    401 	videomem_start_ro = vdu_var(os_VDUVAR_DISPLAY_START);
    402 
    403 	/* pretty print the individual page types */
    404 	for (count = 0; count < rom_blocks; count++) {
    405 		printf("Found ROM  (%d)", count);
    406 		printf(" at 0x%s", sprint0(8,'0','x', ROM_addr[count]));
    407 		printf(" for %s k\n", sprint0(5,' ','d', (ROM_pages[count]*nbpp)>>10));
    408 	};
    409 
    410 	for (count = 0; count < io_blocks; count++) {
    411 		printf("Found I/O  (%d)", count);
    412 		printf(" at 0x%s", sprint0(8,'0','x', IO_addr[count]));
    413 		printf(" for %s k\n", sprint0(5,' ','d', (IO_pages[count]*nbpp)>>10));
    414 	};
    415 
    416 	/* for DRAM/VRAM also count the number of pages */
    417 	total_dram_pages = 0;
    418 	for (count = 0; count < dram_blocks; count++) {
    419 		total_dram_pages += DRAM_pages[count];
    420 		printf("Found DRAM (%d)", count);
    421 		printf(" at 0x%s", sprint0(8,'0','x', DRAM_addr[count]));
    422 		printf(" for %s k\n", sprint0(5,' ','d', (DRAM_pages[count]*nbpp)>>10));
    423 	};
    424 
    425 	total_vram_pages = 0;
    426 	for (count = 0; count < vram_blocks; count++) {
    427 		total_vram_pages += VRAM_pages[count];
    428 		printf("Found VRAM (%d)", count);
    429 		printf(" at 0x%s", sprint0(8,'0','x', VRAM_addr[count]));
    430 		printf(" for %s k\n", sprint0(5,' ','d', (VRAM_pages[count]*nbpp)>>10));
    431 	};
    432 
    433 	total_podram_pages = 0;
    434 	for (count = 0; count < podram_blocks; count++) {
    435 		total_podram_pages += PODRAM_pages[count];
    436 		printf("Found Processor only (S)DRAM (%d)", count);
    437 		printf(" at 0x%s", sprint0(8,'0','x', PODRAM_addr[count]));
    438 		printf(" for %s k\n", sprint0(5,' ','d', (PODRAM_pages[count]*nbpp)>>10));
    439 	};
    440 }
    441 
    442 
    443 void get_memory_map(void) {
    444 	struct page_info *page_info;
    445 	int	page, inout;
    446 	int	phys_addr;
    447 
    448 	printf("\nGetting actual memorymapping");
    449 	for (page = 0, page_info = mem_pages_info; page < totalpages; page++, page_info++) {
    450 		page_info->pagenumber = 0;	/* not used */
    451 		page_info->logical    = (firstpage + page) * nbpp;
    452 		page_info->physical   = 0;	/* result comes here */
    453 		/* to avoid triggering a `bug' in RISC OS 4, page it in */
    454 		*((int *) page_info->logical) = 0;
    455 	};
    456 	/* close list */
    457 	page_info->pagenumber = -1;
    458 
    459 	inout = osmemory_GIVEN_LOG_ADDR | osmemory_RETURN_PAGE_NO | osmemory_RETURN_PHYS_ADDR;
    460 	osmemory_page_op(inout, mem_pages_info, totalpages);
    461 
    462 	printf(" ; sorting ");
    463 	sort_memory_map();
    464 	printf(".\n");
    465 
    466 	/* get the first DRAM index and show the physical memory fragments we got */
    467 	printf("\nFound physical memory blocks :\n");
    468 	first_mapped_DRAM_page_index = -1;
    469 	first_mapped_PODRAM_page_index = -1;
    470 	for (page=0; page < totalpages; page++) {
    471 		phys_addr = mem_pages_info[page].physical;
    472 		printf("[0x%x", phys_addr);
    473 		while (mem_pages_info[page+1].physical - phys_addr == nbpp) {
    474 			if ((first_mapped_DRAM_page_index<0) && (phys_addr >= DRAM_addr[0])) {
    475 				first_mapped_DRAM_page_index = page;
    476 			};
    477 			if ((first_mapped_PODRAM_page_index<0) && (phys_addr >= PODRAM_addr[0])) {
    478 				first_mapped_PODRAM_page_index = page;
    479 			};
    480 			page++;
    481 			phys_addr = mem_pages_info[page].physical;
    482 		};
    483 		printf("-0x%x]  ", (phys_addr + nbpp -1));
    484 	};
    485 	printf("\n\n");
    486 	if (first_mapped_PODRAM_page_index < 0) {
    487 		if (PODRAM_addr[0]) panic("Found no (S)DRAM mapped in the bootloader ... increase Wimpslot!");
    488 	};
    489 	if (first_mapped_DRAM_page_index < 0) panic("No DRAM  mapped in the bootloader ... increase Wimpslot!");
    490 }
    491 
    492 
    493 void create_initial_page_tables(void) {
    494 	u_long page, section, addr, kpage;
    495 
    496 	/* mark a section by the following bits and domain 0, AP=01, CB=0 */
    497 	/*         A         P         C        B        section                 domain		*/
    498 	section = (0<<11) | (1<<10) | (0<<3) | (0<<2) | (1<<4) | (1<<1) | (0) | (0 << 5);
    499 
    500 	/* first of all a full 1:1 mapping */
    501 	for (page = 0; page < 4*1024; page++) {
    502 		initial_page_tables[page] = (page<<20) | section;
    503 	};
    504 
    505 	/* video memory is mapped 1:1 in the DRAM section or in VRAM section	*/
    506 
    507 	/* map 1Mb from top of memory to bottom 1Mb of virtual memmap		*/
    508 	top_1Mb_dram = (((top_physdram - 1024*1024) >> 20) << 20);
    509 	initial_page_tables[0] = top_1Mb_dram | section;
    510 
    511 	/* map 16 Mb of kernel space to KERNEL_BASE i.e. marks[KERNEL_START]	*/
    512 	for (page = 0; page < 16; page++) {
    513 		addr  = (kernel_physical_start >> 20) + page;
    514 		kpage = (marks[MARK_START]     >> 20) + page;
    515 		initial_page_tables[kpage] = (addr << 20) | section;
    516 	};
    517 }
    518 
    519 
    520 void add_pagetables_at_top(void) {
    521 	int page;
    522 	u_long src, dst, fragaddr;
    523 
    524 	/* Special : destination must be on a 16 Kb boundary			*/
    525 	/* get 4 pages on the top of the physical memory and copy PT's in it	*/
    526 	new_L1_pages_phys = top_physdram - 4*nbpp;
    527 
    528 	/* If the L1 page tables are not 16 kb aligned, adjust base until it is	*/
    529 	while (new_L1_pages_phys & (16*1024-1)) {
    530 		new_L1_pages_phys -= nbpp;
    531 	};
    532 	if (new_L1_pages_phys & (16*1024-1)) panic("Paranoia : L1 pages not on 16Kb boundary");
    533 
    534 	dst = new_L1_pages_phys;
    535 	src = (u_long) initial_page_tables;
    536 
    537 	for (page = 0; page < 4; page++) {
    538 		/* get a page for a fragment */
    539 		fragaddr = get_relocated_page(dst, nbpp)->logical;
    540 		memcpy((void *) fragaddr, (void *) src, nbpp);
    541 
    542 		src += nbpp;
    543 		dst += nbpp;
    544 	};
    545 }
    546 
    547 
    548 void add_initvectors(void) {
    549 	u_long *pos;
    550 	u_long  vectoraddr, count;
    551 
    552 	/* the top 1Mb of the physical DRAM pages is mapped at address 0 */
    553 	vectoraddr = get_relocated_page(top_1Mb_dram, nbpp)->logical;
    554 
    555 	/* fill the vectors with `movs pc, lr' opcodes */
    556 	pos = (u_long *) vectoraddr; memset(pos, 0, nbpp);
    557 	for (count = 0; count < 128; count++) *pos++ = 0xE1B0F00E;
    558 }
    559 
    560 
    561 void create_configuration(int argc, char **argv, int start_args) {
    562 	int   i, root_specified, id_low, id_high;
    563 	char *pos;
    564 
    565 	bconfig_new_phys = kernel_free_vm_start - pv_offset;
    566 	bconfig_page = get_relocated_page(bconfig_new_phys, nbpp);
    567 	bconfig = (struct bootconfig *) (bconfig_page->logical);
    568 	kernel_free_vm_start += nbpp;
    569 
    570 	/* get some miscelanious info for the bootblock */
    571 	os_readsysinfo_monitor_info(NULL, &monitor_type, &monitor_sync);
    572 	os_readsysinfo_chip_presence(&ioeb_flags, &superio_flags, &lcd_flags);
    573 	os_readsysinfo_superio_features(&superio_flags_basic, &superio_flags_extra);
    574 	os_readsysinfo_unique_id(&id_low, &id_high);
    575 
    576 	/* fill in the bootconfig *bconfig structure : generic version II */
    577 	memset(bconfig, 0, sizeof(bconfig));
    578 	bconfig->magic			= BOOTCONFIG_MAGIC;
    579 	bconfig->version		= BOOTCONFIG_VERSION;
    580 	strcpy(bconfig->kernelname, booted_file);
    581 
    582 	/* get the kernel base name and update the RiscOS name to a Unix name */
    583 	i = strlen(bconfig->kernelname);
    584 	while ((i >= 0) && (bconfig->kernelname[i] != '.')) i--;
    585 	if (i) memcpy(bconfig->kernelname, bconfig->kernelname+i+1, strlen(booted_file)-i);
    586 
    587 	pos = bconfig->kernelname;
    588 	while (*pos) {
    589 		if (*pos == '/') *pos = '.';
    590 		pos++;
    591 	};
    592 
    593 	/* set the machine_id */
    594 	memcpy(&(bconfig->machine_id), &id_low, 4);
    595 
    596 	/* check if the `root' is specified */
    597 	root_specified = 0;
    598 	strcpy(bconfig->args, "");
    599 	for (i = start_args; i < argc; i++) {
    600 		if (strncmp(argv[i], "root=",5) ==0) root_specified = 1;
    601 		strcat(bconfig->args, argv[i]);
    602 	};
    603 	if (!root_specified) {
    604 		strcat(bconfig->args, "root=");
    605 		strcat(bconfig->args, DEFAULT_ROOT);
    606 	};
    607 
    608 	/* mark kernel pointers */
    609 	bconfig->kernvirtualbase	= marks[MARK_START];
    610 	bconfig->kernphysicalbase	= kernel_physical_start;
    611 	bconfig->kernsize		= kernel_free_vm_start - marks[MARK_START];
    612 	bconfig->ksym_start		= marks[MARK_SYM];
    613 	bconfig->ksym_end		= marks[MARK_SYM] + marks[MARK_NSYM];
    614 
    615 	/* setup display info */
    616 	bconfig->display_phys		= videomem_start;
    617 	bconfig->display_start		= videomem_start;
    618 	bconfig->display_size		= display_size;
    619 	bconfig->width			= vdu_var(os_MODEVAR_XWIND_LIMIT);
    620 	bconfig->height			= vdu_var(os_MODEVAR_YWIND_LIMIT);
    621 	bconfig->log2_bpp		= vdu_var(os_MODEVAR_LOG2_BPP);
    622 	bconfig->framerate		= 56;		/* XXX why? better guessing possible? XXX */
    623 
    624 	/* fill in memory info */
    625 	bconfig->pagesize		= nbpp;
    626 	bconfig->drampages		= total_dram_pages + total_podram_pages;	/* XXX */
    627 	bconfig->vrampages		= total_vram_pages;
    628 	bconfig->dramblocks		= dram_blocks + podram_blocks;			/* XXX */
    629 	bconfig->vramblocks		= vram_blocks;
    630 
    631 	for (i = 0; i < dram_blocks; i++) {
    632 		bconfig->dram[i].address = DRAM_addr[i];
    633 		bconfig->dram[i].pages   = DRAM_pages[i];
    634 		bconfig->dram[i].flags   = PHYSMEM_TYPE_GENERIC;
    635 	};
    636 	for (; i < dram_blocks + podram_blocks; i++) {
    637 		bconfig->dram[i].address = PODRAM_addr[i];
    638 		bconfig->dram[i].pages   = PODRAM_pages[i];
    639 		bconfig->dram[i].flags   = PHYSMEM_TYPE_PROCESSOR_ONLY;
    640 	};
    641 	for (i = 0; i < vram_blocks; i++) {
    642 		bconfig->vram[i].address = VRAM_addr[i];
    643 		bconfig->vram[i].pages   = VRAM_pages[i];
    644 		bconfig->vram[i].flags   = PHYSMEM_TYPE_GENERIC;
    645 	};
    646 }
    647 
    648 
    649 int main(int argc, char **argv) {
    650 	int howto, start_args, ret;
    651 
    652 	printf("\n\n");
    653 	printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
    654 	printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
    655 	printf(">> Booting NetBSD/acorn32 on a RiscPC/A7000/NC\n");
    656 	printf("\n");
    657 
    658 	process_args(argc, argv, &howto, booted_file, &start_args);
    659 
    660 	printf("Booting %s (howto = 0x%x)\n", booted_file, howto);
    661 
    662 	init_datastructures();
    663 	get_memory_configuration();
    664 	get_memory_map();
    665 
    666 	/* point to the first free DRAM page guaranteed to be in strict order up */
    667 	if (first_mapped_PODRAM_page_index) {
    668 		free_relocation_page = mem_pages_info + first_mapped_PODRAM_page_index;
    669 		kernel_physical_start = PODRAM_addr[0];
    670 	} else {
    671 		free_relocation_page = mem_pages_info + first_mapped_DRAM_page_index;
    672 		kernel_physical_start = DRAM_addr[0];
    673 	};
    674 
    675 	printf("\nLoading %s ", booted_file);
    676 
    677 	/* first count the kernel to get the markers */
    678 	ret = loadfile(booted_file, marks, COUNT_KERNEL);
    679 	if (ret == -1) panic("Kernel load failed");				/* lie to the user ...	*/
    680 	close(ret);
    681 
    682 	/* calculate how much the difference is between physical and virtual space for the kernel	*/
    683 	pv_offset = ((u_long) marks[MARK_START] - kernel_physical_start);
    684 	kernel_free_vm_start = (marks[MARK_END] + nbpp-1) & ~(nbpp-1);		/* round on a page	*/
    685 
    686 	/* we seem to be forced to clear the marks() ? */
    687 	bzero(marks, sizeof(marks[MARK_MAX]));
    688 
    689 	/* really load it ! */
    690 	ret = loadfile(booted_file, marks, LOAD_KERNEL);
    691 	if (ret == -1) panic("Kernel load failed");
    692 	close(ret);
    693 
    694 	/* finish off the relocation information */
    695 	create_initial_page_tables();
    696 	add_initvectors();
    697 	add_pagetables_at_top();
    698 	create_configuration(argc, argv, start_args);
    699 
    700 	/* done relocating and creating information, now update and check the relocation mechanism */
    701 	prepare_and_check_relocation_system();
    702 
    703 	printf("\nStarting at 0x%lx\n", marks[MARK_ENTRY]);
    704 	printf("Will boot in a few secs due to relocation....\nbye bye from RISC OS!");
    705 
    706 	/* dismount all filesystems */
    707 	xosfscontrol_shutdown();
    708 
    709 	/* reset devices, well they try to anyway */
    710 	service_pre_reset();
    711 
    712 	start_kernel(
    713 		/* r0 relocation code page (V)	*/ relocate_code_page->logical,
    714 		/* r1 relocation pv offset	*/ relocate_code_page->physical-relocate_code_page->logical,
    715 		/* r2 configuration structure	*/ bconfig_new_phys,
    716 		/* r3 relocation table (P)	*/ relocate_table_pages->physical,	/* one piece! */
    717 		/* r4 L1 page descriptor (P)	*/ new_L1_pages_phys,
    718 		/* r5 kernel entry point	*/ marks[MARK_ENTRY]
    719 	);
    720 	return 0;
    721 }
    722 
    723 
    724 ssize_t boot32_read(int f, void *addr, size_t size) {
    725 	caddr_t fragaddr;
    726 	size_t fragsize;
    727 	ssize_t bytes_read, total;
    728 
    729 	/* printf("read at %p for %ld bytes\n", addr, size); */
    730 	total = 0;
    731 	while (size > 0) {
    732 		fragsize = nbpp;				/* select one page	*/
    733 		if (size < nbpp) fragsize = size;		/* clip to size left	*/
    734 
    735 		/* get a page for a fragment */
    736 		fragaddr = (caddr_t) get_relocated_page((u_long) addr - pv_offset, fragsize)->logical;
    737 
    738 		bytes_read = read(f, fragaddr, fragsize);
    739 		if (bytes_read < 0) return bytes_read;		/* error!		*/
    740 		total += bytes_read;				/* account read bytes	*/
    741 
    742 		if (bytes_read < fragsize) return total;	/* does this happen?	*/
    743 
    744 		size -= fragsize;				/* advance		*/
    745 		addr += fragsize;
    746 	};
    747 	return total;
    748 }
    749 
    750 
    751 void *boot32_memcpy(void *dst, const void *src, size_t size) {
    752 	caddr_t fragaddr;
    753 	size_t fragsize;
    754 
    755 	/* printf("memcpy to %p from %p for %ld bytes\n", dst, src, size); */
    756 	while (size > 0) {
    757 		fragsize = nbpp;				/* select one page	*/
    758 		if (size < nbpp) fragsize = size;		/* clip to size left	*/
    759 
    760 		/* get a page for a fragment */
    761 		fragaddr = (caddr_t) get_relocated_page((u_long) dst - pv_offset, fragsize)->logical;
    762 		memcpy(fragaddr, src, size);
    763 
    764 		src += fragsize;				/* account copy		*/
    765 		dst += fragsize;
    766 		size-= fragsize;
    767 	};
    768 	return dst;
    769 };
    770 
    771 
    772 void *boot32_memset(void *dst, int c, size_t size) {
    773 	caddr_t fragaddr;
    774 	size_t fragsize;
    775 
    776 	/* printf("memset %p for %ld bytes with %d\n", dst, size, c); */
    777 	while (size > 0) {
    778 		fragsize = nbpp;				/* select one page	*/
    779 		if (size < nbpp) fragsize = size;		/* clip to size left	*/
    780 
    781 		/* get a page for a fragment */
    782 		fragaddr = (caddr_t) get_relocated_page((u_long) dst - pv_offset, fragsize)->logical;
    783 		memset(fragaddr, c, fragsize);
    784 
    785 		dst += fragsize;				/* account memsetting	*/
    786 		size-= fragsize;
    787 
    788 	};
    789 	return dst;
    790 }
    791 
    792 
    793 /* This sort routine needs to be re-implemented in either assembler or use other algorithm one day; its slow */
    794 void sort_memory_map(void) {
    795 	int out, in, count;
    796 	struct page_info *out_page, *in_page, temp_page;
    797 
    798 	count = 0;
    799 	for (out = 0, out_page = mem_pages_info; out < totalpages; out++, out_page++) {
    800 		for (in = out+1, in_page = out_page+1; in < totalpages; in++, in_page++) {
    801 			if (in_page->physical < out_page->physical) {
    802 				memcpy(&temp_page, in_page,    sizeof(struct page_info));
    803 				memcpy(in_page,    out_page,   sizeof(struct page_info));
    804 				memcpy(out_page,   &temp_page, sizeof(struct page_info));
    805 			};
    806 			count++;
    807 			if ((count & 0x3ffff) == 0) twirl();
    808 		};
    809 	};
    810 }
    811 
    812 
    813 struct page_info *get_relocated_page(u_long destination, int size) {
    814 	struct page_info *page;
    815 
    816 	/* get a page for a fragment */
    817 	page = free_relocation_page;
    818 	if (free_relocation_page->pagenumber < 0) panic("\n\nOut of pages; increase Wimpslot and try again");
    819 	reloc_entries++;
    820 	if (reloc_entries >= MAX_RELOCPAGES) panic("\n\nToo many relocations! What are you loading ??");
    821 
    822 	/* record the relocation */
    823 	*reloc_pos++ = free_relocation_page->physical;
    824 	*reloc_pos++ = destination;
    825 	*reloc_pos++ = size;
    826 	free_relocation_page++;				/* advance 		*/
    827 
    828 	return page;
    829 }
    830 
    831 
    832 int vdu_var(int var) {
    833 	int varlist[2], vallist[2];
    834 
    835 	varlist[0] = var;
    836 	varlist[1] = -1;
    837 	os_read_vdu_variables(varlist, vallist);
    838 	return vallist[0];
    839 }
    840 
    841 
    842 void twirl(void) {
    843 	printf("%c%c", "|/-\\"[(int) twirl_cnt], 8);
    844 	twirl_cnt++;
    845 	twirl_cnt &= 3;
    846 }
    847 
    848 
    849 void process_args(int argc, char **argv, int *howto, char *file, int *start_args) {
    850 	int i, j;
    851 	static char filename[80];
    852 
    853 	*howto = 0;
    854 	*file = NULL; *start_args = 1;
    855 	for (i = 1; i < argc; i++) {
    856 		if (argv[i][0] == '-')
    857 			for (j = 1; argv[i][j]; j++)
    858 				BOOT_FLAG(argv[i][j], *howto);
    859 		else {
    860 			if (*file)
    861 				*start_args = i;
    862 			else {
    863 				strcpy(file, argv[i]);
    864 				*start_args = i+1;
    865 			};
    866 			break;
    867 		};
    868 	};
    869 	if (*file == NULL) {
    870 		if (*howto & RB_ASKNAME) {
    871 			printf("boot: ");
    872 			gets(filename);
    873 			strcpy(file, filename);
    874 		} else
    875 			strcpy(file, "netbsd");
    876 	};
    877 }
    878 
    879 
    880 char *sprint0(int width, char prefix, char base, int value) {
    881 	static char format[50], scrap[50];
    882 	char *pos;
    883 	int length;
    884 
    885 	for (pos = format, length = 0; length<width; length++) *pos++ = prefix;
    886 	*pos++ = '%';
    887 	*pos++ = base;
    888 	*pos++ = (char) 0;
    889 
    890 	sprintf(scrap, format, value);
    891 	length = strlen(scrap);
    892 
    893 	return scrap+length-width;
    894 }
    895 
    896