vaseboot/VasEBoot-core/kern/mips/arc/init.c

467 lines
11 KiB
C

/*
* VAS_EBOOT -- GRand Unified Bootloader
* Copyright (C) 2009,2010 Free Software Foundation, Inc.
*
* VAS_EBOOT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VAS_EBOOT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VAS_EBOOT. If not, see <http://www.gnu.org/licenses/>.
*/
#include <VasEBoot/kernel.h>
#include <VasEBoot/misc.h>
#include <VasEBoot/env.h>
#include <VasEBoot/time.h>
#include <VasEBoot/types.h>
#include <VasEBoot/misc.h>
#include <VasEBoot/mm.h>
#include <VasEBoot/time.h>
#include <VasEBoot/machine/kernel.h>
#include <VasEBoot/machine/memory.h>
#include <VasEBoot/arc/console.h>
#include <VasEBoot/cpu/memory.h>
#include <VasEBoot/cpu/time.h>
#include <VasEBoot/memory.h>
#include <VasEBoot/term.h>
#include <VasEBoot/arc/arc.h>
#include <VasEBoot/offsets.h>
#include <VasEBoot/i18n.h>
#include <VasEBoot/disk.h>
#include <VasEBoot/partition.h>
const char *type_names[] = {
#ifdef VAS_EBOOT_CPU_WORDS_BIGENDIAN
NULL,
#endif
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
"eisa", "tc", "scsi", "dti", "multi", "disk", "tape", "cdrom", "worm",
"serial", "net", "video", "par", "point", "key", "audio", "other",
"rdisk", "fdisk", "tape", "modem", "monitor", "print", "pointer",
"keyboard", "term",
#ifndef VAS_EBOOT_CPU_WORDS_BIGENDIAN
"other",
#endif
"line", "network", NULL
};
static int
iterate_rec (const char *prefix, const struct VasEBoot_arc_component *parent,
VasEBoot_arc_iterate_devs_hook_t hook, void *hook_data,
int alt_names)
{
const struct VasEBoot_arc_component *comp;
FOR_ARC_CHILDREN(comp, parent)
{
char *name;
const char *cname = NULL;
if (comp->type < ARRAY_SIZE (type_names))
cname = type_names[comp->type];
if (!cname)
cname = "unknown";
if (alt_names)
name = VasEBoot_xasprintf ("%s/%s%lu", prefix, cname, comp->key);
else
name = VasEBoot_xasprintf ("%s%s(%lu)", prefix, cname, comp->key);
if (!name)
return 1;
if (hook (name, comp, hook_data))
{
VasEBoot_free (name);
return 1;
}
if (iterate_rec ((parent ? name : prefix), comp, hook, hook_data,
alt_names))
{
VasEBoot_free (name);
return 1;
}
VasEBoot_free (name);
}
return 0;
}
int
VasEBoot_arc_iterate_devs (VasEBoot_arc_iterate_devs_hook_t hook, void *hook_data,
int alt_names)
{
return iterate_rec ((alt_names ? "arc" : ""), NULL, hook, hook_data,
alt_names);
}
VasEBoot_err_t
VasEBoot_machine_mmap_iterate (VasEBoot_memory_hook_t hook, void *hook_data)
{
struct VasEBoot_arc_memory_descriptor *cur = NULL;
while (1)
{
VasEBoot_memory_type_t type;
cur = VAS_EBOOT_ARC_FIRMWARE_VECTOR->getmemorydescriptor (cur);
if (!cur)
return VAS_EBOOT_ERR_NONE;
switch (cur->type)
{
case VAS_EBOOT_ARC_MEMORY_EXCEPTION_BLOCK:
case VAS_EBOOT_ARC_MEMORY_SYSTEM_PARAMETER_BLOCK:
case VAS_EBOOT_ARC_MEMORY_FW_PERMANENT:
default:
type = VAS_EBOOT_MEMORY_RESERVED;
break;
case VAS_EBOOT_ARC_MEMORY_FW_TEMPORARY:
case VAS_EBOOT_ARC_MEMORY_FREE:
case VAS_EBOOT_ARC_MEMORY_LOADED:
case VAS_EBOOT_ARC_MEMORY_FREE_CONTIGUOUS:
type = VAS_EBOOT_MEMORY_AVAILABLE;
break;
case VAS_EBOOT_ARC_MEMORY_BADRAM:
type = VAS_EBOOT_MEMORY_BADRAM;
break;
}
if (hook (((VasEBoot_uint64_t) cur->start_page) << 12,
((VasEBoot_uint64_t) cur->num_pages) << 12, type, hook_data))
return VAS_EBOOT_ERR_NONE;
}
}
char *
VasEBoot_arc_alt_name_to_norm (const char *name, const char *suffix)
{
char *optr;
const char *iptr;
char * ret = VasEBoot_malloc (2 * VasEBoot_strlen (name) + VasEBoot_strlen (suffix));
int state = 0;
if (!ret)
return NULL;
optr = ret;
for (iptr = name + 4; *iptr; iptr++)
if (state == 0)
{
if (!VasEBoot_isdigit (*iptr))
*optr++ = *iptr;
else
{
*optr++ = '(';
*optr++ = *iptr;
state = 1;
}
}
else
{
if (VasEBoot_isdigit (*iptr))
*optr++ = *iptr;
else
{
*optr++ = ')';
state = 0;
}
}
if (state)
*optr++ = ')';
VasEBoot_strcpy (optr, suffix);
return ret;
}
static char *
norm_name_to_alt (const char *name)
{
char *optr;
const char *iptr;
int state = 0;
char * ret = VasEBoot_malloc (VasEBoot_strlen (name) + sizeof ("arc/"));
if (!ret)
return NULL;
optr = VasEBoot_stpcpy (ret, "arc/");
for (iptr = name; *iptr; iptr++)
{
if (state == 3)
{
*optr++ = '/';
state = 0;
}
if (*iptr == '(')
{
state = 1;
continue;
}
if (*iptr == ')')
{
if (state == 1)
*optr++ = '0';
state = 3;
continue;
}
*optr++ = *iptr;
if (state == 1)
state = 2;
}
*optr = '\0';
return ret;
}
extern VasEBoot_uint32_t VasEBoot_total_modules_size __attribute__ ((section(".text")));
VasEBoot_addr_t VasEBoot_modbase;
extern char _end[];
static char boot_location[256];
void
VasEBoot_machine_init (void)
{
struct VasEBoot_arc_memory_descriptor *cur = NULL;
VasEBoot_addr_t modend;
VasEBoot_memcpy (boot_location,
(char *) (VAS_EBOOT_DECOMPRESSOR_LINK_ADDR - 256), 256);
VasEBoot_modbase = ALIGN_UP ((VasEBoot_addr_t) _end, VAS_EBOOT_KERNEL_MACHINE_MOD_ALIGN);
modend = VasEBoot_modbase + VasEBoot_total_modules_size;
VasEBoot_console_init_early ();
/* FIXME: measure this. */
VasEBoot_arch_cpuclock = 150000000;
VasEBoot_install_get_time_ms (VasEBoot_rtc_get_time_ms);
while (1)
{
VasEBoot_uint64_t start, end;
cur = VAS_EBOOT_ARC_FIRMWARE_VECTOR->getmemorydescriptor (cur);
if (!cur)
break;
if (cur->type != VAS_EBOOT_ARC_MEMORY_FREE
&& cur->type != VAS_EBOOT_ARC_MEMORY_LOADED
&& cur->type != VAS_EBOOT_ARC_MEMORY_FREE_CONTIGUOUS)
continue;
start = ((VasEBoot_uint64_t) cur->start_page) << 12;
end = ((VasEBoot_uint64_t) cur->num_pages) << 12;
end += start;
if ((VasEBoot_uint64_t) start < (modend & 0x1fffffff))
start = (modend & 0x1fffffff);
if ((VasEBoot_uint64_t) end > 0x20000000)
end = 0x20000000;
if (end > start)
VasEBoot_mm_init_region ((void *) (VasEBoot_addr_t) (start | 0x80000000),
end - start);
}
VasEBoot_console_init_lately ();
VasEBoot_arcdisk_init ();
}
void
VasEBoot_machine_fini (int flags __attribute__ ((unused)))
{
}
void
VasEBoot_halt (void)
{
VAS_EBOOT_ARC_FIRMWARE_VECTOR->powerdown ();
VasEBoot_millisleep (1500);
VasEBoot_puts_ (N_("Shutdown failed"));
VasEBoot_refresh ();
while (1);
}
void
VasEBoot_exit (void)
{
VAS_EBOOT_ARC_FIRMWARE_VECTOR->exit ();
VasEBoot_millisleep (1500);
VasEBoot_puts_ (N_("Exit failed"));
VasEBoot_refresh ();
while (1);
}
static char *
get_part (char *dev)
{
char *ptr;
if (!*dev)
return 0;
ptr = dev + VasEBoot_strlen (dev) - 1;
if (ptr == dev || *ptr != ')')
return 0;
ptr--;
while (VasEBoot_isdigit (*ptr) && ptr > dev)
ptr--;
if (*ptr != '(' || ptr == dev)
return 0;
ptr--;
if (ptr - dev < (int) sizeof ("partition") - 2)
return 0;
ptr -= sizeof ("partition") - 2;
if (VasEBoot_memcmp (ptr, "partition", sizeof ("partition") - 1) != 0)
return 0;
return ptr;
}
static VasEBoot_disk_addr_t
get_partition_offset (char *part, VasEBoot_disk_addr_t *en)
{
VasEBoot_arc_fileno_t handle;
VasEBoot_disk_addr_t ret = -1;
struct VasEBoot_arc_fileinfo info;
VasEBoot_arc_err_t r;
if (VAS_EBOOT_ARC_FIRMWARE_VECTOR->open (part, VAS_EBOOT_ARC_FILE_ACCESS_OPEN_RO,
&handle))
return -1;
r = VAS_EBOOT_ARC_FIRMWARE_VECTOR->getfileinformation (handle, &info);
if (!r)
{
ret = (info.start >> 9);
*en = (info.end >> 9);
}
VAS_EBOOT_ARC_FIRMWARE_VECTOR->close (handle);
return ret;
}
struct get_device_name_ctx
{
char *partition_name;
VasEBoot_disk_addr_t poff, pend;
};
static int
get_device_name_iter (VasEBoot_disk_t disk __attribute__ ((unused)),
const VasEBoot_partition_t part, void *data)
{
struct get_device_name_ctx *ctx = data;
if (VasEBoot_partition_get_start (part) == ctx->poff
&& VasEBoot_partition_get_len (part) == ctx->pend)
{
ctx->partition_name = VasEBoot_partition_get_name (part);
return 1;
}
return 0;
}
void
VasEBoot_machine_get_bootlocation (char **device, char **path)
{
char *loaddev = boot_location;
char *pptr, *partptr;
char *dname;
VasEBoot_disk_addr_t poff = -1, pend = -1;
struct get_device_name_ctx ctx;
VasEBoot_disk_t parent = 0;
unsigned i;
for (i = 0; i < ARRAY_SIZE (type_names); i++)
if (type_names[i]
&& VasEBoot_memcmp (loaddev, type_names[i], VasEBoot_strlen (type_names[i])) == 0
&& loaddev[VasEBoot_strlen (type_names[i])] == '(')
break;
if (i == ARRAY_SIZE (type_names))
pptr = loaddev;
else
for (pptr = loaddev; *pptr && *pptr != '/' && *pptr != '\\'; pptr++);
if (*pptr)
{
char *iptr, *optr;
char sep = *pptr;
*path = VasEBoot_malloc (VasEBoot_strlen (pptr) + 1);
if (!*path)
return;
for (iptr = pptr, optr = *path; *iptr; iptr++, optr++)
if (*iptr == sep)
*optr = '/';
else
*optr = *iptr;
*optr = '\0';
*path = VasEBoot_strdup (pptr);
*pptr = '\0';
}
if (*loaddev == '\0')
{
const char *syspart = 0;
if (VAS_EBOOT_ARC_SYSTEM_PARAMETER_BLOCK->firmware_vector_length
>= (unsigned) ((char *) (&VAS_EBOOT_ARC_FIRMWARE_VECTOR->getenvironmentvariable + 1)
- (char *) VAS_EBOOT_ARC_FIRMWARE_VECTOR)
&& VAS_EBOOT_ARC_FIRMWARE_VECTOR->getenvironmentvariable)
syspart = VAS_EBOOT_ARC_FIRMWARE_VECTOR->getenvironmentvariable ("SystemPartition");
if (!syspart)
return;
loaddev = VasEBoot_strdup (syspart);
if (loaddev == NULL)
return;
}
partptr = get_part (loaddev);
if (partptr)
{
poff = get_partition_offset (loaddev, &pend);
*partptr = '\0';
}
dname = norm_name_to_alt (loaddev);
if (poff == (VasEBoot_addr_t) -1)
{
*device = dname;
if (loaddev != boot_location)
VasEBoot_free (loaddev);
return;
}
parent = VasEBoot_disk_open (dname);
if (!parent)
{
*device = dname;
if (loaddev != boot_location)
VasEBoot_free (loaddev);
return;
}
if (poff == 0
&& pend == VasEBoot_disk_native_sectors (parent))
{
VasEBoot_disk_close (parent);
*device = dname;
if (loaddev != boot_location)
VasEBoot_free (loaddev);
return;
}
ctx.partition_name = NULL;
ctx.poff = poff;
ctx.pend = pend;
VasEBoot_partition_iterate (parent, get_device_name_iter, &ctx);
VasEBoot_disk_close (parent);
if (! ctx.partition_name)
{
*device = dname;
if (loaddev != boot_location)
VasEBoot_free (loaddev);
return;
}
*device = VasEBoot_xasprintf ("%s,%s", dname,
ctx.partition_name);
VasEBoot_free (ctx.partition_name);
VasEBoot_free (dname);
if (loaddev != boot_location)
VasEBoot_free (loaddev);
}