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