Initial revision
This commit is contained in:
commit
6a161fa938
80 changed files with 23264 additions and 0 deletions
99
kern/device.c
Normal file
99
kern/device.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
/* device.c - device manager */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/device.h>
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/net.h>
|
||||
#include <pupa/fs.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/misc.h>
|
||||
|
||||
static char *pupa_device_root;
|
||||
|
||||
pupa_err_t
|
||||
pupa_device_set_root (const char *name)
|
||||
{
|
||||
pupa_free (pupa_device_root);
|
||||
pupa_device_root = pupa_strdup (name);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
const char *
|
||||
pupa_device_get_root (void)
|
||||
{
|
||||
if (! pupa_device_root)
|
||||
pupa_error (PUPA_ERR_BAD_DEVICE, "no root device");
|
||||
|
||||
return pupa_device_root;
|
||||
}
|
||||
|
||||
pupa_device_t
|
||||
pupa_device_open (const char *name)
|
||||
{
|
||||
pupa_disk_t disk = 0;
|
||||
pupa_device_t dev = 0;
|
||||
|
||||
if (! name)
|
||||
{
|
||||
if (! pupa_device_root)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_DEVICE, "no device is set");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
name = pupa_device_root;
|
||||
}
|
||||
|
||||
dev = pupa_malloc (sizeof (*dev));
|
||||
if (! dev)
|
||||
goto fail;
|
||||
|
||||
/* Try to open a disk. */
|
||||
disk = pupa_disk_open (name);
|
||||
if (! disk)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_DEVICE, "unknown device");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev->disk = disk;
|
||||
dev->net = 0; /* FIXME */
|
||||
|
||||
return dev;
|
||||
|
||||
fail:
|
||||
if (disk)
|
||||
pupa_disk_close (disk);
|
||||
|
||||
pupa_free (dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_device_close (pupa_device_t device)
|
||||
{
|
||||
if (device->disk)
|
||||
pupa_disk_close (device->disk);
|
||||
|
||||
pupa_free (device);
|
||||
|
||||
return pupa_errno;
|
||||
}
|
474
kern/disk.c
Normal file
474
kern/disk.c
Normal file
|
@ -0,0 +1,474 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/machine/partition.h>
|
||||
#include <pupa/misc.h>
|
||||
|
||||
/* Disk cache. */
|
||||
struct pupa_disk_cache
|
||||
{
|
||||
unsigned long id;
|
||||
unsigned long sector;
|
||||
char *data;
|
||||
int lock;
|
||||
};
|
||||
|
||||
static struct pupa_disk_cache pupa_disk_cache_table[PUPA_DISK_CACHE_NUM];
|
||||
|
||||
#if 0
|
||||
static unsigned long pupa_disk_cache_hits;
|
||||
static unsigned long pupa_disk_cache_misses;
|
||||
|
||||
void
|
||||
pupa_disk_cache_get_performance (unsigned long *hits, unsigned long *misses)
|
||||
{
|
||||
*hits = pupa_disk_cache_hits;
|
||||
*misses = pupa_disk_cache_misses;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned
|
||||
pupa_disk_cache_get_index (unsigned long id, unsigned long sector)
|
||||
{
|
||||
return ((id * 2606459 + (sector >> PUPA_DISK_CACHE_BITS))
|
||||
% PUPA_DISK_CACHE_NUM);
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_disk_cache_invalidate (unsigned long id, unsigned long sector)
|
||||
{
|
||||
unsigned index;
|
||||
struct pupa_disk_cache *cache;
|
||||
|
||||
sector &= ~(PUPA_DISK_CACHE_SIZE - 1);
|
||||
index = pupa_disk_cache_get_index (id, sector);
|
||||
cache = pupa_disk_cache_table + index;
|
||||
|
||||
if (cache->id == id && cache->sector == sector && cache->data)
|
||||
{
|
||||
cache->lock = 1;
|
||||
pupa_free (cache->data);
|
||||
cache->data = 0;
|
||||
cache->lock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pupa_disk_cache_invalidate_all (void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < PUPA_DISK_CACHE_NUM; i++)
|
||||
{
|
||||
struct pupa_disk_cache *cache = pupa_disk_cache_table + i;
|
||||
|
||||
if (cache->data && ! cache->lock)
|
||||
{
|
||||
pupa_free (cache->data);
|
||||
cache->data = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
pupa_disk_cache_fetch (unsigned long id, unsigned long sector)
|
||||
{
|
||||
struct pupa_disk_cache *cache;
|
||||
unsigned index;
|
||||
|
||||
index = pupa_disk_cache_get_index (id, sector);
|
||||
cache = pupa_disk_cache_table + index;
|
||||
|
||||
if (cache->id == id && cache->sector == sector)
|
||||
{
|
||||
cache->lock = 1;
|
||||
#if 0
|
||||
pupa_disk_cache_hits++;
|
||||
#endif
|
||||
return cache->data;
|
||||
}
|
||||
|
||||
#if 0
|
||||
pupa_disk_cache_misses++;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_disk_cache_unlock (unsigned long id, unsigned long sector)
|
||||
{
|
||||
struct pupa_disk_cache *cache;
|
||||
unsigned index;
|
||||
|
||||
index = pupa_disk_cache_get_index (id, sector);
|
||||
cache = pupa_disk_cache_table + index;
|
||||
|
||||
if (cache->id == id && cache->sector == sector)
|
||||
cache->lock = 0;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_disk_cache_store (unsigned long id, unsigned long sector,
|
||||
const char *data)
|
||||
{
|
||||
unsigned index;
|
||||
struct pupa_disk_cache *cache;
|
||||
|
||||
pupa_disk_cache_invalidate (id, sector);
|
||||
|
||||
index = pupa_disk_cache_get_index (id, sector);
|
||||
cache = pupa_disk_cache_table + index;
|
||||
|
||||
cache->data = pupa_malloc (PUPA_DISK_SECTOR_SIZE << PUPA_DISK_CACHE_BITS);
|
||||
if (! cache->data)
|
||||
return pupa_errno;
|
||||
|
||||
pupa_memcpy (cache->data, data,
|
||||
PUPA_DISK_SECTOR_SIZE << PUPA_DISK_CACHE_BITS);
|
||||
cache->id = id;
|
||||
cache->sector = sector;
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static pupa_disk_dev_t pupa_disk_dev_list;
|
||||
|
||||
void
|
||||
pupa_disk_dev_register (pupa_disk_dev_t dev)
|
||||
{
|
||||
dev->next = pupa_disk_dev_list;
|
||||
pupa_disk_dev_list = dev;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_disk_dev_unregister (pupa_disk_dev_t dev)
|
||||
{
|
||||
pupa_disk_dev_t *p, q;
|
||||
|
||||
for (p = &pupa_disk_dev_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (q == dev)
|
||||
{
|
||||
*p = q->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pupa_disk_dev_iterate (int (*hook) (const char *name))
|
||||
{
|
||||
pupa_disk_dev_t p;
|
||||
|
||||
for (p = pupa_disk_dev_list; p; p = p->next)
|
||||
if ((p->iterate) (hook))
|
||||
break;
|
||||
}
|
||||
|
||||
pupa_disk_t
|
||||
pupa_disk_open (const char *name)
|
||||
{
|
||||
char *p;
|
||||
pupa_disk_t disk;
|
||||
pupa_disk_dev_t dev;
|
||||
char *raw = (char *) name;
|
||||
|
||||
disk = (pupa_disk_t) pupa_malloc (sizeof (*disk));
|
||||
if (! disk)
|
||||
return 0;
|
||||
|
||||
disk->dev = 0;
|
||||
disk->read_hook = 0;
|
||||
disk->partition = 0;
|
||||
disk->data = 0;
|
||||
disk->name = pupa_strdup (name);
|
||||
if (! disk->name)
|
||||
goto fail;
|
||||
|
||||
p = pupa_strchr (name, ',');
|
||||
if (p)
|
||||
{
|
||||
pupa_size_t len = p - name;
|
||||
|
||||
raw = pupa_malloc (len + 1);
|
||||
if (! raw)
|
||||
goto fail;
|
||||
|
||||
pupa_memcpy (raw, name, len);
|
||||
raw[len] = '\0';
|
||||
}
|
||||
|
||||
for (dev = pupa_disk_dev_list; dev; dev = dev->next)
|
||||
{
|
||||
if ((dev->open) (raw, disk) == PUPA_ERR_NONE)
|
||||
break;
|
||||
else if (pupa_errno == PUPA_ERR_UNKNOWN_DEVICE)
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
else
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (! dev)
|
||||
{
|
||||
pupa_error (PUPA_ERR_UNKNOWN_DEVICE, "no such disk");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (p && ! disk->has_partitions)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_DEVICE, "no partition on this disk");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
disk->dev = dev;
|
||||
|
||||
if (p)
|
||||
disk->partition = pupa_partition_probe (disk, p + 1);
|
||||
|
||||
fail:
|
||||
|
||||
if (raw && raw != name)
|
||||
pupa_free (raw);
|
||||
|
||||
if (pupa_errno != PUPA_ERR_NONE)
|
||||
{
|
||||
pupa_disk_close (disk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return disk;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_disk_close (pupa_disk_t disk)
|
||||
{
|
||||
if (disk->dev && disk->dev->close)
|
||||
(disk->dev->close) (disk);
|
||||
|
||||
pupa_free (disk->partition);
|
||||
pupa_free ((void *) disk->name);
|
||||
pupa_free (disk);
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_disk_check_range (pupa_disk_t disk, unsigned long *sector,
|
||||
unsigned long *offset, pupa_ssize_t size)
|
||||
{
|
||||
*sector += *offset >> PUPA_DISK_SECTOR_BITS;
|
||||
*offset &= PUPA_DISK_SECTOR_SIZE - 1;
|
||||
|
||||
if (disk->partition)
|
||||
{
|
||||
unsigned long start, len;
|
||||
|
||||
start = pupa_partition_get_start (disk->partition);
|
||||
len = pupa_partition_get_len (disk->partition);
|
||||
|
||||
if (*sector >= len
|
||||
|| len - *sector < ((*offset + size + PUPA_DISK_SECTOR_SIZE - 1)
|
||||
>> PUPA_DISK_SECTOR_BITS))
|
||||
return pupa_error (PUPA_ERR_OUT_OF_RANGE, "out of partition");
|
||||
|
||||
*sector += start;
|
||||
}
|
||||
|
||||
if (disk->total_sectors <= *sector
|
||||
|| ((*offset + size + PUPA_DISK_SECTOR_SIZE - 1)
|
||||
>> PUPA_DISK_SECTOR_BITS) > disk->total_sectors - *sector)
|
||||
return pupa_error (PUPA_ERR_OUT_OF_RANGE, "out of disk");
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Read data from the disk. */
|
||||
pupa_err_t
|
||||
pupa_disk_read (pupa_disk_t disk, unsigned long sector,
|
||||
unsigned long offset, unsigned long size, char *buf)
|
||||
{
|
||||
char *tmp_buf;
|
||||
|
||||
/* First of all, check if the region is within the disk. */
|
||||
if (pupa_disk_check_range (disk, §or, &offset, size) != PUPA_ERR_NONE)
|
||||
return pupa_errno;
|
||||
|
||||
/* Allocate a temporary buffer. */
|
||||
tmp_buf = pupa_malloc (PUPA_DISK_SECTOR_SIZE << PUPA_DISK_CACHE_BITS);
|
||||
if (! tmp_buf)
|
||||
return pupa_errno;
|
||||
|
||||
/* Until SIZE is zero... */
|
||||
while (size)
|
||||
{
|
||||
char *data;
|
||||
unsigned long start_sector;
|
||||
unsigned long len;
|
||||
unsigned long pos;
|
||||
|
||||
/* For reading bulk data. */
|
||||
start_sector = sector & ~(PUPA_DISK_CACHE_SIZE - 1);
|
||||
pos = (sector - start_sector) << PUPA_DISK_SECTOR_BITS;
|
||||
len = (PUPA_DISK_SECTOR_SIZE << PUPA_DISK_CACHE_BITS) - pos - offset;
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
/* Fetch the cache. */
|
||||
data = pupa_disk_cache_fetch (disk->id, start_sector);
|
||||
if (data)
|
||||
{
|
||||
/* Just copy it! */
|
||||
pupa_memcpy (buf, data + pos + offset, len);
|
||||
pupa_disk_cache_unlock (disk->id, start_sector);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise read data from the disk actually. */
|
||||
if ((disk->dev->read) (disk, start_sector,
|
||||
PUPA_DISK_CACHE_SIZE, tmp_buf)
|
||||
!= PUPA_ERR_NONE)
|
||||
{
|
||||
/* Uggh... Failed. Instead, just read necessary data. */
|
||||
unsigned num;
|
||||
|
||||
/* If more data is required, no way. */
|
||||
if (pos + size
|
||||
>= (PUPA_DISK_SECTOR_SIZE << PUPA_DISK_CACHE_BITS))
|
||||
goto finish;
|
||||
|
||||
num = ((size + PUPA_DISK_SECTOR_SIZE - 1)
|
||||
>> PUPA_DISK_SECTOR_BITS);
|
||||
if ((disk->dev->read) (disk, sector, num, tmp_buf))
|
||||
goto finish;
|
||||
|
||||
pupa_memcpy (buf, tmp_buf + offset, size);
|
||||
|
||||
/* Call the read hook, if any. */
|
||||
if (disk->read_hook)
|
||||
while (size)
|
||||
{
|
||||
(disk->read_hook) (sector, offset,
|
||||
((size > PUPA_DISK_SECTOR_SIZE)
|
||||
? PUPA_DISK_SECTOR_SIZE
|
||||
: size));
|
||||
sector++;
|
||||
size -= PUPA_DISK_SECTOR_SIZE - offset;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/* This must be the end. */
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Copy it and store it in the disk cache. */
|
||||
pupa_memcpy (buf, tmp_buf + pos + offset, len);
|
||||
pupa_disk_cache_store (disk->id, start_sector, tmp_buf);
|
||||
}
|
||||
|
||||
/* Call the read hook, if any. */
|
||||
if (disk->read_hook)
|
||||
{
|
||||
unsigned long s = sector;
|
||||
unsigned long l = len;
|
||||
|
||||
while (l)
|
||||
{
|
||||
(disk->read_hook) (s, offset,
|
||||
((l > PUPA_DISK_SECTOR_SIZE)
|
||||
? PUPA_DISK_SECTOR_SIZE
|
||||
: l));
|
||||
s++;
|
||||
l -= PUPA_DISK_SECTOR_SIZE - offset;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sector = start_sector + PUPA_DISK_CACHE_SIZE;
|
||||
buf += len;
|
||||
size -= len;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
finish:
|
||||
|
||||
pupa_free (tmp_buf);
|
||||
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_disk_write (pupa_disk_t disk, unsigned long sector,
|
||||
unsigned long offset, unsigned long size, const char *buf)
|
||||
{
|
||||
if (pupa_disk_check_range (disk, §or, &offset, size) != PUPA_ERR_NONE)
|
||||
return -1;
|
||||
|
||||
while (size)
|
||||
{
|
||||
if (offset != 0 || (size < PUPA_DISK_SECTOR_SIZE && size != 0))
|
||||
{
|
||||
char tmp_buf[PUPA_DISK_SECTOR_SIZE];
|
||||
unsigned long len;
|
||||
|
||||
if (pupa_disk_read (disk, sector, 0, PUPA_DISK_SECTOR_SIZE, tmp_buf)
|
||||
!= PUPA_ERR_NONE)
|
||||
goto finish;
|
||||
|
||||
len = PUPA_DISK_SECTOR_SIZE - offset;
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
pupa_memcpy (tmp_buf + offset, buf, len);
|
||||
|
||||
pupa_disk_cache_invalidate (disk->id, sector);
|
||||
|
||||
if ((disk->dev->write) (disk, sector, 1, tmp_buf) != PUPA_ERR_NONE)
|
||||
goto finish;
|
||||
|
||||
sector++;
|
||||
buf += len;
|
||||
size -= len;
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long len;
|
||||
unsigned long n;
|
||||
|
||||
len = size & ~(PUPA_DISK_SECTOR_SIZE - 1);
|
||||
n = size >> PUPA_DISK_SECTOR_BITS;
|
||||
|
||||
if ((disk->dev->write) (disk, sector, n, buf) != PUPA_ERR_NONE)
|
||||
goto finish;
|
||||
|
||||
while (n--)
|
||||
pupa_disk_cache_invalidate (disk->id, sector++);
|
||||
|
||||
buf += len;
|
||||
size -= len;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
|
||||
return pupa_errno;
|
||||
}
|
599
kern/dl.c
Normal file
599
kern/dl.c
Normal file
|
@ -0,0 +1,599 @@
|
|||
/* dl.c - loadable module support */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <pupa/elf.h>
|
||||
#include <pupa/dl.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/file.h>
|
||||
|
||||
#if PUPA_HOST_SIZEOF_VOID_P == 4
|
||||
|
||||
typedef Elf32_Word Elf_Word;
|
||||
typedef Elf32_Addr Elf_Addr;
|
||||
typedef Elf32_Ehdr Elf_Ehdr;
|
||||
typedef Elf32_Shdr Elf_Shdr;
|
||||
typedef Elf32_Sym Elf_Sym;
|
||||
|
||||
# define ELF_ST_BIND(val) ELF32_ST_BIND (val)
|
||||
# define ELF_ST_TYPE(val) ELF32_ST_TYPE (val)
|
||||
|
||||
#elif PUPA_HOST_SIZEOF_VOID_P == 8
|
||||
|
||||
typedef Elf64_Word Elf_Word;
|
||||
typedef Elf64_Addr Elf_Addr;
|
||||
typedef Elf64_Ehdr Elf_Ehdr;
|
||||
typedef Elf64_Shdr Elf_Shdr;
|
||||
typedef Elf64_Sym Elf_Sym;
|
||||
|
||||
# define ELF_ST_BIND(val) ELF64_ST_BIND (val)
|
||||
# define ELF_ST_TYPE(val) ELF64_ST_TYPE (val)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
struct pupa_dl_list
|
||||
{
|
||||
struct pupa_dl_list *next;
|
||||
pupa_dl_t mod;
|
||||
};
|
||||
typedef struct pupa_dl_list *pupa_dl_list_t;
|
||||
|
||||
static pupa_dl_list_t pupa_dl_head;
|
||||
|
||||
static pupa_err_t
|
||||
pupa_dl_add (pupa_dl_t mod)
|
||||
{
|
||||
pupa_dl_list_t l;
|
||||
|
||||
if (pupa_dl_get (mod->name))
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE,
|
||||
"`%s' is already loaded", mod->name);
|
||||
|
||||
l = (pupa_dl_list_t) pupa_malloc (sizeof (*l));
|
||||
if (! l)
|
||||
return pupa_errno;
|
||||
|
||||
l->mod = mod;
|
||||
l->next = pupa_dl_head;
|
||||
pupa_dl_head = l;
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_dl_remove (pupa_dl_t mod)
|
||||
{
|
||||
pupa_dl_list_t *p, q;
|
||||
|
||||
for (p = &pupa_dl_head, q = *p; q; p = &q->next, q = *p)
|
||||
if (q->mod == mod)
|
||||
{
|
||||
*p = q->next;
|
||||
pupa_free (q);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pupa_dl_t
|
||||
pupa_dl_get (const char *name)
|
||||
{
|
||||
pupa_dl_list_t l;
|
||||
|
||||
for (l = pupa_dl_head; l; l = l->next)
|
||||
if (pupa_strcmp (name, l->mod->name) == 0)
|
||||
return l->mod;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct pupa_symbol
|
||||
{
|
||||
struct pupa_symbol *next;
|
||||
const char *name;
|
||||
void *addr;
|
||||
pupa_dl_t mod; /* The module to which this symbol belongs. */
|
||||
};
|
||||
typedef struct pupa_symbol *pupa_symbol_t;
|
||||
|
||||
/* The size of the symbol table. */
|
||||
#define PUPA_SYMTAB_SIZE 509
|
||||
|
||||
/* The symbol table (using an open-hash). */
|
||||
static struct pupa_symbol *pupa_symtab[PUPA_SYMTAB_SIZE];
|
||||
|
||||
/* Simple hash function. */
|
||||
static unsigned
|
||||
pupa_symbol_hash (const char *s)
|
||||
{
|
||||
unsigned key = 0;
|
||||
|
||||
while (*s)
|
||||
key = key * 65599 + *s++;
|
||||
|
||||
return (key + (key >> 5)) % PUPA_SYMTAB_SIZE;
|
||||
}
|
||||
|
||||
/* Resolve the symbol name NAME and return the address.
|
||||
Return NULL, if not found. */
|
||||
void *
|
||||
pupa_dl_resolve_symbol (const char *name)
|
||||
{
|
||||
pupa_symbol_t sym;
|
||||
|
||||
for (sym = pupa_symtab[pupa_symbol_hash (name)]; sym; sym = sym->next)
|
||||
if (pupa_strcmp (sym->name, name) == 0)
|
||||
return sym->addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register a symbol with the name NAME and the address ADDR. */
|
||||
pupa_err_t
|
||||
pupa_dl_register_symbol (const char *name, void *addr, pupa_dl_t mod)
|
||||
{
|
||||
pupa_symbol_t sym;
|
||||
unsigned k;
|
||||
|
||||
sym = (pupa_symbol_t) pupa_malloc (sizeof (*sym));
|
||||
if (! sym)
|
||||
return pupa_errno;
|
||||
|
||||
if (mod)
|
||||
{
|
||||
sym->name = pupa_strdup (name);
|
||||
if (! sym->name)
|
||||
{
|
||||
pupa_free (sym);
|
||||
return pupa_errno;
|
||||
}
|
||||
}
|
||||
else
|
||||
sym->name = name;
|
||||
|
||||
sym->addr = addr;
|
||||
sym->mod = mod;
|
||||
|
||||
k = pupa_symbol_hash (name);
|
||||
sym->next = pupa_symtab[k];
|
||||
pupa_symtab[k] = sym;
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Unregister all the symbols defined in the module MOD. */
|
||||
static void
|
||||
pupa_dl_unregister_symbols (pupa_dl_t mod)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (! mod)
|
||||
pupa_fatal ("core symbols cannot be unregistered");
|
||||
|
||||
for (i = 0; i < PUPA_SYMTAB_SIZE; i++)
|
||||
{
|
||||
pupa_symbol_t sym, *p, q;
|
||||
|
||||
for (p = &pupa_symtab[i], sym = *p; sym; sym = q)
|
||||
{
|
||||
q = sym->next;
|
||||
if (sym->mod == mod)
|
||||
{
|
||||
*p = q;
|
||||
pupa_free ((void *) sym->name);
|
||||
pupa_free (sym);
|
||||
}
|
||||
else
|
||||
p = &sym->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the address of a section whose index is N. */
|
||||
static void *
|
||||
pupa_dl_get_section_addr (pupa_dl_t mod, unsigned n)
|
||||
{
|
||||
pupa_dl_segment_t seg;
|
||||
|
||||
for (seg = mod->segment; seg; seg = seg->next)
|
||||
if (seg->section == n)
|
||||
return seg->addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Load all segments from memory specified by E. */
|
||||
static pupa_err_t
|
||||
pupa_dl_load_segments (pupa_dl_t mod, const Elf_Ehdr *e)
|
||||
{
|
||||
unsigned i;
|
||||
Elf_Shdr *s;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
|
||||
{
|
||||
if (s->sh_flags & SHF_ALLOC)
|
||||
{
|
||||
pupa_dl_segment_t seg;
|
||||
|
||||
seg = (pupa_dl_segment_t) pupa_malloc (sizeof (*seg));
|
||||
if (! seg)
|
||||
return pupa_errno;
|
||||
|
||||
if (s->sh_size)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
addr = pupa_memalign (s->sh_addralign, s->sh_size);
|
||||
if (! addr)
|
||||
{
|
||||
pupa_free (seg);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
switch (s->sh_type)
|
||||
{
|
||||
case SHT_PROGBITS:
|
||||
pupa_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
|
||||
break;
|
||||
case SHT_NOBITS:
|
||||
pupa_memset (addr, 0, s->sh_size);
|
||||
break;
|
||||
}
|
||||
|
||||
seg->addr = addr;
|
||||
}
|
||||
else
|
||||
seg->addr = 0;
|
||||
|
||||
seg->size = s->sh_size;
|
||||
seg->section = i;
|
||||
seg->next = mod->segment;
|
||||
mod->segment = seg;
|
||||
}
|
||||
}
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_dl_resolve_symbols (pupa_dl_t mod, Elf_Ehdr *e)
|
||||
{
|
||||
unsigned i;
|
||||
Elf_Shdr *s;
|
||||
Elf_Sym *sym;
|
||||
const char *str;
|
||||
Elf_Word size, entsize;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (s->sh_type == SHT_SYMTAB)
|
||||
break;
|
||||
|
||||
if (i == e->e_shnum)
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE, "no symbol table");
|
||||
|
||||
sym = (Elf_Sym *) ((char *) e + s->sh_offset);
|
||||
size = s->sh_size;
|
||||
entsize = s->sh_entsize;
|
||||
|
||||
s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link);
|
||||
str = (char *) e + s->sh_offset;
|
||||
|
||||
for (i = 0;
|
||||
i < size / entsize;
|
||||
i++, sym = (Elf_Sym *) ((char *) sym + entsize))
|
||||
{
|
||||
unsigned char type = ELF_ST_TYPE (sym->st_info);
|
||||
unsigned char bind = ELF_ST_BIND (sym->st_info);
|
||||
const char *name = str + sym->st_name;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case STT_NOTYPE:
|
||||
/* Resolve a global symbol. */
|
||||
if (sym->st_name != 0 && sym->st_shndx == 0)
|
||||
{
|
||||
sym->st_value = (Elf_Addr) pupa_dl_resolve_symbol (name);
|
||||
if (! sym->st_value)
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE,
|
||||
"the symbol `%s' not found", name);
|
||||
}
|
||||
else
|
||||
sym->st_value = 0;
|
||||
break;
|
||||
|
||||
case STT_OBJECT:
|
||||
sym->st_value += (Elf_Addr) pupa_dl_get_section_addr (mod,
|
||||
sym->st_shndx);
|
||||
if (bind != STB_LOCAL)
|
||||
if (pupa_dl_register_symbol (name, (void *) sym->st_value, mod))
|
||||
return pupa_errno;
|
||||
break;
|
||||
|
||||
case STT_FUNC:
|
||||
sym->st_value += (Elf_Addr) pupa_dl_get_section_addr (mod,
|
||||
sym->st_shndx);
|
||||
if (bind != STB_LOCAL)
|
||||
if (pupa_dl_register_symbol (name, (void *) sym->st_value, mod))
|
||||
return pupa_errno;
|
||||
|
||||
if (pupa_strcmp (name, "pupa_mod_init") == 0)
|
||||
mod->init = (void (*) ()) sym->st_value;
|
||||
else if (pupa_strcmp (name, "pupa_mod_fini") == 0)
|
||||
mod->fini = (void (*) ()) sym->st_value;
|
||||
break;
|
||||
|
||||
case STT_SECTION:
|
||||
sym->st_value = (Elf_Addr) pupa_dl_get_section_addr (mod,
|
||||
sym->st_shndx);
|
||||
break;
|
||||
|
||||
case STT_FILE:
|
||||
sym->st_value = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE,
|
||||
"unknown symbol type `%d'", (int) type);
|
||||
}
|
||||
}
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_dl_call_init (pupa_dl_t mod)
|
||||
{
|
||||
if (mod->init)
|
||||
(mod->init) ();
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_dl_resolve_name (pupa_dl_t mod, Elf_Ehdr *e)
|
||||
{
|
||||
Elf_Shdr *s;
|
||||
const char *str;
|
||||
unsigned i;
|
||||
|
||||
s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
|
||||
str = (char *) e + s->sh_offset;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (pupa_strcmp (str + s->sh_name, ".modname") == 0)
|
||||
{
|
||||
mod->name = pupa_strdup ((char *) e + s->sh_offset);
|
||||
if (! mod->name)
|
||||
return pupa_errno;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == e->e_shnum)
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE, "no module name found");
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_dl_resolve_dependencies (pupa_dl_t mod, Elf_Ehdr *e)
|
||||
{
|
||||
Elf_Shdr *s;
|
||||
const char *str;
|
||||
unsigned i;
|
||||
|
||||
s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
|
||||
str = (char *) e + s->sh_offset;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (pupa_strcmp (str + s->sh_name, ".moddeps") == 0)
|
||||
{
|
||||
const char *name = (char *) e + s->sh_offset;
|
||||
const char *max = name + s->sh_size;
|
||||
|
||||
while (name < max)
|
||||
{
|
||||
pupa_dl_t m;
|
||||
pupa_dl_dep_t dep;
|
||||
|
||||
m = pupa_dl_load (name);
|
||||
if (! m)
|
||||
return pupa_errno;
|
||||
|
||||
dep = (pupa_dl_dep_t) pupa_malloc (sizeof (*dep));
|
||||
if (! dep)
|
||||
return pupa_errno;
|
||||
|
||||
dep->mod = m;
|
||||
dep->next = mod->dep;
|
||||
mod->dep = dep;
|
||||
|
||||
name += pupa_strlen (name) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Load a module from core memory. */
|
||||
pupa_dl_t
|
||||
pupa_dl_load_core (void *addr, pupa_size_t size)
|
||||
{
|
||||
Elf_Ehdr *e;
|
||||
pupa_dl_t mod;
|
||||
|
||||
e = addr;
|
||||
if (! pupa_arch_dl_check_header (e, size))
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_MODULE, "invalid ELF header");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mod = (pupa_dl_t) pupa_malloc (sizeof (*mod));
|
||||
if (! mod)
|
||||
return 0;
|
||||
|
||||
mod->name = 0;
|
||||
mod->ref_count = 1;
|
||||
mod->dep = 0;
|
||||
mod->segment = 0;
|
||||
mod->init = 0;
|
||||
mod->fini = 0;
|
||||
|
||||
if (pupa_dl_resolve_name (mod, e)
|
||||
|| pupa_dl_resolve_dependencies (mod, e)
|
||||
|| pupa_dl_load_segments (mod, e)
|
||||
|| pupa_dl_resolve_symbols (mod, e)
|
||||
|| pupa_arch_dl_relocate_symbols (mod, e))
|
||||
{
|
||||
mod->fini = 0;
|
||||
pupa_dl_unload (mod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pupa_dl_call_init (mod);
|
||||
|
||||
if (pupa_dl_add (mod))
|
||||
{
|
||||
pupa_dl_unload (mod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
/* Load a module from the file FILENAME. */
|
||||
pupa_dl_t
|
||||
pupa_dl_load_file (const char *filename)
|
||||
{
|
||||
pupa_file_t file;
|
||||
pupa_ssize_t size;
|
||||
void *core = 0;
|
||||
pupa_dl_t mod = 0;
|
||||
|
||||
file = pupa_file_open (filename);
|
||||
if (! file)
|
||||
return 0;
|
||||
|
||||
size = pupa_file_size (file);
|
||||
core = pupa_malloc (size);
|
||||
if (! core)
|
||||
goto failed;
|
||||
|
||||
if (pupa_file_read (file, core, size) != (int) size)
|
||||
goto failed;
|
||||
|
||||
mod = pupa_dl_load_core (core, size);
|
||||
|
||||
failed:
|
||||
pupa_file_close (file);
|
||||
pupa_free (core);
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
static char *pupa_dl_dir;
|
||||
|
||||
/* Load a module using a symbolic name. */
|
||||
pupa_dl_t
|
||||
pupa_dl_load (const char *name)
|
||||
{
|
||||
char *filename;
|
||||
pupa_dl_t mod;
|
||||
|
||||
mod = pupa_dl_get (name);
|
||||
if (mod)
|
||||
{
|
||||
mod->ref_count++;
|
||||
return mod;
|
||||
}
|
||||
|
||||
if (! pupa_dl_dir)
|
||||
pupa_fatal ("module dir is not initialized yet");
|
||||
|
||||
filename = (char *) pupa_malloc (pupa_strlen (pupa_dl_dir) + 1
|
||||
+ pupa_strlen (name) + 3);
|
||||
if (! filename)
|
||||
return 0;
|
||||
|
||||
pupa_sprintf (filename, "%s/%s.o", pupa_dl_dir, name);
|
||||
mod = pupa_dl_load_file (filename);
|
||||
pupa_free (filename);
|
||||
|
||||
if (! mod)
|
||||
return 0;
|
||||
|
||||
if (pupa_strcmp (mod->name, name) != 0)
|
||||
pupa_error (PUPA_ERR_BAD_MODULE, "mismatched names");
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
/* Unload the module MOD. */
|
||||
void
|
||||
pupa_dl_unload (pupa_dl_t mod)
|
||||
{
|
||||
pupa_dl_dep_t dep, depn;
|
||||
pupa_dl_segment_t seg, segn;
|
||||
|
||||
if (--mod->ref_count > 0)
|
||||
return;
|
||||
|
||||
if (mod->fini)
|
||||
(mod->fini) ();
|
||||
|
||||
pupa_dl_remove (mod);
|
||||
pupa_dl_unregister_symbols (mod);
|
||||
|
||||
for (dep = mod->dep; dep; dep = depn)
|
||||
{
|
||||
depn = dep->next;
|
||||
pupa_dl_unload (dep->mod);
|
||||
pupa_free (dep);
|
||||
}
|
||||
|
||||
for (seg = mod->segment; seg; seg = segn)
|
||||
{
|
||||
segn = seg->next;
|
||||
pupa_free (seg->addr);
|
||||
pupa_free (seg);
|
||||
}
|
||||
|
||||
pupa_free (mod->name);
|
||||
pupa_free (mod);
|
||||
}
|
||||
|
||||
void
|
||||
pupa_dl_init (const char *dir)
|
||||
{
|
||||
pupa_dl_dir = (char *) dir;
|
||||
}
|
61
kern/err.c
Normal file
61
kern/err.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* err.c - error handling routines */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define PUPA_MAX_ERRMSG 256
|
||||
|
||||
pupa_err_t pupa_errno;
|
||||
char pupa_errmsg[PUPA_MAX_ERRMSG];
|
||||
|
||||
pupa_err_t
|
||||
pupa_error (pupa_err_t n, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
pupa_errno = n;
|
||||
|
||||
va_start (ap, fmt);
|
||||
pupa_vsprintf (pupa_errmsg, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_fatal (const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, fmt);
|
||||
pupa_vprintf (fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
pupa_stop ();
|
||||
}
|
||||
|
||||
void
|
||||
pupa_print_error (void)
|
||||
{
|
||||
if (pupa_errno != PUPA_ERR_NONE)
|
||||
pupa_printf ("error: %s\n", pupa_errmsg);
|
||||
}
|
158
kern/file.c
Normal file
158
kern/file.c
Normal file
|
@ -0,0 +1,158 @@
|
|||
/* file.c - file I/O functions */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/file.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/fs.h>
|
||||
#include <pupa/device.h>
|
||||
|
||||
/* Get the device part of the filename NAME. It is enclosed by parentheses. */
|
||||
char *
|
||||
pupa_file_get_device_name (const char *name)
|
||||
{
|
||||
if (name[0] == '(')
|
||||
{
|
||||
char *p = pupa_strchr (name, ')');
|
||||
char *ret;
|
||||
|
||||
if (! p)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FILENAME, "missing `)'");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = (char *) pupa_malloc (p - name);
|
||||
if (! ret)
|
||||
return 0;
|
||||
|
||||
pupa_memcpy (ret, name + 1, p - name - 1);
|
||||
ret[p - name - 1] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pupa_file_t
|
||||
pupa_file_open (const char *name)
|
||||
{
|
||||
pupa_device_t device;
|
||||
pupa_file_t file = 0;
|
||||
char *device_name;
|
||||
char *file_name;
|
||||
|
||||
device_name = pupa_file_get_device_name (name);
|
||||
if (pupa_errno)
|
||||
return 0;
|
||||
|
||||
/* Get the file part of NAME. */
|
||||
file_name = pupa_strchr (name, ')');
|
||||
if (file_name)
|
||||
file_name++;
|
||||
else
|
||||
file_name = (char *) name;
|
||||
|
||||
device = pupa_device_open (device_name);
|
||||
pupa_free (device_name);
|
||||
if (! device)
|
||||
goto fail;
|
||||
|
||||
file = (pupa_file_t) pupa_malloc (sizeof (*file));
|
||||
if (! file)
|
||||
goto fail;
|
||||
|
||||
file->device = device;
|
||||
file->offset = 0;
|
||||
file->data = 0;
|
||||
file->read_hook = 0;
|
||||
|
||||
if (device->disk && file_name[0] != '/')
|
||||
/* This is a block list. */
|
||||
file->fs = &pupa_fs_blocklist;
|
||||
else
|
||||
{
|
||||
file->fs = pupa_fs_probe (device);
|
||||
if (! file->fs)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((file->fs->open) (file, file_name) != PUPA_ERR_NONE)
|
||||
goto fail;
|
||||
|
||||
return file;
|
||||
|
||||
fail:
|
||||
if (device)
|
||||
pupa_device_close (device);
|
||||
|
||||
/* if (net) pupa_net_close (net); */
|
||||
|
||||
pupa_free (file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pupa_ssize_t
|
||||
pupa_file_read (pupa_file_t file, char *buf, pupa_ssize_t len)
|
||||
{
|
||||
pupa_ssize_t res;
|
||||
|
||||
if (len == 0 || len > file->size - file->offset)
|
||||
len = file->size - file->offset;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
res = (file->fs->read) (file, buf, len);
|
||||
if (res > 0)
|
||||
file->offset += res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_file_close (pupa_file_t file)
|
||||
{
|
||||
if (file->fs->close)
|
||||
(file->fs->close) (file);
|
||||
|
||||
pupa_device_close (file->device);
|
||||
pupa_free (file);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
pupa_ssize_t
|
||||
pupa_file_seek (pupa_file_t file, pupa_ssize_t offset)
|
||||
{
|
||||
pupa_ssize_t old;
|
||||
|
||||
if (offset < 0 || offset >= file->size)
|
||||
{
|
||||
pupa_error (PUPA_ERR_OUT_OF_RANGE,
|
||||
"attempt to seek outside of the file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
old = file->offset;
|
||||
file->offset = offset;
|
||||
return old;
|
||||
}
|
224
kern/fs.c
Normal file
224
kern/fs.c
Normal file
|
@ -0,0 +1,224 @@
|
|||
/* fs.c - filesystem manager */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/net.h>
|
||||
#include <pupa/fs.h>
|
||||
#include <pupa/file.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/term.h>
|
||||
|
||||
static pupa_fs_t pupa_fs_list;
|
||||
|
||||
void
|
||||
pupa_fs_register (pupa_fs_t fs)
|
||||
{
|
||||
fs->next = pupa_fs_list;
|
||||
pupa_fs_list = fs;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_fs_unregister (pupa_fs_t fs)
|
||||
{
|
||||
pupa_fs_t *p, q;
|
||||
|
||||
for (p = &pupa_fs_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (q == fs)
|
||||
{
|
||||
*p = q->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pupa_fs_iterate (int (*hook) (const pupa_fs_t fs))
|
||||
{
|
||||
pupa_fs_t p;
|
||||
|
||||
for (p = pupa_fs_list; p; p = p->next)
|
||||
if (hook (p))
|
||||
break;
|
||||
}
|
||||
|
||||
pupa_fs_t
|
||||
pupa_fs_probe (pupa_device_t device)
|
||||
{
|
||||
pupa_fs_t p;
|
||||
auto int dummy_func (const char *filename, int dir);
|
||||
|
||||
int dummy_func (const char *filename __attribute__ ((unused)),
|
||||
int dir __attribute__ ((unused)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (device->disk)
|
||||
{
|
||||
for (p = pupa_fs_list; p; p = p->next)
|
||||
{
|
||||
(p->dir) (device, "/", dummy_func);
|
||||
if (pupa_errno == PUPA_ERR_NONE)
|
||||
return p;
|
||||
|
||||
if (pupa_errno != PUPA_ERR_BAD_FS)
|
||||
return 0;
|
||||
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
}
|
||||
}
|
||||
else if (device->net->fs)
|
||||
return device->net->fs;
|
||||
|
||||
pupa_error (PUPA_ERR_UNKNOWN_FS, "unknown filesystem");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Block list support routines. */
|
||||
|
||||
struct pupa_fs_block
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned long length;
|
||||
};
|
||||
|
||||
static pupa_err_t
|
||||
pupa_fs_blocklist_open (pupa_file_t file, const char *name)
|
||||
{
|
||||
char *p = (char *) name;
|
||||
unsigned num = 0;
|
||||
unsigned i;
|
||||
pupa_disk_t disk = file->device->disk;
|
||||
struct pupa_fs_block *blocks;
|
||||
|
||||
/* First, count the number of blocks. */
|
||||
do
|
||||
{
|
||||
num++;
|
||||
p = pupa_strchr (p, ',');
|
||||
}
|
||||
while (p);
|
||||
|
||||
/* Allocate a block list. */
|
||||
blocks = pupa_malloc (sizeof (struct pupa_fs_block) * (num + 1));
|
||||
if (! blocks)
|
||||
return 0;
|
||||
|
||||
file->size = 0;
|
||||
p = (char *) name;
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
if (*p != '+')
|
||||
{
|
||||
blocks[i].offset = pupa_strtoul (p, &p, 0);
|
||||
if (pupa_errno != PUPA_ERR_NONE || *p != '+')
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FILENAME,
|
||||
"invalid file name `%s'", name);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else
|
||||
blocks[i].offset = 0;
|
||||
|
||||
p++;
|
||||
blocks[i].length = pupa_strtoul (p, &p, 0);
|
||||
if (pupa_errno != PUPA_ERR_NONE
|
||||
|| blocks[i].length == 0
|
||||
|| (*p && *p != ',' && ! pupa_isspace (*p)))
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FILENAME,
|
||||
"invalid file name `%s'", name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (disk->total_sectors < blocks[i].offset + blocks[i].length)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FILENAME, "beyond the total sectors");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
file->size += (blocks[i].length << PUPA_DISK_SECTOR_BITS);
|
||||
p++;
|
||||
}
|
||||
|
||||
blocks[i].length = 0;
|
||||
file->data = blocks;
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
|
||||
fail:
|
||||
pupa_free (blocks);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
static pupa_ssize_t
|
||||
pupa_fs_blocklist_read (pupa_file_t file, char *buf, pupa_ssize_t len)
|
||||
{
|
||||
struct pupa_fs_block *p;
|
||||
unsigned long sector;
|
||||
unsigned long offset;
|
||||
pupa_ssize_t ret = 0;
|
||||
|
||||
if (len > file->size - file->offset)
|
||||
len = file->size - file->offset;
|
||||
|
||||
sector = (file->offset >> PUPA_DISK_SECTOR_BITS);
|
||||
offset = (file->offset & (PUPA_DISK_SECTOR_SIZE - 1));
|
||||
for (p = file->data; p->length && len > 0; p++)
|
||||
{
|
||||
if (sector < p->length)
|
||||
{
|
||||
pupa_ssize_t size;
|
||||
|
||||
size = len;
|
||||
if (((size + offset + PUPA_DISK_SECTOR_SIZE - 1)
|
||||
>> PUPA_DISK_SECTOR_BITS) > p->length - sector)
|
||||
size = ((p->length - sector) << PUPA_DISK_SECTOR_BITS) - offset;
|
||||
|
||||
if (pupa_disk_read (file->device->disk, p->offset + sector, offset,
|
||||
size, buf) != PUPA_ERR_NONE)
|
||||
return -1;
|
||||
|
||||
ret += size;
|
||||
len -= size;
|
||||
sector -= ((size + offset) >> PUPA_DISK_SECTOR_BITS);
|
||||
offset = ((size + offset) & (PUPA_DISK_SECTOR_SIZE - 1));
|
||||
}
|
||||
else
|
||||
sector -= p->length;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct pupa_fs pupa_fs_blocklist =
|
||||
{
|
||||
.name = "blocklist",
|
||||
.dir = 0,
|
||||
.open = pupa_fs_blocklist_open,
|
||||
.read = pupa_fs_blocklist_read,
|
||||
.close = 0,
|
||||
.next = 0
|
||||
};
|
126
kern/i386/dl.c
Normal file
126
kern/i386/dl.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* dl-386.c - arch-dependent part of loadable module support */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/dl.h>
|
||||
#include <pupa/elf.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/err.h>
|
||||
|
||||
/* Check if EHDR is a valid ELF header. */
|
||||
int
|
||||
pupa_arch_dl_check_header (void *ehdr, unsigned size)
|
||||
{
|
||||
Elf32_Ehdr *e = ehdr;
|
||||
|
||||
/* Check the header size. */
|
||||
if (size < sizeof (Elf32_Ehdr))
|
||||
return 0;
|
||||
|
||||
/* Check the magic numbers. */
|
||||
if (e->e_ident[EI_MAG0] != ELFMAG0
|
||||
|| e->e_ident[EI_MAG1] != ELFMAG1
|
||||
|| e->e_ident[EI_MAG2] != ELFMAG2
|
||||
|| e->e_ident[EI_MAG3] != ELFMAG3
|
||||
|| e->e_version != EV_CURRENT
|
||||
|| e->e_ident[EI_CLASS] != ELFCLASS32
|
||||
|| e->e_ident[EI_DATA] != ELFDATA2LSB
|
||||
|| e->e_machine != EM_386
|
||||
|| e->e_type != ET_REL)
|
||||
return 0;
|
||||
|
||||
/* Make sure that every section is within the core. */
|
||||
if (size < e->e_shoff + e->e_shentsize * e->e_shnum)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Relocate symbols. */
|
||||
pupa_err_t
|
||||
pupa_arch_dl_relocate_symbols (pupa_dl_t mod, void *ehdr)
|
||||
{
|
||||
Elf32_Ehdr *e = ehdr;
|
||||
Elf32_Shdr *s;
|
||||
Elf32_Sym *symtab;
|
||||
Elf32_Word entsize;
|
||||
unsigned i;
|
||||
|
||||
/* Find a symbol table. */
|
||||
for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf32_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (s->sh_type == SHT_SYMTAB)
|
||||
break;
|
||||
|
||||
if (i == e->e_shnum)
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE, "no symtab found");
|
||||
|
||||
symtab = (Elf32_Sym *) ((char *) e + s->sh_offset);
|
||||
entsize = s->sh_entsize;
|
||||
|
||||
for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf32_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (s->sh_type == SHT_REL)
|
||||
{
|
||||
pupa_dl_segment_t seg;
|
||||
|
||||
/* Find the target segment. */
|
||||
for (seg = mod->segment; seg; seg = seg->next)
|
||||
if (seg->section == s->sh_info)
|
||||
break;
|
||||
|
||||
if (seg)
|
||||
{
|
||||
Elf32_Rel *rel, *max;
|
||||
|
||||
for (rel = (Elf32_Rel *) ((char *) e + s->sh_offset),
|
||||
max = rel + s->sh_size / s->sh_entsize;
|
||||
rel < max;
|
||||
rel++)
|
||||
{
|
||||
Elf32_Word *addr;
|
||||
Elf32_Sym *sym;
|
||||
|
||||
if (seg->size < rel->r_offset)
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE,
|
||||
"reloc offset is out of the segment");
|
||||
|
||||
addr = (Elf32_Word *) ((char *) seg->addr + rel->r_offset);
|
||||
sym = (Elf32_Sym *) ((char *) symtab
|
||||
+ entsize * ELF32_R_SYM (rel->r_info));
|
||||
|
||||
switch (ELF32_R_TYPE (rel->r_info))
|
||||
{
|
||||
case R_386_32:
|
||||
*addr += sym->st_value;
|
||||
break;
|
||||
|
||||
case R_386_PC32:
|
||||
*addr += (sym->st_value - (Elf32_Word) seg->addr
|
||||
- rel->r_offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
114
kern/i386/pc/init.c
Normal file
114
kern/i386/pc/init.c
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/kernel.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/machine/init.h>
|
||||
#include <pupa/machine/memory.h>
|
||||
#include <pupa/machine/console.h>
|
||||
#include <pupa/machine/biosdisk.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/err.h>
|
||||
|
||||
void
|
||||
pupa_machine_init (void)
|
||||
{
|
||||
pupa_uint32_t cont;
|
||||
struct pupa_machine_mmap_entry entry;
|
||||
pupa_size_t lower_mem = (pupa_get_memsize (0) << 10);
|
||||
pupa_addr_t end_addr = pupa_get_end_addr ();
|
||||
|
||||
/* Initialize the console as early as possible. */
|
||||
pupa_console_init ();
|
||||
|
||||
/* Sanity check. */
|
||||
if (lower_mem < PUPA_MEMORY_MACHINE_RESERVED_END)
|
||||
pupa_fatal ("too small memory");
|
||||
|
||||
/* Turn on Gate A20 to access >1MB. */
|
||||
pupa_gate_a20 (1);
|
||||
|
||||
/* Add the lower memory into free memory. */
|
||||
if (lower_mem >= PUPA_MEMORY_MACHINE_RESERVED_END)
|
||||
pupa_mm_init_region ((void *) PUPA_MEMORY_MACHINE_RESERVED_END,
|
||||
lower_mem - PUPA_MEMORY_MACHINE_RESERVED_END);
|
||||
|
||||
pupa_mm_init_region ((void *) end_addr,
|
||||
PUPA_MEMORY_MACHINE_RESERVED_START - end_addr);
|
||||
|
||||
/* Check if pupa_get_mmap_entry works. */
|
||||
cont = pupa_get_mmap_entry (&entry, 0);
|
||||
|
||||
if (entry.size)
|
||||
do
|
||||
{
|
||||
/* Avoid the lower memory. */
|
||||
if (entry.addr < 0x100000)
|
||||
{
|
||||
if (entry.len <= 0x100000 - entry.addr)
|
||||
goto next;
|
||||
|
||||
entry.len -= 0x100000 - entry.addr;
|
||||
entry.addr = 0x100000;
|
||||
}
|
||||
|
||||
/* Ignore >4GB. */
|
||||
if (entry.addr <= 0xFFFFFFFF && entry.type == 1)
|
||||
{
|
||||
pupa_addr_t addr;
|
||||
pupa_size_t len;
|
||||
|
||||
addr = (pupa_addr_t) entry.addr;
|
||||
len = ((addr + entry.len > 0xFFFFFFFF)
|
||||
? 0xFFFFFFFF - addr
|
||||
: (pupa_size_t) entry.len);
|
||||
pupa_mm_init_region ((void *) addr, len);
|
||||
}
|
||||
|
||||
next:
|
||||
if (! cont)
|
||||
break;
|
||||
|
||||
cont = pupa_get_mmap_entry (&entry, cont);
|
||||
}
|
||||
while (entry.size);
|
||||
else
|
||||
{
|
||||
pupa_uint32_t eisa_mmap = pupa_get_eisa_mmap ();
|
||||
|
||||
if (eisa_mmap)
|
||||
{
|
||||
if ((eisa_mmap & 0xFFFF) == 0x3C00)
|
||||
pupa_mm_init_region ((void *) 0x100000,
|
||||
(eisa_mmap << 16) + 0x100000 * 15);
|
||||
else
|
||||
{
|
||||
pupa_mm_init_region ((void *) 0x100000,
|
||||
(eisa_mmap & 0xFFFF) << 10);
|
||||
pupa_mm_init_region ((void *) 0x1000000, eisa_mmap << 16);
|
||||
}
|
||||
}
|
||||
else
|
||||
pupa_mm_init_region ((void *) 0x100000,
|
||||
(pupa_size_t) pupa_get_memsize (1) << 10);
|
||||
}
|
||||
|
||||
/* The memory system was initialized, thus register built-in devices. */
|
||||
pupa_biosdisk_init ();
|
||||
}
|
1377
kern/i386/pc/startup.S
Normal file
1377
kern/i386/pc/startup.S
Normal file
File diff suppressed because it is too large
Load diff
67
kern/loader.c
Normal file
67
kern/loader.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/loader.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/err.h>
|
||||
|
||||
static pupa_err_t (*pupa_loader_load_module_func) (int argc, char *argv[]);
|
||||
static pupa_err_t (*pupa_loader_boot_func) (void);
|
||||
static pupa_err_t (*pupa_loader_unload_func) (void);
|
||||
|
||||
static int pupa_loader_loaded;
|
||||
|
||||
void
|
||||
pupa_loader_set (pupa_err_t (*load_module) (int argc, char *argv[]),
|
||||
pupa_err_t (*boot) (void),
|
||||
pupa_err_t (*unload) (void))
|
||||
{
|
||||
if (pupa_loader_loaded && pupa_loader_unload_func)
|
||||
if (pupa_loader_unload_func () != PUPA_ERR_NONE)
|
||||
return;
|
||||
|
||||
pupa_loader_load_module_func = load_module;
|
||||
pupa_loader_boot_func = boot;
|
||||
pupa_loader_unload_func = unload;
|
||||
|
||||
pupa_loader_loaded = 1;
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_loader_load_module (int argc, char *argv[])
|
||||
{
|
||||
if (! pupa_loader_loaded)
|
||||
return pupa_error (PUPA_ERR_NO_KERNEL, "no loaded kernel");
|
||||
|
||||
if (! pupa_loader_load_module_func)
|
||||
return pupa_error (PUPA_ERR_BAD_OS, "module not supported");
|
||||
|
||||
return pupa_loader_load_module_func (argc, argv);
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_loader_boot (void)
|
||||
{
|
||||
if (! pupa_loader_loaded)
|
||||
return pupa_error (PUPA_ERR_NO_KERNEL, "no loaded kernel");
|
||||
|
||||
return (pupa_loader_boot_func) ();
|
||||
}
|
||||
|
86
kern/main.c
Normal file
86
kern/main.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/kernel.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/dl.h>
|
||||
#include <pupa/term.h>
|
||||
#include <pupa/rescue.h>
|
||||
|
||||
/* Return the end of the core image. */
|
||||
pupa_addr_t
|
||||
pupa_get_end_addr (void)
|
||||
{
|
||||
return pupa_total_module_size + pupa_end_addr;
|
||||
}
|
||||
|
||||
/* Load all modules in core. */
|
||||
static void
|
||||
pupa_load_modules (void)
|
||||
{
|
||||
struct pupa_module_header *header;
|
||||
|
||||
for (header = (struct pupa_module_header *) pupa_end_addr;
|
||||
header < (struct pupa_module_header *) pupa_get_end_addr ();
|
||||
header = (struct pupa_module_header *) ((char *) header + header->size))
|
||||
{
|
||||
if (! pupa_dl_load_core ((char *) header + header->offset,
|
||||
(header->size - header->offset)))
|
||||
pupa_fatal ("%s", pupa_errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the region where modules reside into dynamic memory. */
|
||||
static void
|
||||
pupa_add_unused_region (void)
|
||||
{
|
||||
if (pupa_total_module_size)
|
||||
pupa_mm_init_region ((void *) pupa_end_addr, pupa_total_module_size);
|
||||
}
|
||||
|
||||
/* The main routine. */
|
||||
void
|
||||
pupa_main (void)
|
||||
{
|
||||
void (*normal_func) (void);
|
||||
|
||||
/* First of all, initialize the machine. */
|
||||
pupa_machine_init ();
|
||||
|
||||
/* Hello. */
|
||||
pupa_setcolorstate (PUPA_TERM_COLOR_HIGHLIGHT);
|
||||
pupa_printf ("Welcome to PUPA!");
|
||||
pupa_setcolorstate (PUPA_TERM_COLOR_STANDARD);
|
||||
pupa_printf ("\n\n");
|
||||
|
||||
pupa_register_exported_symbols ();
|
||||
pupa_load_modules ();
|
||||
pupa_add_unused_region ();
|
||||
|
||||
/* If the function pupa_enter_normal_mode is present, call it. */
|
||||
normal_func = pupa_dl_resolve_symbol ("pupa_enter_normal_mode");
|
||||
if (normal_func)
|
||||
(*normal_func) ();
|
||||
|
||||
/* If pupa_enter_normal_mode fails or doesn't exist, enter rescue mode. */
|
||||
pupa_printf ("Entering into rescue mode...\n");
|
||||
pupa_enter_rescue_mode ();
|
||||
}
|
377
kern/misc.c
Normal file
377
kern/misc.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
/* misc.c - definitions of misc functions */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <stdarg.h>
|
||||
#include <pupa/term.h>
|
||||
|
||||
void *
|
||||
pupa_memcpy (void *dest, const void *src, pupa_size_t n)
|
||||
{
|
||||
char *d = (char *) dest;
|
||||
char *s = (char *) src;
|
||||
|
||||
while (n--)
|
||||
*d++ = *s++;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_printf (const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start (ap, fmt);
|
||||
ret = pupa_vprintf (fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_vprintf (const char *fmt, va_list args)
|
||||
{
|
||||
return pupa_vsprintf (0, fmt, args);
|
||||
}
|
||||
|
||||
int
|
||||
pupa_memcmp (const void *s1, const void *s2, pupa_size_t n)
|
||||
{
|
||||
const char *t1 = s1;
|
||||
const char *t2 = s2;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
if (*t1 != *t2)
|
||||
return (int) *t1 - (int) *t2;
|
||||
|
||||
t1++;
|
||||
t2++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_strcmp (const char *s1, const char *s2)
|
||||
{
|
||||
while (*s1 && *s2)
|
||||
{
|
||||
if (*s1 != *s2)
|
||||
return (int) *s1 - (int) *s2;
|
||||
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
|
||||
return (int) *s1 - (int) *s2;
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_strchr (const char *s, int c)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
if (*s == c)
|
||||
return (char *) s;
|
||||
s++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_strrchr (const char *s, int c)
|
||||
{
|
||||
char *p = 0;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
if (*s == c)
|
||||
p = (char *) s;
|
||||
s++;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_isspace (int c)
|
||||
{
|
||||
return (c == '\n' || c == '\r' || c == ' ' || c == '\t');
|
||||
}
|
||||
|
||||
int
|
||||
pupa_isprint (int c)
|
||||
{
|
||||
return (c >= ' ' && c <= '~');
|
||||
}
|
||||
|
||||
int
|
||||
pupa_isalpha (int c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
int
|
||||
pupa_tolower (int c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return c - 'A' + 'a';
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
pupa_strtoul (const char *str, char **end, int base)
|
||||
{
|
||||
unsigned long num = 0;
|
||||
int found = 0;
|
||||
|
||||
/* Skip white spaces. */
|
||||
while (*str && pupa_isspace (*str))
|
||||
str++;
|
||||
|
||||
/* Guess the base, if not specified. The prefix `0x' means 16, and
|
||||
the prefix `0' means 8. */
|
||||
if (str[0] == '0')
|
||||
{
|
||||
if (str[1] == 'x')
|
||||
{
|
||||
if (base == 0 || base == 16)
|
||||
{
|
||||
base = 16;
|
||||
str += 2;
|
||||
}
|
||||
}
|
||||
else if (str[1] >= '0' && str[1] <= '7')
|
||||
base = 8;
|
||||
}
|
||||
|
||||
if (base == 0)
|
||||
base = 10;
|
||||
|
||||
while (*str)
|
||||
{
|
||||
unsigned long digit;
|
||||
|
||||
digit = pupa_tolower (*str) - '0';
|
||||
if (digit > 9)
|
||||
{
|
||||
digit += '0' - 'a' + 10;
|
||||
if (digit >= (unsigned long) base)
|
||||
break;
|
||||
}
|
||||
|
||||
found = 1;
|
||||
|
||||
if (num > (~0UL - digit) / base)
|
||||
{
|
||||
pupa_error (PUPA_ERR_OUT_OF_RANGE, "overflow is detected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
num += num * base + digit;
|
||||
str++;
|
||||
}
|
||||
|
||||
if (! found)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_NUMBER, "unrecognized number");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (end)
|
||||
*end = (char *) str;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_strdup (const char *s)
|
||||
{
|
||||
pupa_size_t len;
|
||||
char *p;
|
||||
|
||||
len = pupa_strlen (s) + 1;
|
||||
p = (char *) pupa_malloc (len);
|
||||
if (! p)
|
||||
return 0;
|
||||
|
||||
return pupa_memcpy (p, s, len);
|
||||
}
|
||||
|
||||
void *
|
||||
pupa_memset (void *s, int c, pupa_size_t n)
|
||||
{
|
||||
unsigned char *p = (unsigned char *) s;
|
||||
|
||||
while (n--)
|
||||
*p++ = (unsigned char) c;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
pupa_size_t
|
||||
pupa_strlen (const char *s)
|
||||
{
|
||||
char *p = (char *) s;
|
||||
|
||||
while (*p)
|
||||
p++;
|
||||
|
||||
return p - s;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pupa_reverse (char *str)
|
||||
{
|
||||
char *p = str + pupa_strlen (str) - 1;
|
||||
|
||||
while (str < p)
|
||||
{
|
||||
char tmp;
|
||||
|
||||
tmp = *str;
|
||||
*str = *p;
|
||||
*p = tmp;
|
||||
str++;
|
||||
p--;
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_itoa (char *str, int c, unsigned n)
|
||||
{
|
||||
unsigned base = (c == 'x') ? 16 : 10;
|
||||
char *p;
|
||||
|
||||
if ((int) n < 0 && c == 'd')
|
||||
{
|
||||
n = (unsigned) (-((int) n));
|
||||
*str++ = '-';
|
||||
}
|
||||
|
||||
p = str;
|
||||
do
|
||||
{
|
||||
unsigned d = n % base;
|
||||
*p++ = (d > 9) ? d + 'a' - 10 : d + '0';
|
||||
}
|
||||
while (n /= base);
|
||||
*p = 0;
|
||||
|
||||
pupa_reverse (str);
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_vsprintf (char *str, const char *fmt, va_list args)
|
||||
{
|
||||
char c;
|
||||
int count = 0;
|
||||
auto void write_char (char c);
|
||||
auto void write_str (const char *s);
|
||||
|
||||
void write_char (char c)
|
||||
{
|
||||
if (str)
|
||||
*str++ = c;
|
||||
else
|
||||
pupa_putchar (c);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
void write_str (const char *s)
|
||||
{
|
||||
while (*s)
|
||||
write_char (*s++);
|
||||
}
|
||||
|
||||
while ((c = *fmt++) != 0)
|
||||
{
|
||||
if (c != '%')
|
||||
write_char (c);
|
||||
else
|
||||
{
|
||||
char tmp[16];
|
||||
char *p;
|
||||
int n;
|
||||
|
||||
c = *fmt++;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'p':
|
||||
write_str ("0x");
|
||||
c = 'x';
|
||||
/* fall through */
|
||||
case 'x':
|
||||
case 'u':
|
||||
case 'd':
|
||||
n = va_arg (args, int);
|
||||
pupa_itoa (tmp, c, n);
|
||||
write_str (tmp);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
n = va_arg (args, int);
|
||||
write_char (n);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
p = va_arg (args, char *);
|
||||
if (p)
|
||||
write_str (p);
|
||||
else
|
||||
write_str ("(null)");
|
||||
break;
|
||||
|
||||
default:
|
||||
write_char (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (str)
|
||||
*str = '\0';
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_sprintf (char *str, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start (ap, fmt);
|
||||
ret = pupa_vsprintf (str, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
return ret;
|
||||
}
|
352
kern/mm.c
Normal file
352
kern/mm.c
Normal file
|
@ -0,0 +1,352 @@
|
|||
/* mm.c - functions for memory manager */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/disk.h>
|
||||
|
||||
/* Magic words. */
|
||||
#define PUPA_MM_FREE_MAGIC 0x2d3c2808
|
||||
#define PUPA_MM_ALLOC_MAGIC 0x6db08fa4
|
||||
|
||||
typedef struct pupa_mm_header
|
||||
{
|
||||
struct pupa_mm_header *next;
|
||||
pupa_size_t size;
|
||||
pupa_size_t magic;
|
||||
#if PUPA_CPU_SIZEOF_VOID_P == 4
|
||||
char padding[4];
|
||||
#elif PUPA_CPU_SIZEOF_VOID_P == 8
|
||||
char padding[8];
|
||||
#else
|
||||
# error "unknown word size"
|
||||
#endif
|
||||
}
|
||||
*pupa_mm_header_t;
|
||||
|
||||
#if PUPA_CPU_SIZEOF_VOID_P == 4
|
||||
# define PUPA_MM_ALIGN_LOG2 4
|
||||
#elif PUPA_CPU_SIZEOF_VOID_P == 8
|
||||
# define PUPA_MM_ALIGN_LOG2 8
|
||||
#endif
|
||||
|
||||
#define PUPA_MM_ALIGN (1 << PUPA_MM_ALIGN_LOG2)
|
||||
|
||||
typedef struct pupa_mm_region
|
||||
{
|
||||
struct pupa_mm_header *first;
|
||||
struct pupa_mm_region *next;
|
||||
pupa_addr_t addr;
|
||||
pupa_size_t size;
|
||||
}
|
||||
*pupa_mm_region_t;
|
||||
|
||||
|
||||
|
||||
static pupa_mm_region_t base;
|
||||
|
||||
/* Get a header from the pointer PTR, and set *P and *R to a pointer
|
||||
to the header and a pointer to its region, respectively. PTR must
|
||||
be allocated. */
|
||||
static void
|
||||
get_header_from_pointer (void *ptr, pupa_mm_header_t *p, pupa_mm_region_t *r)
|
||||
{
|
||||
if ((unsigned) ptr & (PUPA_MM_ALIGN - 1))
|
||||
pupa_fatal ("unaligned pointer %p", ptr);
|
||||
|
||||
for (*r = base; *r; *r = (*r)->next)
|
||||
if ((unsigned) ptr > (*r)->addr
|
||||
&& (unsigned) ptr <= (*r)->addr + (*r)->size)
|
||||
break;
|
||||
|
||||
if (! *r)
|
||||
pupa_fatal ("out of range pointer %p", ptr);
|
||||
|
||||
*p = (pupa_mm_header_t) ptr - 1;
|
||||
if ((*p)->magic != PUPA_MM_ALLOC_MAGIC)
|
||||
pupa_fatal ("alloc magic is broken at %p", *p);
|
||||
}
|
||||
|
||||
/* Initialize a region starting from ADDR and whose size is SIZE,
|
||||
to use it as free space. */
|
||||
void
|
||||
pupa_mm_init_region (void *addr, pupa_size_t size)
|
||||
{
|
||||
pupa_mm_header_t h;
|
||||
pupa_mm_region_t r, *p, q;
|
||||
|
||||
/* If this region is too small, ignore it. */
|
||||
if (size < PUPA_MM_ALIGN * 2)
|
||||
return;
|
||||
|
||||
/* Allocate a region from the head. */
|
||||
r = (pupa_mm_region_t) (((pupa_addr_t) addr + PUPA_MM_ALIGN - 1)
|
||||
& (~(PUPA_MM_ALIGN - 1)));
|
||||
size -= (char *) r - (char *) addr + sizeof (*r);
|
||||
|
||||
h = (pupa_mm_header_t) ((char *) r + PUPA_MM_ALIGN);
|
||||
h->next = h;
|
||||
h->magic = PUPA_MM_FREE_MAGIC;
|
||||
h->size = (size >> PUPA_MM_ALIGN_LOG2);
|
||||
|
||||
r->first = h;
|
||||
r->addr = (pupa_addr_t) h;
|
||||
r->size = (h->size << PUPA_MM_ALIGN_LOG2);
|
||||
|
||||
/* Find where to insert this region. Put a smaller one before bigger ones,
|
||||
to prevent fragmentations. */
|
||||
for (p = &base, q = *p; q; p = &(q->next), q = *p)
|
||||
if (q->size > r->size)
|
||||
break;
|
||||
|
||||
*p = r;
|
||||
r->next = q;
|
||||
}
|
||||
|
||||
/* Allocate the number of units N with the alignment ALIGN from the ring
|
||||
buffer starting from *FIRST. ALIGN must be a power of two. Return a
|
||||
non-NULL if successful, otherwise return NULL. */
|
||||
static void *
|
||||
pupa_real_malloc (pupa_mm_header_t *first, pupa_size_t n, pupa_size_t align)
|
||||
{
|
||||
pupa_mm_header_t p, q;
|
||||
|
||||
if ((*first)->magic == PUPA_MM_ALLOC_MAGIC)
|
||||
return 0;
|
||||
|
||||
for (q = *first, p = q->next; ; q = p, p = p->next)
|
||||
{
|
||||
pupa_off_t extra;
|
||||
|
||||
extra = ((pupa_addr_t) (p + 1) >> PUPA_MM_ALIGN_LOG2) % align;
|
||||
if (extra)
|
||||
extra = align - extra;
|
||||
|
||||
if (! p)
|
||||
pupa_fatal ("null in the ring");
|
||||
|
||||
if (p->magic != PUPA_MM_FREE_MAGIC)
|
||||
pupa_fatal ("free magic is broken at %p", p);
|
||||
|
||||
if (p->size >= n + extra)
|
||||
{
|
||||
if (extra == 0 && p->size == n)
|
||||
{
|
||||
q->next = p->next;
|
||||
p->magic = PUPA_MM_ALLOC_MAGIC;
|
||||
}
|
||||
else if (extra == 0 || p->size == n + extra)
|
||||
{
|
||||
p->size -= n;
|
||||
p += p->size;
|
||||
p->size = n;
|
||||
p->magic = PUPA_MM_ALLOC_MAGIC;
|
||||
}
|
||||
else
|
||||
{
|
||||
pupa_mm_header_t r;
|
||||
|
||||
r = p + extra + n;
|
||||
r->magic = PUPA_MM_FREE_MAGIC;
|
||||
r->size = p->size - extra - n;
|
||||
r->next = p->next;
|
||||
|
||||
p->size = extra;
|
||||
p->next = r;
|
||||
p += extra;
|
||||
p->size = n;
|
||||
p->magic = PUPA_MM_ALLOC_MAGIC;
|
||||
}
|
||||
|
||||
*first = q;
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
if (p == *first)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate SIZE bytes with the alignment ALIGN and return the pointer. */
|
||||
void *
|
||||
pupa_memalign (pupa_size_t align, pupa_size_t size)
|
||||
{
|
||||
pupa_mm_region_t r;
|
||||
pupa_size_t n = ((size + PUPA_MM_ALIGN - 1) >> PUPA_MM_ALIGN_LOG2) + 1;
|
||||
int first = 1;
|
||||
|
||||
align = (align >> PUPA_MM_ALIGN_LOG2);
|
||||
if (align == 0)
|
||||
align = 1;
|
||||
|
||||
again:
|
||||
|
||||
for (r = base; r; r = r->next)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = pupa_real_malloc (&(r->first), n, align);
|
||||
if (p)
|
||||
return p;
|
||||
}
|
||||
|
||||
/* If failed, invalidate disk caches to increase free memory. */
|
||||
if (first)
|
||||
{
|
||||
pupa_disk_cache_invalidate_all ();
|
||||
first = 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
pupa_error (PUPA_ERR_OUT_OF_MEMORY, "out of memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate SIZE bytes and return the pointer. */
|
||||
void *
|
||||
pupa_malloc (pupa_size_t size)
|
||||
{
|
||||
return pupa_memalign (0, size);
|
||||
}
|
||||
|
||||
/* Deallocate the pointer PTR. */
|
||||
void
|
||||
pupa_free (void *ptr)
|
||||
{
|
||||
pupa_mm_header_t p;
|
||||
pupa_mm_region_t r;
|
||||
|
||||
if (! ptr)
|
||||
return;
|
||||
|
||||
get_header_from_pointer (ptr, &p, &r);
|
||||
|
||||
if (p == r->first)
|
||||
{
|
||||
p->magic = PUPA_MM_FREE_MAGIC;
|
||||
p->next = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
pupa_mm_header_t q;
|
||||
|
||||
for (q = r->first; q >= p || q->next <= p; q = q->next)
|
||||
{
|
||||
if (q->magic != PUPA_MM_FREE_MAGIC)
|
||||
pupa_fatal ("free magic is broken at %p", q);
|
||||
|
||||
if (q >= q->next && (q < p || q->next > p))
|
||||
break;
|
||||
}
|
||||
|
||||
p->magic = PUPA_MM_FREE_MAGIC;
|
||||
p->next = q->next;
|
||||
q->next = p;
|
||||
|
||||
if (p + p->size == p->next)
|
||||
{
|
||||
p->next->magic = 0;
|
||||
p->size += p->next->size;
|
||||
p->next = p->next->next;
|
||||
}
|
||||
|
||||
if (q + q->size == p)
|
||||
{
|
||||
p->magic = 0;
|
||||
q->size += p->size;
|
||||
q->next = p->next;
|
||||
}
|
||||
|
||||
r->first = q;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reallocate SIZE bytes and return the pointer. The contents will be
|
||||
the same as that of PTR. */
|
||||
void *
|
||||
pupa_realloc (void *ptr, pupa_size_t size)
|
||||
{
|
||||
pupa_mm_header_t p;
|
||||
pupa_mm_region_t r;
|
||||
void *q;
|
||||
pupa_size_t n;
|
||||
|
||||
if (! ptr)
|
||||
return pupa_malloc (size);
|
||||
|
||||
if (! size)
|
||||
{
|
||||
pupa_free (ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: Not optimal. */
|
||||
n = ((size + PUPA_MM_ALIGN - 1) >> PUPA_MM_ALIGN_LOG2) + 1;
|
||||
get_header_from_pointer (ptr, &p, &r);
|
||||
|
||||
if (p->size >= n)
|
||||
return p;
|
||||
|
||||
q = pupa_malloc (size);
|
||||
if (! q)
|
||||
return q;
|
||||
|
||||
pupa_memcpy (q, ptr, size);
|
||||
pupa_free (ptr);
|
||||
return q;
|
||||
}
|
||||
|
||||
#if MM_DEBUG
|
||||
void
|
||||
pupa_mm_dump (unsigned lineno)
|
||||
{
|
||||
pupa_mm_region_t r;
|
||||
|
||||
pupa_printf ("called at line %u\n", lineno);
|
||||
for (r = base; r; r = r->next)
|
||||
{
|
||||
pupa_mm_header_t p;
|
||||
|
||||
for (p = (pupa_mm_header_t) ((r->addr + PUPA_MM_ALIGN - 1)
|
||||
& (~(PUPA_MM_ALIGN - 1)));
|
||||
(pupa_addr_t) p < r->addr + r->size;
|
||||
p++)
|
||||
{
|
||||
switch (p->magic)
|
||||
{
|
||||
case PUPA_MM_FREE_MAGIC:
|
||||
pupa_printf ("F:%p:%u:%p\n",
|
||||
p, p->size << PUPA_MM_ALIGN_LOG2, p->next);
|
||||
break;
|
||||
case PUPA_MM_ALLOC_MAGIC:
|
||||
pupa_printf ("A:%p:%u\n", p, p->size << PUPA_MM_ALIGN_LOG2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pupa_printf ("\n");
|
||||
}
|
||||
#endif /* MM_DEBUG */
|
576
kern/rescue.c
Normal file
576
kern/rescue.c
Normal file
|
@ -0,0 +1,576 @@
|
|||
/* rescue.c - rescue mode */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/kernel.h>
|
||||
#include <pupa/term.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/file.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/loader.h>
|
||||
#include <pupa/machine/partition.h>
|
||||
|
||||
#define PUPA_RESCUE_BUF_SIZE 256
|
||||
#define PUPA_RESCUE_MAX_ARGS 20
|
||||
|
||||
struct pupa_rescue_command
|
||||
{
|
||||
const char *name;
|
||||
void (*func) (int argc, char *argv[]);
|
||||
const char *message;
|
||||
struct pupa_rescue_command *next;
|
||||
};
|
||||
typedef struct pupa_rescue_command *pupa_rescue_command_t;
|
||||
|
||||
static char buf[PUPA_RESCUE_BUF_SIZE];
|
||||
|
||||
static pupa_rescue_command_t pupa_rescue_command_list;
|
||||
|
||||
void
|
||||
pupa_rescue_register_command (const char *name,
|
||||
void (*func) (int argc, char *argv[]),
|
||||
const char *message)
|
||||
{
|
||||
pupa_rescue_command_t cmd;
|
||||
|
||||
cmd = (pupa_rescue_command_t) pupa_malloc (sizeof (*cmd));
|
||||
if (! cmd)
|
||||
return;
|
||||
|
||||
cmd->name = name;
|
||||
cmd->func = func;
|
||||
cmd->message = message;
|
||||
|
||||
cmd->next = pupa_rescue_command_list;
|
||||
pupa_rescue_command_list = cmd;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_rescue_unregister_command (const char *name)
|
||||
{
|
||||
pupa_rescue_command_t *p, q;
|
||||
|
||||
for (p = &pupa_rescue_command_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (pupa_strcmp (name, q->name) == 0)
|
||||
{
|
||||
*p = q->next;
|
||||
pupa_free (q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Prompt to input a command and read the line. */
|
||||
static void
|
||||
pupa_rescue_get_command_line (const char *prompt)
|
||||
{
|
||||
int c;
|
||||
int pos = 0;
|
||||
|
||||
pupa_printf (prompt);
|
||||
pupa_memset (buf, 0, PUPA_RESCUE_BUF_SIZE);
|
||||
|
||||
while ((c = PUPA_TERM_ASCII_CHAR (pupa_getkey ())) != '\n' && c != '\r')
|
||||
{
|
||||
if (pupa_isprint (c))
|
||||
{
|
||||
if (pos < PUPA_RESCUE_BUF_SIZE - 1)
|
||||
{
|
||||
buf[pos++] = c;
|
||||
pupa_putchar (c);
|
||||
}
|
||||
}
|
||||
else if (c == '\b')
|
||||
{
|
||||
if (pos > 0)
|
||||
{
|
||||
buf[--pos] = 0;
|
||||
pupa_putchar (c);
|
||||
pupa_putchar (' ');
|
||||
pupa_putchar (c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pupa_putchar ('\n');
|
||||
}
|
||||
|
||||
/* Get the next word in STR and return a next pointer. */
|
||||
static char *
|
||||
next_word (char **str)
|
||||
{
|
||||
char *word;
|
||||
char *p = *str;
|
||||
|
||||
/* Skip spaces. */
|
||||
while (*p && pupa_isspace (*p))
|
||||
p++;
|
||||
|
||||
word = p;
|
||||
|
||||
/* Find a space. */
|
||||
while (*p && ! pupa_isspace (*p))
|
||||
p++;
|
||||
|
||||
*p = '\0';
|
||||
*str = p + 1;
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
/* boot */
|
||||
static void
|
||||
pupa_rescue_cmd_boot (int argc __attribute__ ((unused)),
|
||||
char *argv[] __attribute__ ((unused)))
|
||||
{
|
||||
pupa_loader_boot ();
|
||||
}
|
||||
|
||||
/* cat FILE */
|
||||
static void
|
||||
pupa_rescue_cmd_cat (int argc, char *argv[])
|
||||
{
|
||||
pupa_file_t file;
|
||||
char buf[PUPA_DISK_SECTOR_SIZE];
|
||||
pupa_ssize_t size;
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_ARGUMENT, "no file specified");
|
||||
return;
|
||||
}
|
||||
|
||||
file = pupa_file_open (argv[0]);
|
||||
if (! file)
|
||||
return;
|
||||
|
||||
while ((size = pupa_file_read (file, buf, sizeof (buf))) > 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
unsigned char c = buf[i];
|
||||
|
||||
if (pupa_isprint (c) || pupa_isspace (c))
|
||||
pupa_putchar (c);
|
||||
else
|
||||
{
|
||||
pupa_setcolorstate (PUPA_TERM_COLOR_HIGHLIGHT);
|
||||
pupa_printf ("<%x>", (int) c);
|
||||
pupa_setcolorstate (PUPA_TERM_COLOR_STANDARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pupa_putchar ('\n');
|
||||
pupa_file_close (file);
|
||||
}
|
||||
|
||||
static int
|
||||
pupa_rescue_print_disks (const char *name)
|
||||
{
|
||||
pupa_device_t dev;
|
||||
auto int print_partition (const pupa_partition_t p);
|
||||
|
||||
int print_partition (const pupa_partition_t p)
|
||||
{
|
||||
char *pname = pupa_partition_get_name (p);
|
||||
|
||||
if (pname)
|
||||
{
|
||||
pupa_printf ("(%s,%s) ", name, pname);
|
||||
pupa_free (pname);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev = pupa_device_open (name);
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
|
||||
if (dev)
|
||||
{
|
||||
pupa_printf ("(%s) ", name);
|
||||
|
||||
if (dev->disk && dev->disk->has_partitions)
|
||||
{
|
||||
pupa_partition_iterate (dev->disk, print_partition);
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
pupa_device_close (dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pupa_rescue_print_files (const char *filename, int dir)
|
||||
{
|
||||
pupa_printf ("%s%s ", filename, dir ? "/" : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ls [ARG] */
|
||||
static void
|
||||
pupa_rescue_cmd_ls (int argc, char *argv[])
|
||||
{
|
||||
if (argc < 1)
|
||||
{
|
||||
pupa_disk_dev_iterate (pupa_rescue_print_disks);
|
||||
pupa_putchar ('\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
char *device_name;
|
||||
pupa_device_t dev;
|
||||
pupa_fs_t fs;
|
||||
char *path;
|
||||
|
||||
device_name = pupa_file_get_device_name (argv[0]);
|
||||
dev = pupa_device_open (device_name);
|
||||
if (! dev)
|
||||
goto fail;
|
||||
|
||||
fs = pupa_fs_probe (dev);
|
||||
path = pupa_strchr (argv[0], '/');
|
||||
|
||||
if (! path && ! device_name)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_ARGUMENT, "invalid argument");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (! path)
|
||||
{
|
||||
if (pupa_errno == PUPA_ERR_UNKNOWN_FS)
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
|
||||
pupa_printf ("(%s): Filesystem is %s.\n",
|
||||
device_name, fs ? fs->name : "unknown");
|
||||
}
|
||||
else if (fs)
|
||||
{
|
||||
(fs->dir) (dev, path, pupa_rescue_print_files);
|
||||
pupa_putchar ('\n');
|
||||
}
|
||||
|
||||
fail:
|
||||
if (dev)
|
||||
pupa_device_close (dev);
|
||||
|
||||
pupa_free (device_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* help */
|
||||
static void
|
||||
pupa_rescue_cmd_help (int argc __attribute__ ((unused)),
|
||||
char *argv[] __attribute__ ((unused)))
|
||||
{
|
||||
pupa_rescue_command_t p, q;
|
||||
|
||||
/* Sort the commands. This is not a good algorithm, but this is enough,
|
||||
because rescue mode has a small number of commands. */
|
||||
for (p = pupa_rescue_command_list; p; p = p->next)
|
||||
for (q = p->next; q; q = q->next)
|
||||
if (pupa_strcmp (p->name, q->name) > 0)
|
||||
{
|
||||
struct pupa_rescue_command tmp;
|
||||
|
||||
tmp.name = p->name;
|
||||
tmp.func = p->func;
|
||||
tmp.message = p->message;
|
||||
|
||||
p->name = q->name;
|
||||
p->func = q->func;
|
||||
p->message = q->message;
|
||||
|
||||
q->name = tmp.name;
|
||||
q->func = tmp.func;
|
||||
q->message = tmp.message;
|
||||
}
|
||||
|
||||
/* Print them. */
|
||||
for (p = pupa_rescue_command_list; p; p = p->next)
|
||||
pupa_printf ("%s\t%s\n", p->name, p->message);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
pupa_rescue_cmd_info (void)
|
||||
{
|
||||
extern void pupa_disk_cache_get_performance (unsigned long *,
|
||||
unsigned long *);
|
||||
unsigned long hits, misses;
|
||||
|
||||
pupa_disk_cache_get_performance (&hits, &misses);
|
||||
pupa_printf ("Disk cache: hits = %u, misses = %u ", hits, misses);
|
||||
if (hits + misses)
|
||||
{
|
||||
unsigned long ratio = hits * 10000 / (hits + misses);
|
||||
pupa_printf ("(%u.%u%%)\n", ratio / 100, ratio % 100);
|
||||
}
|
||||
else
|
||||
pupa_printf ("(N/A)\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* (module|initrd) FILE [ARGS] */
|
||||
static void
|
||||
pupa_rescue_cmd_module (int argc, char *argv[])
|
||||
{
|
||||
pupa_loader_load_module (argc, argv);
|
||||
}
|
||||
|
||||
/* root [DEVICE] */
|
||||
static void
|
||||
pupa_rescue_cmd_root (int argc, char *argv[])
|
||||
{
|
||||
pupa_device_t dev;
|
||||
pupa_fs_t fs;
|
||||
|
||||
if (argc > 0)
|
||||
{
|
||||
char *device_name = pupa_file_get_device_name (argv[0]);
|
||||
if (! device_name)
|
||||
return;
|
||||
|
||||
pupa_device_set_root (device_name);
|
||||
pupa_free (device_name);
|
||||
}
|
||||
|
||||
dev = pupa_device_open (0);
|
||||
if (! dev)
|
||||
return;
|
||||
|
||||
fs = pupa_fs_probe (dev);
|
||||
if (pupa_errno == PUPA_ERR_UNKNOWN_FS)
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
|
||||
pupa_printf ("(%s): Filesystem is %s.\n",
|
||||
pupa_device_get_root (), fs ? fs->name : "unknown");
|
||||
|
||||
pupa_device_close (dev);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
pupa_rescue_cmd_testload (int argc, char *argv[])
|
||||
{
|
||||
pupa_file_t file;
|
||||
char *buf;
|
||||
pupa_ssize_t size;
|
||||
pupa_ssize_t pos;
|
||||
auto void read_func (unsigned long sector, unsigned offset, unsigned len);
|
||||
|
||||
void read_func (unsigned long sector __attribute__ ((unused)),
|
||||
unsigned offset __attribute__ ((unused)),
|
||||
unsigned len __attribute__ ((unused)))
|
||||
{
|
||||
pupa_putchar ('.');
|
||||
}
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_ARGUMENT, "no file specified");
|
||||
return;
|
||||
}
|
||||
|
||||
file = pupa_file_open (argv[0]);
|
||||
if (! file)
|
||||
return;
|
||||
|
||||
size = pupa_file_size (file) & ~(PUPA_DISK_SECTOR_SIZE - 1);
|
||||
if (size == 0)
|
||||
{
|
||||
pupa_file_close (file);
|
||||
return;
|
||||
}
|
||||
|
||||
buf = pupa_malloc (size);
|
||||
if (! buf)
|
||||
goto fail;
|
||||
|
||||
pupa_printf ("Reading %s sequentially", argv[0]);
|
||||
file->read_hook = read_func;
|
||||
if (pupa_file_read (file, buf, size) != size)
|
||||
goto fail;
|
||||
pupa_printf (" Done.\n");
|
||||
|
||||
/* Read sequentially again. */
|
||||
pupa_printf ("Reading %s sequentially again", argv[0]);
|
||||
if (pupa_file_seek (file, 0) < 0)
|
||||
goto fail;
|
||||
|
||||
for (pos = 0; pos < size; pos += PUPA_DISK_SECTOR_SIZE)
|
||||
{
|
||||
char sector[PUPA_DISK_SECTOR_SIZE];
|
||||
|
||||
if (pupa_file_read (file, sector, PUPA_DISK_SECTOR_SIZE)
|
||||
!= PUPA_DISK_SECTOR_SIZE)
|
||||
goto fail;
|
||||
|
||||
if (pupa_memcmp (sector, buf + pos, PUPA_DISK_SECTOR_SIZE) != 0)
|
||||
{
|
||||
pupa_printf ("\nDiffers in %d\n", pos);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
pupa_printf (" Done.\n");
|
||||
|
||||
/* Read backwards and compare. */
|
||||
pupa_printf ("Reading %s backwards", argv[0]);
|
||||
pos = size;
|
||||
while (pos > 0)
|
||||
{
|
||||
char sector[PUPA_DISK_SECTOR_SIZE];
|
||||
|
||||
pos -= PUPA_DISK_SECTOR_SIZE;
|
||||
|
||||
if (pupa_file_seek (file, pos) < 0)
|
||||
goto fail;
|
||||
|
||||
if (pupa_file_read (file, sector, PUPA_DISK_SECTOR_SIZE)
|
||||
!= PUPA_DISK_SECTOR_SIZE)
|
||||
goto fail;
|
||||
|
||||
if (pupa_memcmp (sector, buf + pos, PUPA_DISK_SECTOR_SIZE) != 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
pupa_printf ("\nDiffers in %d\n", pos);
|
||||
|
||||
for (i = 0; i < PUPA_DISK_SECTOR_SIZE; i++)
|
||||
pupa_putchar (buf[pos + i]);
|
||||
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
pupa_printf (" Done.\n");
|
||||
|
||||
fail:
|
||||
|
||||
pupa_file_close (file);
|
||||
pupa_free (buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
pupa_rescue_cmd_dump (int argc, char *argv[])
|
||||
{
|
||||
pupa_uint8_t *addr;
|
||||
pupa_size_t size = 4;
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_ARGUMENT, "no address specified");
|
||||
return;
|
||||
}
|
||||
|
||||
addr = (pupa_uint8_t *) pupa_strtoul (argv[0], 0, 0);
|
||||
if (pupa_errno)
|
||||
return;
|
||||
|
||||
if (argc > 1)
|
||||
size = (pupa_size_t) pupa_strtoul (argv[1], 0, 0);
|
||||
|
||||
while (size--)
|
||||
{
|
||||
pupa_printf ("%x%x ", *addr >> 4, *addr & 0xf);
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter the rescue mode. */
|
||||
void
|
||||
pupa_enter_rescue_mode (void)
|
||||
{
|
||||
pupa_rescue_register_command ("boot", pupa_rescue_cmd_boot,
|
||||
"boot an operating system");
|
||||
pupa_rescue_register_command ("cat", pupa_rescue_cmd_cat,
|
||||
"show the contents of a file");
|
||||
pupa_rescue_register_command ("help", pupa_rescue_cmd_help,
|
||||
"show this message");
|
||||
pupa_rescue_register_command ("initrd", pupa_rescue_cmd_module,
|
||||
"load an initrd");
|
||||
pupa_rescue_register_command ("ls", pupa_rescue_cmd_ls,
|
||||
"list devices or files");
|
||||
pupa_rescue_register_command ("module", pupa_rescue_cmd_module,
|
||||
"load an OS module");
|
||||
pupa_rescue_register_command ("root", pupa_rescue_cmd_root,
|
||||
"set a root device");
|
||||
pupa_rescue_register_command ("dump", pupa_rescue_cmd_dump,
|
||||
"dump memory");
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *line = buf;
|
||||
char *name;
|
||||
int n;
|
||||
pupa_rescue_command_t cmd;
|
||||
char *args[PUPA_RESCUE_MAX_ARGS + 1];
|
||||
|
||||
/* Get a command line. */
|
||||
pupa_rescue_get_command_line ("pupa rescue> ");
|
||||
|
||||
/* Get the command name. */
|
||||
name = next_word (&line);
|
||||
|
||||
/* If nothing is specified, restart. */
|
||||
if (*name == '\0')
|
||||
continue;
|
||||
|
||||
/* Get arguments. */
|
||||
for (n = 0; n <= PUPA_RESCUE_MAX_ARGS; n++)
|
||||
{
|
||||
char *arg = next_word (&line);
|
||||
|
||||
if (*arg)
|
||||
args[n] = arg;
|
||||
else
|
||||
break;
|
||||
}
|
||||
args[n] = 0;
|
||||
|
||||
/* Find the command and execute it. */
|
||||
for (cmd = pupa_rescue_command_list; cmd; cmd = cmd->next)
|
||||
{
|
||||
if (pupa_strcmp (name, cmd->name) == 0)
|
||||
{
|
||||
(cmd->func) (n, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If not found, print an error message. */
|
||||
if (! cmd)
|
||||
{
|
||||
pupa_printf ("Unknown command `%s'\n", name);
|
||||
pupa_printf ("Try `help' for usage\n");
|
||||
}
|
||||
|
||||
/* Print an error, if any. */
|
||||
pupa_print_error ();
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
}
|
||||
}
|
153
kern/term.c
Normal file
153
kern/term.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/term.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/mm.h>
|
||||
|
||||
/* The list of terminals. */
|
||||
static pupa_term_t pupa_term_list;
|
||||
|
||||
/* The current terminal. */
|
||||
static pupa_term_t pupa_cur_term;
|
||||
|
||||
void
|
||||
pupa_term_register (pupa_term_t term)
|
||||
{
|
||||
term->next = pupa_term_list;
|
||||
pupa_term_list = term;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_term_unregister (pupa_term_t term)
|
||||
{
|
||||
pupa_term_t *p, q;
|
||||
|
||||
for (p = &pupa_term_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (q == term)
|
||||
{
|
||||
*p = q->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pupa_term_iterate (int (*hook) (pupa_term_t term))
|
||||
{
|
||||
pupa_term_t p;
|
||||
|
||||
for (p = pupa_term_list; p; p = p->next)
|
||||
if (hook (p))
|
||||
break;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_term_set_current (pupa_term_t term)
|
||||
{
|
||||
pupa_cur_term = term;
|
||||
}
|
||||
|
||||
pupa_term_t
|
||||
pupa_term_get_current (void)
|
||||
{
|
||||
return pupa_cur_term;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_putchar (int c)
|
||||
{
|
||||
if (c == '\n')
|
||||
pupa_putchar ('\r');
|
||||
else if (c == '\t' && pupa_cur_term->getxy)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = 8 - ((pupa_getxy () >> 8) & 7);
|
||||
while (n--)
|
||||
pupa_putchar (' ');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
(pupa_cur_term->putchar) (c);
|
||||
}
|
||||
|
||||
int
|
||||
pupa_getkey (void)
|
||||
{
|
||||
return (pupa_cur_term->getkey) ();
|
||||
}
|
||||
|
||||
int
|
||||
pupa_checkkey (void)
|
||||
{
|
||||
return (pupa_cur_term->checkkey) ();
|
||||
}
|
||||
|
||||
pupa_uint16_t
|
||||
pupa_getxy (void)
|
||||
{
|
||||
return (pupa_cur_term->getxy) ();
|
||||
}
|
||||
|
||||
void
|
||||
pupa_gotoxy (pupa_uint8_t x, pupa_uint8_t y)
|
||||
{
|
||||
(pupa_cur_term->gotoxy) (x, y);
|
||||
}
|
||||
|
||||
void
|
||||
pupa_cls (void)
|
||||
{
|
||||
if (pupa_cur_term->flags & PUPA_TERM_DUMB)
|
||||
pupa_putchar ('\n');
|
||||
else
|
||||
(pupa_cur_term->cls) ();
|
||||
}
|
||||
|
||||
void
|
||||
pupa_setcolorstate (pupa_term_color_state state)
|
||||
{
|
||||
if (pupa_cur_term->setcolorstate)
|
||||
(pupa_cur_term->setcolorstate) (state);
|
||||
}
|
||||
|
||||
void
|
||||
pupa_setcolor (pupa_uint8_t normal_color, pupa_uint8_t highlight_color)
|
||||
{
|
||||
if (pupa_cur_term->setcolor)
|
||||
(pupa_cur_term->setcolor) (normal_color, highlight_color);
|
||||
}
|
||||
|
||||
int
|
||||
pupa_setcursor (int on)
|
||||
{
|
||||
static int prev = 1;
|
||||
int ret = prev;
|
||||
|
||||
if (pupa_cur_term->setcursor)
|
||||
{
|
||||
(pupa_cur_term->setcursor) (on);
|
||||
prev = on;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue