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