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