/* $NetBSD: boot32.c,v 1.43.2.2 2019/01/26 21:59:59 pgoyette Exp $ */
/*-
* Copyright (c) 2002 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Thanks a bunch for Ben's framework for the bootloader and its suporting
* libs. This file tries to actually boot NetBSD/acorn32 !
*
*/
#include <lib/libsa/stand.h>
#include <lib/libsa/loadfile.h>
#include <lib/libkern/libkern.h>
#include <riscoscalls.h>
#include <srt0.h>
#include <sys/boot_flag.h>
#include <machine/vmparam.h>
#include <arm/arm32/pte.h>
#include <machine/bootconfig.h>
extern char end[];
/* debugging flags */
int debug = 1;
/* constants */
#define PODRAM_START (512*1024*1024) /* XXX Kinetic cards XXX */
#define MAX_RELOCPAGES 4096
#define DEFAULT_ROOT "/dev/wd0a"
#define IO_BLOCKS 16 /* move these to the bootloader structure? */
#define ROM_BLOCKS 16
#define PODRAM_BLOCKS 16
/* booter variables */
char scrap[80], twirl_cnt; /* misc */
char booted_file[80];
struct bootconfig *bconfig; /* bootconfig passing */
u_long bconfig_new_phys; /* physical address its bound */
/* computer knowledge */
u_int monitor_type, monitor_sync, ioeb_flags, lcd_flags;
u_int superio_flags, superio_flags_basic, superio_flags_extra;
/* sizes */
int nbpp, memory_table_size, memory_image_size;
/* relocate info */
u_long reloc_tablesize, *reloc_instruction_table;
u_long *reloc_pos; /* current empty entry */
int reloc_entries; /* number of relocations */
int first_mapped_DRAM_page_index; /* offset in RISC OS blob */
int first_mapped_PODRAM_page_index;/* offset in RISC OS blob */
struct page_info *mem_pages_info; /* {nr, virt, phys}* */
struct page_info *free_relocation_page; /* points to the page_info chain*/
struct page_info *relocate_code_page; /* points to the copied code */
struct page_info *bconfig_page; /* page for passing on settings */
unsigned char *memory_page_types; /* packed array of 4 bit typeId */
u_long *initial_page_tables; /* pagetables to be booted from */
/* XXX rename *_BLOCKS to MEM_BLOCKS */
/* DRAM/VRAM/ROM/IO info */
/* where the display is */
u_long videomem_start, videomem_pages, display_size;
u_long pv_offset, top_physdram; /* kernel_base - phys. diff */
u_long top_1Mb_dram; /* the lower mapped top 1Mb */
u_long new_L1_pages_phys; /* physical address of L1 pages */
/* for bootconfig passing */
u_long total_podram_pages, total_dram_pages, total_vram_pages;
int dram_blocks, podram_blocks; /* number of mem. objects/type */
int vram_blocks, rom_blocks, io_blocks;
u_long DRAM_addr[DRAM_BLOCKS], DRAM_pages[DRAM_BLOCKS];
/* processor only RAM */
u_long PODRAM_addr[PODRAM_BLOCKS], PODRAM_pages[PODRAM_BLOCKS];
u_long VRAM_addr[VRAM_BLOCKS], VRAM_pages[VRAM_BLOCKS];
u_long ROM_addr[ROM_BLOCKS], ROM_pages[ROM_BLOCKS];
u_long IO_addr[IO_BLOCKS], IO_pages[IO_BLOCKS];
/* RISC OS memory pages we claimed */
u_long firstpage, lastpage, totalpages; /* RISC OS pagecounters */
/* RISC OS memory */
char *memory_image, *bottom_memory, *top_memory;
/* kernel info */
u_long marks[MARK_MAX]; /* loader mark pointers */
u_long kernel_physical_start; /* where does it get relocated */
u_long kernel_physical_maxsize; /* Max allowed size of kernel */
u_long kernel_free_vm_start; /* where does the free VM start */
/* some free space to mess with */
u_long scratch_virtualbase, scratch_physicalbase;
/* bootprogram identifiers */
extern const char bootprog_rev[];
extern const char bootprog_name[];
/* predefines / prototypes */
void init_datastructures(void);
void get_memory_configuration(void);
void get_memory_map(void);
void create_initial_page_tables(void);
void add_pagetables_at_top(void);
int page_info_cmp(const void *a, const void *);
void add_initvectors(void);
void create_configuration(int argc, char **argv, int start_args);
void prepare_and_check_relocation_system(void);
void compact_relocations(void);
void twirl(void);
int vdu_var(int);
void process_args(int argc, char **argv, int *howto, char *file,
int *start_args);
char *sprint0(int width, char prefix, char base, int value);
struct page_info *get_relocated_page(u_long destination, int size);
extern void start_kernel(
int relocate_code_page,
int relocation_pv_offset,
int configuration_structure_in_flat_physical_space,
int virtual_address_relocation_table,
int physical_address_of_new_L1_pages,
int kernel_entry_point
); /* asm */
/* the loader itself */
void
init_datastructures(void)
{
/* Get number of pages and the memorytablesize */
osmemory_read_arrangement_table_size(&memory_table_size, &nbpp);
/* Allocate 99% - (small fixed amount) of the heap for memory_image */
memory_image_size = (int)HIMEM - (int)end - 512 * 1024;
memory_image_size /= 100;
memory_image_size *= 99;
if (memory_image_size <= 256*1024)
panic("Insufficient memory");
memory_image = alloc(memory_image_size);
if (!memory_image)
panic("Can't alloc get my memory image ?");
bottom_memory = memory_image;
top_memory = memory_image + memory_image_size;
firstpage = ((int)bottom_memory / nbpp) + 1; /* safety */
lastpage = ((int)top_memory / nbpp) - 1;
totalpages = lastpage - firstpage;
printf("Allocated %ld memory pages, each of %d kilobytes.\n\n",
totalpages, nbpp>>10 );
/*
* Setup the relocation table. Its a simple array of 3 * 32 bit
* entries. The first word in the array is the number of relocations
* to be done
*/
reloc_tablesize = (MAX_RELOCPAGES+1)*3*sizeof(u_long);
reloc_instruction_table = alloc(reloc_tablesize);
if (!reloc_instruction_table)
panic("Can't alloc my relocate instructions pages");
reloc_entries = 0;
reloc_pos = reloc_instruction_table;
*reloc_pos++ = 0;
/*
* Set up the memory translation info structure. We need to allocate
* one more for the end of list marker. See get_memory_map.
*/
mem_pages_info = alloc((totalpages + 1)*sizeof(struct page_info));
if (!mem_pages_info)
panic("Can't alloc my phys->virt page info");
/*
* Allocate memory for the memory arrangement table. We use this
* structure to retrieve memory page properties to clasify them.
*/
memory_page_types = alloc(memory_table_size);
if (!memory_page_types)
panic("Can't alloc my memory page type block");
/*
* Initial page tables is 16 kb per definition since only sections are
* used.
*/
initial_page_tables = alloc(16*1024);
if (!initial_page_tables)
panic("Can't alloc my initial page tables");
}
void
compact_relocations(void)
{
u_long *reloc_entry, current_length, length;
u_long src, destination, current_src, current_destination;
u_long *current_entry;
current_entry = reloc_entry = reloc_instruction_table + 1;
/* prime the loop */
current_src = reloc_entry[0];
current_destination = reloc_entry[1];
current_length = reloc_entry[2];
reloc_entry += 3;
while (reloc_entry < reloc_pos) {
src = reloc_entry[0];
destination = reloc_entry[1];
length = reloc_entry[2];
if (src == (current_src + current_length) &&
destination == (current_destination + current_length)) {
/* can merge */
current_length += length;
} else {
/* nothing else to do, so save the length */
current_entry[2] = current_length;
/* fill in next entry */
current_entry += 3;
current_src = current_entry[0] = src;
current_destination = current_entry[1] = destination;
current_length = length;
}
reloc_entry += 3;
}
/* save last length */
current_entry[2] = current_length;
current_entry += 3;
/* workout new count of entries */
length = current_entry - (reloc_instruction_table + 1);
printf("Compacted relocations from %d entries to %ld\n",
reloc_entries, length/3);
/* update table to reflect new size */
reloc_entries = length/3;
reloc_instruction_table[0] = length/3;
reloc_pos = current_entry;
}
void
get_memory_configuration(void)
{
int loop, current_page_type, page_count, phys_page;
int page, count, top_bank, video_bank;
int mapped_screen_memory;
int one_mb_pages;
u_long top;
printf("Getting memory configuration ");
osmemory_read_arrangement_table(memory_page_types);
/* init counters */
vram_blocks = dram_blocks = rom_blocks = io_blocks = podram_blocks = 0;
current_page_type = -1;
phys_page = 0; /* physical address in pages */
page_count = 0; /* page counter in this block */
loop = 0; /* loop variable over entries */
/* iterating over a packed array of 2 page types/byte i.e. 8 kb/byte */
while (loop < 2*memory_table_size) {
page = memory_page_types[loop / 2]; /* read twice */
if (loop & 1) page >>= 4; /* take other nibble */
/*
* bits 0-2 give type, bit3 means the bit page is
* allocatable
*/
page &= 0x7; /* only take bottom 3 bits */
if (page != current_page_type) {
/* passed a boundary ... note this block */
/*
* splitting in different vars is for
* compatability reasons
*/
switch (current_page_type) {
case -1:
case 0:
break;
case osmemory_TYPE_DRAM:
if ((phys_page * nbpp)< PODRAM_START) {
DRAM_addr[dram_blocks] =
phys_page * nbpp;
DRAM_pages[dram_blocks] =
page_count;
dram_blocks++;
} else {
PODRAM_addr[podram_blocks] =
phys_page * nbpp;
PODRAM_pages[podram_blocks] =
page_count;
podram_blocks++;
}
break;
case osmemory_TYPE_VRAM:
VRAM_addr[vram_blocks] = phys_page * nbpp;
VRAM_pages[vram_blocks] = page_count;
vram_blocks++;
break;
case osmemory_TYPE_ROM:
ROM_addr[rom_blocks] = phys_page * nbpp;
ROM_pages[rom_blocks] = page_count;
rom_blocks++;
break;
case osmemory_TYPE_IO:
IO_addr[io_blocks] = phys_page * nbpp;
IO_pages[io_blocks] = page_count;
io_blocks++;
break;
default:
printf("WARNING : found unknown "
"memory object %d ", current_page_type);
printf(" at 0x%s",
sprint0(8,'0','x', phys_page * nbpp));
printf(" for %s k\n",
sprint0(5,' ','d', (page_count*nbpp)>>10));
break;
}
current_page_type = page;
phys_page = loop;
page_count = 0;
}
/*
* smallest unit we recognise is one page ... silly
* could be upto 64 pages i.e. 256 kb
*/
page_count += 1;
loop += 1;
if ((loop & 31) == 0) twirl();
}
printf(" \n\n");
if (VRAM_pages[0] == 0) {
/* map DRAM as video memory */
display_size =
vdu_var(os_VDUVAR_TOTAL_SCREEN_SIZE) & ~(nbpp-1);
#if 0
mapped_screen_memory = 1024 * 1024; /* max allowed on RiscPC */
videomem_pages = (mapped_screen_memory / nbpp);
videomem_start = DRAM_addr[0];
DRAM_addr[0] += videomem_pages * nbpp;
DRAM_pages[0] -= videomem_pages;
#else
mapped_screen_memory = display_size;
videomem_pages = mapped_screen_memory / nbpp;
one_mb_pages = (1024*1024)/nbpp;
/*
* OK... we need one Mb at the top for compliance with current
* kernel structure. This ought to be abolished one day IMHO.
* Also we have to take care that the kernel needs to be in
* DRAM0a and even has to start there.
* XXX one Mb simms are the smallest supported XXX
*/
top_bank = dram_blocks-1;
video_bank = top_bank;
if (DRAM_pages[top_bank] == one_mb_pages) video_bank--;
if (DRAM_pages[video_bank] < videomem_pages)
panic("Weird memory configuration found; please "
"contact acorn32 portmaster.");
/* split off the top 1Mb */
DRAM_addr [top_bank+1] = DRAM_addr[top_bank] +
(DRAM_pages[top_bank] - one_mb_pages)*nbpp;
DRAM_pages[top_bank+1] = one_mb_pages;
DRAM_pages[top_bank ] -= one_mb_pages;
dram_blocks++;
/* Map video memory at the end of the choosen DIMM */
videomem_start = DRAM_addr[video_bank] +
(DRAM_pages[video_bank] - videomem_pages)*nbpp;
DRAM_pages[video_bank] -= videomem_pages;
/* sanity */
if (DRAM_pages[top_bank] == 0) {
DRAM_addr [top_bank] = DRAM_addr [top_bank+1];
DRAM_pages[top_bank] = DRAM_pages[top_bank+1];
dram_blocks--;
}
#endif
} else {
/* use VRAM */
mapped_screen_memory = 0;
videomem_start = VRAM_addr[0];
videomem_pages = VRAM_pages[0];
display_size = videomem_pages * nbpp;
}
if (mapped_screen_memory) {
printf("Used %d kb DRAM ", mapped_screen_memory / 1024);
printf("at 0x%s for video memory\n",
sprint0(8,'0','x', videomem_start));
}
/* find top of (PO)DRAM pages */
top_physdram = 0;
for (loop = 0; loop < podram_blocks; loop++) {
top = PODRAM_addr[loop] + PODRAM_pages[loop]*nbpp;
if (top > top_physdram) top_physdram = top;
}
for (loop = 0; loop < dram_blocks; loop++) {
top = DRAM_addr[loop] + DRAM_pages[loop]*nbpp;
if (top > top_physdram) top_physdram = top;
}
if (top_physdram == 0)
panic("reality check: No DRAM in this machine?");
if (((top_physdram >> 20) << 20) != top_physdram)
panic("Top is not not aligned on a Mb; "
"remove very small DIMMS?");
/* pretty print the individual page types */
for (count = 0; count < rom_blocks; count++) {
printf("Found ROM (%d)", count);
printf(" at 0x%s", sprint0(8,'0','x', ROM_addr[count]));
printf(" for %s k\n",
sprint0(5,' ','d', (ROM_pages[count]*nbpp)>>10));
}
for (count = 0; count < io_blocks; count++) {
printf("Found I/O (%d)", count);
printf(" at 0x%s", sprint0(8,'0','x', IO_addr[count]));
printf(" for %s k\n",
sprint0(5,' ','d', (IO_pages[count]*nbpp)>>10));
}
/* for DRAM/VRAM also count the number of pages */
total_dram_pages = 0;
for (count = 0; count < dram_blocks; count++) {
total_dram_pages += DRAM_pages[count];
printf("Found DRAM (%d)", count);
printf(" at 0x%s", sprint0(8,'0','x', DRAM_addr[count]));
printf(" for %s k\n",
sprint0(5,' ','d', (DRAM_pages[count]*nbpp)>>10));
}
total_vram_pages = 0;
for (count = 0; count < vram_blocks; count++) {
total_vram_pages += VRAM_pages[count];
printf("Found VRAM (%d)", count);
printf(" at 0x%s", sprint0(8,'0','x', VRAM_addr[count]));
printf(" for %s k\n",
sprint0(5,' ','d', (VRAM_pages[count]*nbpp)>>10));
}
total_podram_pages = 0;
for (count = 0; count < podram_blocks; count++) {
total_podram_pages += PODRAM_pages[count];
printf("Found Processor only (S)DRAM (%d)", count);
printf(" at 0x%s", sprint0(8,'0','x', PODRAM_addr[count]));
printf(" for %s k\n",
sprint0(5,' ','d', (PODRAM_pages[count]*nbpp)>>10));
}
}
void
get_memory_map(void)
{
struct page_info *page_info;
int page, inout;
int phys_addr;
printf("\nGetting actual memorymapping");
for (page = 0, page_info = mem_pages_info;
page < totalpages;
page++, page_info++) {
page_info->pagenumber = 0; /* not used */
page_info->logical = (firstpage + page) * nbpp;
page_info->physical = 0; /* result comes here */
/* to avoid triggering a `bug' in RISC OS 4, page it in */
*((int *)page_info->logical) = 0;
}
/* close list */
page_info->pagenumber = -1;
inout = osmemory_GIVEN_LOG_ADDR | osmemory_RETURN_PAGE_NO |
osmemory_RETURN_PHYS_ADDR;
osmemory_page_op(inout, mem_pages_info, totalpages);
printf(" ; sorting ");
qsort(mem_pages_info, totalpages, sizeof(struct page_info),
&page_info_cmp);
printf(".\n");
/*
* get the first DRAM index and show the physical memory
* fragments we got
*/
printf("\nFound physical memory blocks :\n");
first_mapped_DRAM_page_index = -1;
first_mapped_PODRAM_page_index = -1;
for (page=0; page < totalpages; page++) {
phys_addr = mem_pages_info[page].physical;
printf("[0x%x", phys_addr);
while (mem_pages_info[page+1].physical - phys_addr == nbpp) {
if (first_mapped_DRAM_page_index < 0 &&
phys_addr >= DRAM_addr[0])
first_mapped_DRAM_page_index = page;
if (first_mapped_PODRAM_page_index < 0 &&
phys_addr >= PODRAM_addr[0])
first_mapped_PODRAM_page_index = page;
page++;
phys_addr = mem_pages_info[page].physical;
}
printf("-0x%x] ", phys_addr + nbpp -1);
}
printf("\n\n");
if (first_mapped_PODRAM_page_index < 0 && PODRAM_addr[0])
panic("Found no (S)DRAM mapped in the bootloader");
if (first_mapped_DRAM_page_index < 0)
panic("No DRAM mapped in the bootloader");
}
void
create_initial_page_tables(void)
{
u_long page, section, addr, kpage;
/* mark a section by the following bits and domain 0, AP=01, CB=0 */
/* A P C B section
domain */
section = (0<<11) | (1<<10) | (0<<3) | (0<<2) | (1<<4) | (1<<1) |
(0) | (0 << 5);
/* first of all a full 1:1 mapping */
for (page = 0; page < 4*1024; page++)
initial_page_tables[page] = (page<<20) | section;
/*
* video memory is mapped 1:1 in the DRAM section or in VRAM
* section
*
* map 1Mb from top of DRAM memory to bottom 1Mb of virtual memmap
*/
top_1Mb_dram = (((top_physdram - 1024*1024) >> 20) << 20);
initial_page_tables[0] = top_1Mb_dram | section;
/*
* map 16 Mb of kernel space to KERNEL_BASE
* i.e. marks[KERNEL_START]
*/
for (page = 0; page < 16; page++) {
addr = (kernel_physical_start >> 20) + page;
kpage = (marks[MARK_START] >> 20) + page;
initial_page_tables[kpage] = (addr << 20) | section;
}
}
void
add_pagetables_at_top(void)
{
int page;
u_long src, dst, fragaddr;
/* Special : destination must be on a 16 Kb boundary */
/* get 4 pages on the top of the physical memory and copy PT's in it */
new_L1_pages_phys = top_physdram - 4 * nbpp;
/*
* If the L1 page tables are not 16 kb aligned, adjust base
* until it is
*/
while (new_L1_pages_phys & (16*1024-1))
new_L1_pages_phys -= nbpp;
if (new_L1_pages_phys & (16*1024-1))
panic("Paranoia : L1 pages not on 16Kb boundary");
dst = new_L1_pages_phys;
src = (u_long)initial_page_tables;
for (page = 0; page < 4; page++) {
/* get a page for a fragment */
fragaddr = get_relocated_page(dst, nbpp)->logical;
memcpy((void *)fragaddr, (void *)src, nbpp);
src += nbpp;
dst += nbpp;
}
}
void
add_initvectors(void)
{
u_long *pos;
u_long vectoraddr, count;
/* the top 1Mb of the physical DRAM pages is mapped at address 0 */
vectoraddr = get_relocated_page(top_1Mb_dram, nbpp)->logical;
/* fill the vectors with `movs pc, lr' opcodes */
pos = (u_long *)vectoraddr; memset(pos, 0, nbpp);
for (count = 0; count < 128; count++) *pos++ = 0xE1B0F00E;
}
/*
* Work out the display's vertical sync rate. One might hope that there
* would be a simpler way than by counting vsync interrupts for a second,
* but if there is, I can't find it.
*/
static int
vsync_rate(void)
{
uint8_t count0;
unsigned int time0;
count0 = osbyte_read(osbyte_VAR_VSYNC_TIMER);
time0 = os_read_monotonic_time();
while (os_read_monotonic_time() - time0 < 100)
continue;
return (uint8_t)(count0 - osbyte_read(osbyte_VAR_VSYNC_TIMER));
}
void
create_configuration(int argc, char **argv, int start_args)
{
int i, root_specified, id_low, id_high;
char *pos;
bconfig_new_phys = kernel_free_vm_start - pv_offset;
bconfig_page = get_relocated_page(bconfig_new_phys, nbpp);
bconfig = (struct bootconfig *)(bconfig_page->logical);
kernel_free_vm_start += nbpp;
/* get some miscelanious info for the bootblock */
os_readsysinfo_monitor_info(NULL, (int *)&monitor_type, (int *)&monitor_sync);
os_readsysinfo_chip_presence((int *)&ioeb_flags, (int *)&superio_flags, (int *)&lcd_flags);
os_readsysinfo_superio_features((int *)&superio_flags_basic,
(int *)&superio_flags_extra);
os_readsysinfo_unique_id(&id_low, &id_high);
/* fill in the bootconfig *bconfig structure : generic version II */
memset(bconfig, 0, sizeof(*bconfig));
bconfig->magic = BOOTCONFIG_MAGIC;
bconfig->version = BOOTCONFIG_VERSION;
strcpy(bconfig->kernelname, booted_file);
/*
* get the kernel base name and update the RiscOS name to a
* Unix name
*/
i = strlen(booted_file);
while (i >= 0 && booted_file[i] != '.') i--;
if (i) {
strcpy(bconfig->kernelname, "/");
strcat(bconfig->kernelname, booted_file+i+1);
}
pos = bconfig->kernelname+1;
while (*pos) {
if (*pos == '/') *pos = '.';
pos++;
}
/* set the machine_id */
memcpy(&(bconfig->machine_id), &id_low, 4);
/* check if the `root' is specified */
root_specified = 0;
strcpy(bconfig->args, "");
for (i = start_args; i < argc; i++) {
if (strncmp(argv[i], "root=",5) ==0) root_specified = 1;
if (i > start_args)
strcat(bconfig->args, " ");
strcat(bconfig->args, argv[i]);
}
if (!root_specified) {
if (start_args < argc)
strcat(bconfig->args, " ");
strcat(bconfig->args, "root=");
strcat(bconfig->args, DEFAULT_ROOT);
}
/* mark kernel pointers */
bconfig->kernvirtualbase = marks[MARK_START];
bconfig->kernphysicalbase = kernel_physical_start;
bconfig->kernsize = kernel_free_vm_start -
marks[MARK_START];
bconfig->ksym_start = marks[MARK_SYM];
bconfig->ksym_end = marks[MARK_SYM] + marks[MARK_NSYM];
/* setup display info */
bconfig->display_phys = videomem_start;
bconfig->display_start = videomem_start;
bconfig->display_size = display_size;
bconfig->width = vdu_var(os_MODEVAR_XWIND_LIMIT);
bconfig->height = vdu_var(os_MODEVAR_YWIND_LIMIT);
bconfig->log2_bpp = vdu_var(os_MODEVAR_LOG2_BPP);
bconfig->framerate = vsync_rate();
/* fill in memory info */
bconfig->pagesize = nbpp;
bconfig->drampages = total_dram_pages +
total_podram_pages; /* XXX */
bconfig->vrampages = total_vram_pages;
bconfig->dramblocks = dram_blocks + podram_blocks; /*XXX*/
bconfig->vramblocks = vram_blocks;
for (i = 0; i < dram_blocks; i++) {
bconfig->dram[i].address = DRAM_addr[i];
bconfig->dram[i].pages = DRAM_pages[i];
bconfig->dram[i].flags = PHYSMEM_TYPE_GENERIC;
}
for (; i < dram_blocks + podram_blocks; i++) {
bconfig->dram[i].address = PODRAM_addr[i-dram_blocks];
bconfig->dram[i].pages = PODRAM_pages[i-dram_blocks];
bconfig->dram[i].flags = PHYSMEM_TYPE_PROCESSOR_ONLY;
}
for (i = 0; i < vram_blocks; i++) {
bconfig->vram[i].address = VRAM_addr[i];
bconfig->vram[i].pages = VRAM_pages[i];
bconfig->vram[i].flags = PHYSMEM_TYPE_GENERIC;
}
}
int get_riscos_ver(void);
#define ModuleName_UtilityModule "UtilityModule"
int
get_riscos_ver(void)
{
int module, section;
os_error *e;
char *name;
int version;
version = 0;
/* Full enumeration */
module = 0;
section = -1;
do {
e = xosmodule_enumeratewithversion(&module, §ion, &name,
NULL, NULL, &version);
if (!strncmp(name, ModuleName_UtilityModule,
sizeof (ModuleName_UtilityModule))) {
return version;
}
} while (e == NULL && section == -1);
return 0;
}
int main(int, char **);
int
main(int argc, char **argv)
{
int howto, start_args, ret;
int riscosver;
int class;
riscosver = get_riscos_ver();
/*
* RISC OS version is in BCD
* Top 16 bits = major version
* Bottom 16 bits = fractional part
* e.g. 3.71 = 0x00037100
*/
printf("\n\n");
printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
printf(">> Booting NetBSD/acorn32 on a RiscPC/A7000/NC\n");
printf(">> RISC OS version: %d.%d%d\n",
(riscosver >> 16) & 0xff,
(riscosver >> 12) & 0xf,
(riscosver >> 8) & 0xf);
printf("\n");
process_args(argc, argv, &howto, booted_file, &start_args);
printf("Booting %s (howto = 0x%x)\n", booted_file, howto);
init_datastructures();
get_memory_configuration();
get_memory_map();
/*
* point to the first free DRAM page guaranteed to be in
* strict order up
*/
if (podram_blocks != 0) {
free_relocation_page =
mem_pages_info + first_mapped_PODRAM_page_index;
kernel_physical_start = PODRAM_addr[0];
kernel_physical_maxsize = PODRAM_pages[0] * nbpp;
} else {
free_relocation_page =
mem_pages_info + first_mapped_DRAM_page_index;
kernel_physical_start = DRAM_addr[0];
kernel_physical_maxsize = DRAM_pages[0] * nbpp;
}
printf("\nLoading %s ", booted_file);
/* first count the kernel to get the markers */
ret = loadfile(booted_file, marks, COUNT_KERNEL);
if (ret == -1) panic("Kernel load failed"); /* lie to the user ... */
close(ret);
if (marks[MARK_END] - marks[MARK_START] > kernel_physical_maxsize)
{
panic("\nKernel is bigger than the first DRAM module, unable to boot\n");
}
/*
* calculate how much the difference is between physical and
* virtual space for the kernel
*/
pv_offset = ((u_long)marks[MARK_START] - kernel_physical_start);
/* round on a page */
kernel_free_vm_start = (marks[MARK_END] + nbpp-1) & ~(nbpp-1);
/* we seem to be forced to clear the marks[] ? */
memset(marks, 0, sizeof(marks));
/* really load it ! */
ret = loadfile(booted_file, marks, LOAD_KERNEL);
if (ret == -1) panic("Kernel load failed");
close(ret);
/* finish off the relocation information */
create_initial_page_tables();
add_initvectors();
add_pagetables_at_top();
create_configuration(argc, argv, start_args);
/*
* done relocating and creating information, now update and
* check the relocation mechanism
*/
compact_relocations();
/*
* grab a page to copy the bootstrap code into
*/
relocate_code_page = free_relocation_page++;
printf("\nStarting at 0x%lx, p@0x%lx\n", marks[MARK_ENTRY], kernel_physical_start);
printf("%ld entries, first one is 0x%lx->0x%lx for %lx bytes\n",
reloc_instruction_table[0],
reloc_instruction_table[1],
reloc_instruction_table[2],
reloc_instruction_table[3]);
printf("Will boot in a few secs due to relocation....\n"
"bye bye from RISC OS!");
/* dismount all filesystems */
xosfscontrol_shutdown();
/*
* OS_ReadSysInfo Platform class reason code not valid
* on RISC OS 3.
* XXX Don't know about RISC OS 4
*/
if (riscosver >= 0x40000) {
os_readsysinfo_platform_class(&class, NULL, NULL);
if (class != osreadsysinfo_Platform_Pace) {
/* reset devices, well try to anyway */
service_pre_reset();
}
} else {
service_pre_reset();
}
start_kernel(
/* r0 relocation code page (V) */ relocate_code_page->logical,
/* r1 relocation pv offset */
relocate_code_page->physical-relocate_code_page->logical,
/* r2 configuration structure */ bconfig_new_phys,
/* r3 relocation table (l) */
(int)reloc_instruction_table, /* one piece! */
/* r4 L1 page descriptor (P) */ new_L1_pages_phys,
/* r5 kernel entry point */ marks[MARK_ENTRY]
);
return 0;
}
ssize_t
boot32_read(int f, void *addr, size_t size)
{
void *fragaddr;
size_t fragsize;
ssize_t bytes_read, total;
/* printf("read at %p for %ld bytes\n", addr, size); */
total = 0;
while (size > 0) {
fragsize = nbpp; /* select one page */
if (size < nbpp) fragsize = size;/* clip to size left */
/* get a page for a fragment */
fragaddr = (void *)get_relocated_page((u_long) addr -
pv_offset, fragsize)->logical;
bytes_read = read(f, fragaddr, fragsize);
if (bytes_read < 0) return bytes_read; /* error! */
total += bytes_read; /* account read bytes */
if (bytes_read < fragsize)
return total; /* does this happen? */
size -= fragsize; /* advance */
addr += fragsize;
}
return total;
}
void *
boot32_memcpy(void *dst, const void *src, size_t size)
{
void *fragaddr;
size_t fragsize;
/* printf("memcpy to %p from %p for %ld bytes\n", dst, src, size); */
while (size > 0) {
fragsize = nbpp; /* select one page */
if (size < nbpp) fragsize = size;/* clip to size left */
/* get a page for a fragment */
fragaddr = (void *)get_relocated_page((u_long) dst -
pv_offset, fragsize)->logical;
memcpy(fragaddr, src, size);
src += fragsize; /* account copy */
dst += fragsize;
size-= fragsize;
}
return dst;
}
void *
boot32_memset(void *dst, int c, size_t size)
{
void *fragaddr;
size_t fragsize;
/* printf("memset %p for %ld bytes with %d\n", dst, size, c); */
while (size > 0) {
fragsize = nbpp; /* select one page */
if (size < nbpp) fragsize = size;/* clip to size left */
/* get a page for a fragment */
fragaddr = (void *)get_relocated_page((u_long)dst - pv_offset,
fragsize)->logical;
memset(fragaddr, c, fragsize);
dst += fragsize; /* account memsetting */
size-= fragsize;
}
return dst;
}
/* We can rely on the fact that two entries never have identical ->physical */
int
page_info_cmp(const void *a, const void *b)
{
return (((struct page_info *)a)->physical <
((struct page_info *)b)->physical) ? -1 : 1;
}
struct page_info *
get_relocated_page(u_long destination, int size)
{
struct page_info *page;
/* get a page for a fragment */
page = free_relocation_page;
if (free_relocation_page->pagenumber < 0) panic("\n\nOut of pages");
reloc_entries++;
if (reloc_entries >= MAX_RELOCPAGES)
panic("\n\nToo many relocations! What are you loading ??");
/* record the relocation */
if (free_relocation_page->physical & 0x3)
panic("\n\nphysical address is not aligned!");
if (destination & 0x3)
panic("\n\ndestination address is not aligned!");
*reloc_pos++ = free_relocation_page->physical;
*reloc_pos++ = destination;
*reloc_pos++ = size;
free_relocation_page++; /* advance */
return page;
}
int
vdu_var(int var)
{
int varlist[2], vallist[2];
varlist[0] = var;
varlist[1] = -1;
os_read_vdu_variables(varlist, vallist);
return vallist[0];
}
void
twirl(void)
{
printf("%c%c", "|/-\\"[(int) twirl_cnt], 8);
twirl_cnt++;
twirl_cnt &= 3;
}
void
process_args(int argc, char **argv, int *howto, char *file, int *start_args)
{
int i, j;
static char filename[80];
*howto = 0;
*file = NULL; *start_args = 1;
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-')
for (j = 1; argv[i][j]; j++)
BOOT_FLAG(argv[i][j], *howto);
else {
if (*file)
*start_args = i;
else {
strcpy(file, argv[i]);
*start_args = i+1;
}
break;
}
}
if (*file == NULL) {
if (*howto & RB_ASKNAME) {
printf("boot: ");
kgets(filename, sizeof(filename));
strcpy(file, filename);
} else
strcpy(file, "netbsd");
}
}
char *
sprint0(int width, char prefix, char base, int value)
{
static char format[50], scrap[50];
char *pos;
int length;
for (pos = format, length = 0; length<width; length++) *pos++ = prefix;
*pos++ = '%';
*pos++ = base;
*pos++ = (char) 0;
snprintf(scrap, sizeof(scrap), format, value);
length = strlen(scrap);
return scrap+length-width;
}