boot32.c revision 1.37.6.1 1 /* $NetBSD: boot32.c,v 1.37.6.1 2011/06/06 09:04:41 jruoho Exp $ */
2
3 /*-
4 * Copyright (c) 2002 Reinoud Zandijk
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Thanks a bunch for Ben's framework for the bootloader and its suporting
30 * libs. This file tries to actually boot NetBSD/acorn32 !
31 *
32 * XXX eventually to be partly merged back with boot26 ? XXX
33 */
34
35 #include <lib/libsa/stand.h>
36 #include <lib/libsa/loadfile.h>
37 #include <lib/libkern/libkern.h>
38 #include <riscoscalls.h>
39 #include <srt0.h>
40 #include <sys/boot_flag.h>
41 #include <machine/vmparam.h>
42 #include <arm/arm32/pte.h>
43 #include <machine/bootconfig.h>
44
45 extern char end[];
46
47 /* debugging flags */
48 int debug = 1;
49
50
51 /* constants */
52 #define PODRAM_START (512*1024*1024) /* XXX Kinetic cards XXX */
53
54 #define MAX_RELOCPAGES 4096
55
56 #define DEFAULT_ROOT "/dev/wd0a"
57
58
59 #define IO_BLOCKS 16 /* move these to the bootloader structure? */
60 #define ROM_BLOCKS 16
61 #define PODRAM_BLOCKS 16
62
63
64 /* booter variables */
65 char scrap[80], twirl_cnt; /* misc */
66 char booted_file[80];
67
68 struct bootconfig *bconfig; /* bootconfig passing */
69 u_long bconfig_new_phys; /* physical address its bound */
70
71 /* computer knowledge */
72 u_int monitor_type, monitor_sync, ioeb_flags, lcd_flags;
73 u_int superio_flags, superio_flags_basic, superio_flags_extra;
74
75 /* sizes */
76 int nbpp, memory_table_size, memory_image_size;
77 /* relocate info */
78 u_long reloc_tablesize, *reloc_instruction_table;
79 u_long *reloc_pos; /* current empty entry */
80 int reloc_entries; /* number of relocations */
81 int first_mapped_DRAM_page_index; /* offset in RISC OS blob */
82 int first_mapped_PODRAM_page_index;/* offset in RISC OS blob */
83
84 struct page_info *mem_pages_info; /* {nr, virt, phys}* */
85 struct page_info *free_relocation_page; /* points to the page_info chain*/
86 struct page_info *relocate_code_page; /* points to the copied code */
87 struct page_info *bconfig_page; /* page for passing on settings */
88
89 unsigned char *memory_page_types; /* packed array of 4 bit typeId */
90
91 u_long *initial_page_tables; /* pagetables to be booted from */
92
93
94 /* XXX rename *_BLOCKS to MEM_BLOCKS */
95 /* DRAM/VRAM/ROM/IO info */
96 /* where the display is */
97 u_long videomem_start, videomem_pages, display_size;
98
99 u_long pv_offset, top_physdram; /* kernel_base - phys. diff */
100 u_long top_1Mb_dram; /* the lower mapped top 1Mb */
101 u_long new_L1_pages_phys; /* physical address of L1 pages */
102
103 /* for bootconfig passing */
104 u_long total_podram_pages, total_dram_pages, total_vram_pages;
105 int dram_blocks, podram_blocks; /* number of mem. objects/type */
106 int vram_blocks, rom_blocks, io_blocks;
107
108 u_long DRAM_addr[DRAM_BLOCKS], DRAM_pages[DRAM_BLOCKS];
109 /* processor only RAM */
110 u_long PODRAM_addr[PODRAM_BLOCKS], PODRAM_pages[PODRAM_BLOCKS];
111 u_long VRAM_addr[VRAM_BLOCKS], VRAM_pages[VRAM_BLOCKS];
112 u_long ROM_addr[ROM_BLOCKS], ROM_pages[ROM_BLOCKS];
113 u_long IO_addr[IO_BLOCKS], IO_pages[IO_BLOCKS];
114
115
116 /* RISC OS memory pages we claimed */
117 u_long firstpage, lastpage, totalpages; /* RISC OS pagecounters */
118 /* RISC OS memory */
119 char *memory_image, *bottom_memory, *top_memory;
120
121 /* kernel info */
122 u_long marks[MARK_MAX]; /* loader mark pointers */
123 u_long kernel_physical_start; /* where does it get relocated */
124 u_long kernel_physical_maxsize; /* Max allowed size of kernel */
125 u_long kernel_free_vm_start; /* where does the free VM start */
126 /* some free space to mess with */
127 u_long scratch_virtualbase, scratch_physicalbase;
128
129
130 /* bootprogram identifiers */
131 extern const char bootprog_rev[];
132 extern const char bootprog_name[];
133
134 /* predefines / prototypes */
135 void init_datastructures(void);
136 void get_memory_configuration(void);
137 void get_memory_map(void);
138 void create_initial_page_tables(void);
139 void add_pagetables_at_top(void);
140 int page_info_cmp(const void *a, const void *);
141 void add_initvectors(void);
142 void create_configuration(int argc, char **argv, int start_args);
143 void prepare_and_check_relocation_system(void);
144 void compact_relocations(void);
145 void twirl(void);
146 int vdu_var(int);
147 void process_args(int argc, char **argv, int *howto, char *file,
148 int *start_args);
149
150 char *sprint0(int width, char prefix, char base, int value);
151 struct page_info *get_relocated_page(u_long destination, int size);
152
153 extern 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 */
164 void
165 init_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
231 void
232 compact_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
281 void
282 get_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
501 void
502 get_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
561 void
562 create_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
598 void
599 add_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
631 void
632 add_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 */
650 static int
651 vsync_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
663 void
664 create_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
766 int
767 main(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
879 ssize_t
880 boot32_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
910 void *
911 boot32_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
934 void *
935 boot32_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 */
959 int
960 page_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
967 struct page_info *
968 get_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
995 int
996 vdu_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
1007 void
1008 twirl(void)
1009 {
1010
1011 printf("%c%c", "|/-\\"[(int) twirl_cnt], 8);
1012 twirl_cnt++;
1013 twirl_cnt &= 3;
1014 }
1015
1016
1017 void
1018 process_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
1050 char *
1051 sprint0(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