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