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