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