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