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