+2004-02-15 Jeroen Dekkers <jeroen@dekkers.cx>
+
+ * fs/ext2.c (pupa_ext2_read_file): Correct the value of BLOCKEND
+ when it is EXT2_BLOCK_SIZE (data). New argument READ_HOOK, all
+ callers changed. Set DATA->DISK->READ_HOOK to READ_HOOK before
+ reading and reset it after reading.
+ (pupa_ext2_close): Return PUPA_ERR_NONE.
+
+ * include/pupa/i386/pc/linux.h (PUPA_LINUX_INITRD_MAX_ADDRESS):
+ Correct value.
+ (struct linux_kernel_header): Add kernel_version and
+ initrd_addr_max.
+ * loader/i386/pc/linux.c (pupa_rescue_cmd_linux): Check whether
+ pupa_file_read succeeds.
+ (pupa_rescue_cmd_initrd): Implement.
+
2003-12-03 Marco Gerards <metgerards@student.han.nl>
* fs/ext2.c (pupa_ext2_label): New function.
/* ext2.c - Second Extended filesystem */
/*
* PUPA -- Preliminary Universal Programming Architecture for GRUB
+ * Copyright (C) 2004 Free Software Foundation, Inc.
* Copyright (C) 2003 Marco Gerards <metgerards@student.han.nl>.
*
* This program is free software; you can redistribute it and/or modify
/* Read LEN bytes from the file described by DATA starting with byte
POS. Return the amount of read bytes in READ. */
static pupa_ssize_t
-pupa_ext2_read_file (struct pupa_ext2_data *data, int pos,
- unsigned int len, char *buf)
+pupa_ext2_read_file (struct pupa_ext2_data *data,
+ void (*read_hook) (unsigned long sector,
+ unsigned offset, unsigned length),
+ int pos, unsigned int len, char *buf)
{
int i;
int blockcnt;
/* Last block. */
if (i == blockcnt - 1)
- blockend = (len + pos) % EXT2_BLOCK_SIZE (data);
+ {
+ blockend = (len + pos) % EXT2_BLOCK_SIZE (data);
+
+ /* The last portion is exactly EXT2_BLOCK_SIZE (data). */
+ if (!blockend)
+ blockend = EXT2_BLOCK_SIZE (data);
+ }
/* First block. */
if (i == pos / EXT2_BLOCK_SIZE (data))
is zero filled instead. */
if (blknr)
{
+ data->disk->read_hook = read_hook;
pupa_disk_read (data->disk, blknr, skipfirst,
- blockend, buf);
+ blockend, buf);
+ data->disk->read_hook = 0;
if (pupa_errno)
return -1;
}
struct ext2_dirent dirent;
/* Read the directory entry. */
- pupa_ext2_read_file (data, fpos, sizeof (struct ext2_dirent),
+ pupa_ext2_read_file (data, 0, fpos, sizeof (struct ext2_dirent),
(char *) &dirent);
if (pupa_errno)
goto fail;
char filename[dirent.namelen + 1];
/* Read the filename part of this directory entry. */
- pupa_ext2_read_file (data, fpos
+ pupa_ext2_read_file (data, 0, fpos
+ sizeof (struct ext2_dirent),
dirent.namelen, filename);
if (pupa_errno)
pupa_le_to_cpu32 (inode->size));
else
{
- pupa_ext2_read_file (data, 0,
+ pupa_ext2_read_file (data, 0, 0,
pupa_le_to_cpu32 (inode->size),
symlink);
if (pupa_errno)
pupa_dl_unref (my_mod);
#endif
- return pupa_errno;
+ return PUPA_ERR_NONE;
}
/* Read LEN bytes data from FILE into BUF. */
struct pupa_ext2_data *data =
(struct pupa_ext2_data *) file->data;
- return pupa_ext2_read_file (data, file->offset, len, buf);
+ return pupa_ext2_read_file (data, file->read_hook, file->offset, len, buf);
}
{
struct ext2_dirent dirent;
- pupa_ext2_read_file (data, fpos, sizeof (struct ext2_dirent),
+ pupa_ext2_read_file (data, 0, fpos, sizeof (struct ext2_dirent),
(char *) &dirent);
if (pupa_errno)
goto fail;
{
char filename[dirent.namelen + 1];
- pupa_ext2_read_file (data, fpos + sizeof (struct ext2_dirent),
+ pupa_ext2_read_file (data, 0, fpos + sizeof (struct ext2_dirent),
dirent.namelen, filename);
if (pupa_errno)
goto fail;
/*
* PUPA -- Preliminary Universal Programming Architecture for GRUB
- * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
+ * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc.
* Copyright (C) 2003 Yoshinori K. Okuji <okuji@enbug.org>
*
* This program is free software; you can redistribute it and/or modify
#define PUPA_LINUX_MAGIC_SIGNATURE 0x53726448 /* "HdrS" */
#define PUPA_LINUX_DEFAULT_SETUP_SECTS 4
#define PUPA_LINUX_FLAG_CAN_USE_HEAP 0x80
-#define PUPA_LINUX_INITRD_MAX_ADDRESS 0x38000000
+#define PUPA_LINUX_INITRD_MAX_ADDRESS 0x37FFFFFF
#define PUPA_LINUX_MAX_SETUP_SECTS 64
#define PUPA_LINUX_BOOT_LOADER_TYPE 0x72
#define PUPA_LINUX_HEAP_END_OFFSET (0x9000 - 0x200)
pupa_uint32_t header; /* Magic signature "HdrS" */
pupa_uint16_t version; /* Boot protocol version supported */
pupa_uint32_t realmode_swtch; /* Boot loader hook */
- pupa_uint32_t start_sys; /* Points to kernel version string */
+ pupa_uint16_t start_sys; /* The load-low segment (obsolete) */
+ pupa_uint16_t kernel_version; /* Points to kernel version string */
pupa_uint8_t type_of_loader; /* Boot loader identifier */
pupa_uint8_t loadflags; /* Boot protocol option flags */
pupa_uint16_t setup_move_size; /* Move to high memory size */
pupa_uint16_t heap_end_ptr; /* Free memory after setup end */
pupa_uint16_t pad1; /* Unused */
char *cmd_line_ptr; /* Points to the kernel command line */
+ pupa_uint32_t initrd_addr_max; /* Highest address for initrd */
} __attribute__ ((packed));
#endif /* ! ASM_FILE */
/* linux.c - boot Linux zImage or bzImage */
/*
* PUPA -- Preliminary Universal Programming Architecture for GRUB
- * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
+ * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc.
* Copyright (C) 2003 Yoshinori K. Okuji <okuji@enbug.org>
*
* This program is free software; you can redistribute it and/or modify
struct linux_kernel_header lh;
pupa_uint8_t setup_sects;
pupa_size_t real_size, prot_size;
+ pupa_ssize_t len;
int i;
char *dest;
/* Put the real mode code at the temporary address. */
pupa_memmove (pupa_linux_tmp_addr, &lh, sizeof (lh));
- pupa_file_read (file, pupa_linux_tmp_addr + sizeof (lh),
- real_size + PUPA_DISK_SECTOR_SIZE - sizeof (lh));
+
+ len = real_size + PUPA_DISK_SECTOR_SIZE - sizeof (lh);
+ if (pupa_file_read (file, pupa_linux_tmp_addr + sizeof (lh), len) != len)
+ {
+ pupa_error (PUPA_ERR_FILE_READ_ERROR, "Couldn't read file");
+ goto fail;
+ }
if (lh.header != pupa_cpu_to_le32 (PUPA_LINUX_MAGIC_SIGNATURE)
|| pupa_le_to_cpu16 (lh.version) < 0x0200)
*dest = '\0';
- pupa_file_read (file, (char *) PUPA_LINUX_BZIMAGE_ADDR, prot_size);
-
+ len = prot_size;
+ if (pupa_file_read (file, (char *) PUPA_LINUX_BZIMAGE_ADDR, len) != len)
+ pupa_error (PUPA_ERR_FILE_READ_ERROR, "Couldn't read file");
+
if (pupa_errno == PUPA_ERR_NONE)
{
pupa_linux_prot_size = prot_size;
void
pupa_rescue_cmd_initrd (int argc, char *argv[])
{
- pupa_error (PUPA_ERR_NOT_IMPLEMENTED_YET, "not implemented yet");
+ pupa_file_t file = 0;
+ pupa_ssize_t size;
+ pupa_addr_t addr_max, addr_min, addr;
+ struct linux_kernel_header *lh;
+
+ if (argc == 0)
+ {
+ pupa_error (PUPA_ERR_BAD_ARGUMENT, "No module specified");
+ goto fail;
+ }
+
+ if (!loaded)
+ {
+ pupa_error (PUPA_ERR_BAD_ARGUMENT, "You need to load the kernel first.");
+ goto fail;
+ }
+
+ lh = (struct linux_kernel_header *) pupa_linux_tmp_addr;
+
+ if (!(lh->header == pupa_cpu_to_le32 (PUPA_LINUX_MAGIC_SIGNATURE)
+ && pupa_le_to_cpu16 (lh->version) >= 0x0200))
+ {
+ pupa_error (PUPA_ERR_BAD_OS, "The kernel is too old for initrd.");
+ goto fail;
+ }
+
+ /* Get the highest address available for the initrd. */
+ if (pupa_le_to_cpu16 (lh->version) >= 0x0203)
+ addr_max = pupa_cpu_to_le32 (lh->initrd_addr_max);
+ else
+ addr_max = PUPA_LINUX_INITRD_MAX_ADDRESS;
+
+ if (!linux_mem_size && linux_mem_size < addr_max)
+ addr_max = linux_mem_size;
+
+ /* Linux 2.3.xx has a bug in the memory range check, so avoid
+ the last page.
+ Linux 2.2.xx has a bug in the memory range check, which is
+ worse than that of Linux 2.3.xx, so avoid the last 64kb. */
+ addr_max -= 0x10000;
+
+ if (addr_max > pupa_os_area_addr + pupa_os_area_size)
+ addr_max = pupa_os_area_addr + pupa_os_area_size;
+
+ addr_min = (pupa_addr_t) pupa_linux_tmp_addr + PUPA_LINUX_CL_END_OFFSET;
+
+ file = pupa_file_open (argv[0]);
+ if (!file)
+ goto fail;
+
+ size = pupa_file_size (file);
+
+ /* Put the initrd as high as possible, 4Ki aligned. */
+ addr = (addr_max - size) & ~0xFFF;
+
+ if (addr < addr_min)
+ {
+ pupa_error (PUPA_ERR_OUT_OF_RANGE, "The initrd is too big");
+ goto fail;
+ }
+
+ if (pupa_file_read (file, (void *)addr, size) != size)
+ {
+ pupa_error (PUPA_ERR_FILE_READ_ERROR, "Couldn't read file");
+ goto fail;
+ }
+
+ lh->ramdisk_image = addr;
+ lh->ramdisk_size = size;
+
+ fail:
+ if (file)
+ pupa_file_close (file);
}
+
PUPA_MOD_INIT
{
pupa_rescue_register_command ("linux",