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