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