/*
|
/*
|
* loader.c -- the NetBSD system loader
|
* loader.c -- the NetBSD system loader
|
*/
|
*/
|
|
|
|
|
#include "types.h"
|
#include "types.h"
|
#include "disklabel.h"
|
#include "disklabel.h"
|
#include "fs.h"
|
#include "fs.h"
|
#include "dinode.h"
|
#include "dinode.h"
|
#include "dir.h"
|
#include "dir.h"
|
#include "stdarg.h"
|
#include "stdarg.h"
|
#include "auxlib.h"
|
#include "auxlib.h"
|
#include "biolib.h"
|
#include "biolib.h"
|
#include "elf.h"
|
#include "elf.h"
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* constants and data types */
|
/* constants and data types */
|
|
|
|
|
#define DFLT_KERNEL "/netbsd" /* default path to kernel */
|
#define DFLT_KERNEL "/netbsd" /* default path to kernel */
|
|
|
#define MAX_LINE 100 /* line buffer size */
|
#define MAX_LINE 100 /* line buffer size */
|
|
|
#define SSHIFT 9 /* ld of sector size */
|
#define SSHIFT 9 /* ld of sector size */
|
#define SSIZE (1 << SSHIFT) /* disk sector size in bytes */
|
#define SSIZE (1 << SSHIFT) /* disk sector size in bytes */
|
#define SMASK (SSIZE - 1) /* sector mask */
|
#define SMASK (SSIZE - 1) /* sector mask */
|
|
|
#define BSHIFT 13 /* ld of block size */
|
#define BSHIFT 13 /* ld of block size */
|
#define BSIZE (1 << BSHIFT) /* disk block size in bytes */
|
#define BSIZE (1 << BSHIFT) /* disk block size in bytes */
|
#define BMASK (BSIZE - 1) /* block mask */
|
#define BMASK (BSIZE - 1) /* block mask */
|
|
|
|
|
typedef struct ufs1_dinode Dinode;
|
typedef struct ufs1_dinode Dinode;
|
typedef struct direct Dirent;
|
typedef struct direct Dirent;
|
typedef unsigned int daddr_t;
|
typedef unsigned int daddr_t;
|
typedef unsigned int ino_t;
|
typedef unsigned int ino_t;
|
|
|
|
|
#define NIPB (BSIZE / sizeof(Dinode))
|
#define NIPB (BSIZE / sizeof(Dinode))
|
|
|
#define NULL 0
|
#define NULL 0
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* debugging */
|
/* debugging */
|
|
|
|
|
Bool debugReadSectors = FALSE;
|
Bool debugReadSectors = FALSE;
|
Bool debugReadDiskLabel = FALSE;
|
Bool debugReadDiskLabel = FALSE;
|
Bool debugReadSuperBlock = FALSE;
|
Bool debugReadSuperBlock = FALSE;
|
Bool debugGetInode = FALSE;
|
Bool debugGetInode = FALSE;
|
Bool debugSearchDir = FALSE;
|
Bool debugSearchDir = FALSE;
|
Bool debugLoadElf = FALSE;
|
Bool debugLoadElf = FALSE;
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* halt with error message */
|
/* halt with error message */
|
|
|
|
|
void halt(char *msg) {
|
void halt(char *msg) {
|
printf("%s, machine halted.\n", msg);
|
printf("%s, machine halted.\n", msg);
|
while (1) ;
|
while (1) ;
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* disk I/O */
|
/* disk I/O */
|
|
|
|
|
unsigned int bootDisk = 0; /* gets loaded by previous stage */
|
unsigned int bootDisk = 0; /* gets loaded by previous stage */
|
/* never changed */
|
/* never changed */
|
unsigned int startSector = 0; /* gets loaded by previous stage */
|
unsigned int startSector = 0; /* gets loaded by previous stage */
|
/* initially holds start of slice */
|
/* initially holds start of slice */
|
/* disklabel read --> start of partition */
|
/* disklabel read --> start of partition */
|
unsigned int numSectors = 0; /* gets loaded by previous stage */
|
unsigned int numSectors = 0; /* gets loaded by previous stage */
|
/* initially holds size of slice */
|
/* initially holds size of slice */
|
/* disklabel read --> size of partition */
|
/* disklabel read --> size of partition */
|
|
|
unsigned int spf; /* superblock read --> sectors per fragment */
|
unsigned int spf; /* superblock read --> sectors per fragment */
|
unsigned int spb; /* superblock read --> sectors per block */
|
unsigned int spb; /* superblock read --> sectors per block */
|
|
|
|
|
/*
|
/*
|
* read disk sectors
|
* read disk sectors
|
*
|
*
|
* NOTE: buffer must be word-aligned
|
* NOTE: buffer must be word-aligned
|
*/
|
*/
|
void readSectors(unsigned int start,
|
void readSectors(unsigned int start,
|
unsigned int count,
|
unsigned int count,
|
void *buffer) {
|
void *buffer) {
|
unsigned int sector;
|
unsigned int sector;
|
int result;
|
int result;
|
|
|
if (start + count > numSectors) {
|
if (start + count > numSectors) {
|
halt("Sector number exceeds slice or partition size");
|
halt("Sector number exceeds slice or partition size");
|
}
|
}
|
sector = startSector + start;
|
sector = startSector + start;
|
if (debugReadSectors) {
|
if (debugReadSectors) {
|
printf("DEBUG: reading sector 0x%08X, %d sectors\n", sector, count);
|
printf("DEBUG: reading sector 0x%08X, %d sectors\n", sector, count);
|
}
|
}
|
result = rwscts(bootDisk, 'r', sector,
|
result = rwscts(bootDisk, 'r', sector,
|
(unsigned int) buffer & 0x3FFFFFFF, count);
|
(unsigned int) buffer & 0x3FFFFFFF, count);
|
if (result != 0) {
|
if (result != 0) {
|
halt("Load error");
|
halt("Load error");
|
}
|
}
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* disklabel handling */
|
/* disklabel handling */
|
|
|
|
|
unsigned int diskLabel[SSIZE / sizeof(unsigned int)];
|
unsigned int diskLabel[SSIZE / sizeof(unsigned int)];
|
DiskLabel *dlp = (DiskLabel *) &diskLabel[0];
|
DiskLabel *dlp = (DiskLabel *) &diskLabel[0];
|
|
|
unsigned int superStart; /* partition-relative offset, in sectors */
|
unsigned int superStart; /* partition-relative offset, in sectors */
|
unsigned int superSize; /* size, in sectors */
|
unsigned int superSize; /* size, in sectors */
|
|
|
|
|
void readDiskLabel(void) {
|
void readDiskLabel(void) {
|
readSectors(1, 1, dlp);
|
readSectors(1, 1, dlp);
|
if (dlp->d_magic != DSKMAGIC ||
|
if (dlp->d_magic != DSKMAGIC ||
|
dlp->d_magic2 != DSKMAGIC) {
|
dlp->d_magic2 != DSKMAGIC) {
|
halt("Disklabel corrupted");
|
halt("Disklabel corrupted");
|
}
|
}
|
|
|
startSector = dlp->d_parts[0].p_offset;
|
startSector = dlp->d_parts[0].p_offset;
|
numSectors = dlp->d_parts[0].p_size;
|
numSectors = dlp->d_parts[0].p_size;
|
|
|
superStart = dlp->d_bbsize;
|
superStart = dlp->d_bbsize;
|
if ((superStart & SMASK) != 0) {
|
if ((superStart & SMASK) != 0) {
|
halt("Superblock offset is not multiple of sector size");
|
halt("Superblock offset is not multiple of sector size");
|
}
|
}
|
superStart >>= SSHIFT;
|
superStart >>= SSHIFT;
|
|
|
superSize = dlp->d_sbsize;
|
superSize = dlp->d_sbsize;
|
if ((superSize & SMASK) != 0) {
|
if ((superSize & SMASK) != 0) {
|
halt("Superblock size is not multiple of sector size");
|
halt("Superblock size is not multiple of sector size");
|
}
|
}
|
if (superSize > BSIZE) {
|
if (superSize > BSIZE) {
|
halt("Superblock too big");
|
halt("Superblock too big");
|
}
|
}
|
superSize >>= SSHIFT;
|
superSize >>= SSHIFT;
|
|
|
if (debugReadDiskLabel) {
|
if (debugReadDiskLabel) {
|
printf("DEBUG: super start = %d sectors, super size = %d sectors\n",
|
printf("DEBUG: super start = %d sectors, super size = %d sectors\n",
|
superStart, superSize);
|
superStart, superSize);
|
}
|
}
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* superblock handling */
|
/* superblock handling */
|
|
|
|
|
unsigned int superBlock[BSIZE / sizeof(unsigned int)];
|
unsigned int superBlock[BSIZE / sizeof(unsigned int)];
|
struct fs *sbp = (struct fs *) &superBlock[0];
|
struct fs *sbp = (struct fs *) &superBlock[0];
|
|
|
|
|
void readSuperBlock(void) {
|
void readSuperBlock(void) {
|
readSectors(superStart, superSize, sbp);
|
readSectors(superStart, superSize, sbp);
|
if (sbp->fs_magic != FS_UFS1_MAGIC) {
|
if (sbp->fs_magic != FS_UFS1_MAGIC) {
|
halt("Wrong magic number in superblock");
|
halt("Wrong magic number in superblock");
|
}
|
}
|
spf = sbp->fs_fsize / SSIZE;
|
spf = sbp->fs_fsize / SSIZE;
|
spb = sbp->fs_bsize / SSIZE;
|
spb = sbp->fs_bsize / SSIZE;
|
if (sbp->fs_inopb != NIPB) {
|
if (sbp->fs_inopb != NIPB) {
|
halt("Wrong number of inodes per block");
|
halt("Wrong number of inodes per block");
|
}
|
}
|
if (debugReadSuperBlock) {
|
if (debugReadSuperBlock) {
|
printf("DEBUG: %d sectors per fragment\n", spf);
|
printf("DEBUG: %d sectors per fragment\n", spf);
|
printf("DEBUG: %d sectors per block\n", spb);
|
printf("DEBUG: %d sectors per block\n", spb);
|
printf("DEBUG: %d inodes per block\n", NIPB);
|
printf("DEBUG: %d inodes per block\n", NIPB);
|
}
|
}
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* file operations */
|
/* file operations */
|
|
|
|
|
unsigned int sibno = 0;
|
unsigned int sibno = 0;
|
unsigned int sib[8192 / sizeof(unsigned int)];
|
unsigned int sib[8192 / sizeof(unsigned int)];
|
unsigned int *sibp = (unsigned int *) &sib[0];
|
unsigned int *sibp = (unsigned int *) &sib[0];
|
|
|
|
|
/*
|
/*
|
* read a block of a file
|
* read a block of a file
|
*
|
*
|
* NOTE: addr must be word-aligned
|
* NOTE: addr must be word-aligned
|
*/
|
*/
|
void readFileBlock(Dinode *ip, int blkno, void *addr) {
|
void readFileBlock(Dinode *ip, int blkno, void *addr) {
|
unsigned int diskFrag;
|
unsigned int diskFrag;
|
|
|
if (blkno < NDADDR) {
|
if (blkno < NDADDR) {
|
/* direct block */
|
/* direct block */
|
diskFrag = ip->di_db[blkno];
|
diskFrag = ip->di_db[blkno];
|
} else
|
} else
|
if (blkno - NDADDR < sbp->fs_bsize / sizeof(int32_t)) {
|
if (blkno - NDADDR < sbp->fs_bsize / sizeof(int32_t)) {
|
/* single indirect block */
|
/* single indirect block */
|
if (sibno != ip->di_ib[0]) {
|
if (sibno != ip->di_ib[0]) {
|
sibno = ip->di_ib[0];
|
sibno = ip->di_ib[0];
|
readSectors(sibno * spf, spb, sibp);
|
readSectors(sibno * spf, spb, sibp);
|
}
|
}
|
diskFrag = sibp[blkno - NDADDR];
|
diskFrag = sibp[blkno - NDADDR];
|
} else {
|
} else {
|
/* double or triple indirect blocks */
|
/* double or triple indirect blocks */
|
halt("Cannot do double or triple indirect blocks");
|
halt("Cannot do double or triple indirect blocks");
|
}
|
}
|
readSectors(diskFrag * spf, spb, addr);
|
readSectors(diskFrag * spf, spb, addr);
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* read a number of bytes from a file
|
* read a number of bytes from a file
|
*/
|
*/
|
void readFile(Dinode *ip, unsigned int offset,
|
void readFile(Dinode *ip, unsigned int offset,
|
unsigned int size, void *buffer) {
|
unsigned int size, void *buffer) {
|
unsigned int dskblk[8192 / sizeof(unsigned int)];
|
unsigned int dskblk[8192 / sizeof(unsigned int)];
|
unsigned char *bufp;
|
unsigned char *bufp;
|
unsigned char *blkp;
|
unsigned char *blkp;
|
unsigned int blkno;
|
unsigned int blkno;
|
unsigned int index;
|
unsigned int index;
|
unsigned int aux;
|
unsigned int aux;
|
unsigned int numBytes;
|
unsigned int numBytes;
|
int i;
|
int i;
|
|
|
bufp = (unsigned char *) buffer;
|
bufp = (unsigned char *) buffer;
|
blkp = (unsigned char *) dskblk;
|
blkp = (unsigned char *) dskblk;
|
blkno = offset / sbp->fs_bsize;
|
blkno = offset / sbp->fs_bsize;
|
index = offset % sbp->fs_bsize;
|
index = offset % sbp->fs_bsize;
|
aux = sbp->fs_bsize - index;
|
aux = sbp->fs_bsize - index;
|
numBytes = (size <= aux) ? size : aux;
|
numBytes = (size <= aux) ? size : aux;
|
readFileBlock(ip, blkno, blkp);
|
readFileBlock(ip, blkno, blkp);
|
for (i = 0; i < numBytes; i++) {
|
for (i = 0; i < numBytes; i++) {
|
*bufp++ = blkp[index++];
|
*bufp++ = blkp[index++];
|
}
|
}
|
blkno++;
|
blkno++;
|
size -= numBytes;
|
size -= numBytes;
|
while (size >= sbp->fs_bsize) {
|
while (size >= sbp->fs_bsize) {
|
index = 0;
|
index = 0;
|
numBytes = sbp->fs_bsize;
|
numBytes = sbp->fs_bsize;
|
readFileBlock(ip, blkno, blkp);
|
readFileBlock(ip, blkno, blkp);
|
for (i = 0; i < numBytes; i++) {
|
for (i = 0; i < numBytes; i++) {
|
*bufp++ = blkp[index++];
|
*bufp++ = blkp[index++];
|
}
|
}
|
blkno++;
|
blkno++;
|
size -= numBytes;
|
size -= numBytes;
|
}
|
}
|
if (size > 0) {
|
if (size > 0) {
|
index = 0;
|
index = 0;
|
numBytes = size;
|
numBytes = size;
|
readFileBlock(ip, blkno, blkp);
|
readFileBlock(ip, blkno, blkp);
|
for (i = 0; i < numBytes; i++) {
|
for (i = 0; i < numBytes; i++) {
|
*bufp++ = blkp[index++];
|
*bufp++ = blkp[index++];
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* inode handling */
|
/* inode handling */
|
|
|
|
|
unsigned int inodeBlock[BSIZE / sizeof(unsigned int)];
|
unsigned int inodeBlock[BSIZE / sizeof(unsigned int)];
|
Dinode *ibp = (Dinode *) &inodeBlock[0];
|
Dinode *ibp = (Dinode *) &inodeBlock[0];
|
|
|
|
|
Dinode *getInode(unsigned int inode) {
|
Dinode *getInode(unsigned int inode) {
|
unsigned int fnum;
|
unsigned int fnum;
|
unsigned int inum;
|
unsigned int inum;
|
Dinode *ip;
|
Dinode *ip;
|
|
|
fnum = ino_to_fsba(sbp, inode);
|
fnum = ino_to_fsba(sbp, inode);
|
inum = ino_to_fsbo(sbp, inode);
|
inum = ino_to_fsbo(sbp, inode);
|
if (debugGetInode) {
|
if (debugGetInode) {
|
printf("DEBUG: getting inode 0x%08X\n", inode);
|
printf("DEBUG: getting inode 0x%08X\n", inode);
|
printf("DEBUG: this is in fragment %d, inode %d\n", fnum, inum);
|
printf("DEBUG: this is in fragment %d, inode %d\n", fnum, inum);
|
}
|
}
|
readSectors(fnum * spf, spb, ibp);
|
readSectors(fnum * spf, spb, ibp);
|
ip = ibp + inum;
|
ip = ibp + inum;
|
if (ip->di_size[0] != 0) {
|
if (ip->di_size[0] != 0) {
|
halt("File too big");
|
halt("File too big");
|
}
|
}
|
if (debugGetInode) {
|
if (debugGetInode) {
|
printf("DEBUG: mode of file = 0x%04X\n", ip->di_mode);
|
printf("DEBUG: mode of file = 0x%04X\n", ip->di_mode);
|
printf("DEBUG: size of file = 0x%08X\n", ip->di_size[1]);
|
printf("DEBUG: size of file = 0x%08X\n", ip->di_size[1]);
|
}
|
}
|
return ip;
|
return ip;
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* convert path to inode */
|
/* convert path to inode */
|
|
|
|
|
unsigned int directoryBlock[BSIZE / sizeof(unsigned int)];
|
unsigned int directoryBlock[BSIZE / sizeof(unsigned int)];
|
Dirent *dbp = (Dirent *) &directoryBlock[0];
|
Dirent *dbp = (Dirent *) &directoryBlock[0];
|
|
|
|
|
Dinode *pathToInode(char *path) {
|
Dinode *pathToInode(char *path) {
|
Dinode *ip;
|
Dinode *ip;
|
char c;
|
char c;
|
char dirBuffer[FFS_MAXNAMLEN];
|
char dirBuffer[FFS_MAXNAMLEN];
|
char *cp;
|
char *cp;
|
unsigned int offset;
|
unsigned int offset;
|
Dirent *dp;
|
Dirent *dp;
|
unsigned int ino;
|
unsigned int ino;
|
unsigned int len;
|
unsigned int len;
|
|
|
/* get root inode */
|
/* get root inode */
|
ip = getInode(ROOTINO);
|
ip = getInode(ROOTINO);
|
/* traverse file system tree while matching path components */
|
/* traverse file system tree while matching path components */
|
c = *path++;
|
c = *path++;
|
while (1) {
|
while (1) {
|
/* skip leading slashes in path component */
|
/* skip leading slashes in path component */
|
while (c == '/') {
|
while (c == '/') {
|
c = *path++;
|
c = *path++;
|
}
|
}
|
if (c == '\0') {
|
if (c == '\0') {
|
/* no more path components */
|
/* no more path components */
|
break;
|
break;
|
}
|
}
|
/* if there is another component, gather up its name */
|
/* if there is another component, gather up its name */
|
cp = dirBuffer;
|
cp = dirBuffer;
|
while (c != '/' && c != '\0') {
|
while (c != '/' && c != '\0') {
|
if (cp < &dirBuffer[FFS_MAXNAMLEN]) {
|
if (cp < &dirBuffer[FFS_MAXNAMLEN]) {
|
*cp++ = c;
|
*cp++ = c;
|
}
|
}
|
c = *path++;
|
c = *path++;
|
}
|
}
|
*cp++ = '\0';
|
*cp++ = '\0';
|
/* ip must be a directory */
|
/* ip must be a directory */
|
if ((ip->di_mode & IFMT) != IFDIR) {
|
if ((ip->di_mode & IFMT) != IFDIR) {
|
return NULL;
|
return NULL;
|
}
|
}
|
if (debugSearchDir) {
|
if (debugSearchDir) {
|
printf("DEBUG: this is a directory, ok\n");
|
printf("DEBUG: this is a directory, ok\n");
|
printf("DEBUG: path component to search for = '%s'\n", dirBuffer);
|
printf("DEBUG: path component to search for = '%s'\n", dirBuffer);
|
}
|
}
|
/* search directory */
|
/* search directory */
|
offset = 0;
|
offset = 0;
|
while (1) {
|
while (1) {
|
if (offset >= ip->di_size[1]) {
|
if (offset >= ip->di_size[1]) {
|
/* component not found */
|
/* component not found */
|
return NULL;
|
return NULL;
|
}
|
}
|
if ((offset & BMASK) == 0) {
|
if ((offset & BMASK) == 0) {
|
/* read the next directory block */
|
/* read the next directory block */
|
readFileBlock(ip, offset >> BSHIFT, dbp);
|
readFileBlock(ip, offset >> BSHIFT, dbp);
|
dp = dbp;
|
dp = dbp;
|
}
|
}
|
ino = dp->d_fileno;
|
ino = dp->d_fileno;
|
len = dp->d_reclen;
|
len = dp->d_reclen;
|
if (debugSearchDir) {
|
if (debugSearchDir) {
|
printf("DEBUG: ino = %4d, len = %4d, ", ino, len);
|
printf("DEBUG: ino = %4d, len = %4d, ", ino, len);
|
printf("dirsiz = %4d, name = %s\n", DIRSIZ(0, dp, 0), dp->d_name);
|
printf("dirsiz = %4d, name = %s\n", DIRSIZ(0, dp, 0), dp->d_name);
|
}
|
}
|
if (ino != 0) {
|
if (ino != 0) {
|
if (strcmp(dirBuffer, dp->d_name) == 0) {
|
if (strcmp(dirBuffer, dp->d_name) == 0) {
|
/* component found */
|
/* component found */
|
break;
|
break;
|
}
|
}
|
}
|
}
|
/* no match, try next entry */
|
/* no match, try next entry */
|
dp = (Dirent *) ((unsigned char *) dp + len);
|
dp = (Dirent *) ((unsigned char *) dp + len);
|
offset += len;
|
offset += len;
|
}
|
}
|
/* get corresponding inode */
|
/* get corresponding inode */
|
ip = getInode(ino);
|
ip = getInode(ino);
|
/* look for more components */
|
/* look for more components */
|
}
|
}
|
return ip;
|
return ip;
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* load an ELF executable */
|
/* load an ELF executable */
|
|
|
|
|
#define MAX_PHDR_SIZE 100
|
#define MAX_PHDR_SIZE 100
|
|
|
|
|
Bool loadElf(Dinode *ip, unsigned int *entryPointPtr) {
|
Bool loadElf(Dinode *ip, unsigned int *entryPointPtr) {
|
Elf32_Ehdr fileHeader;
|
Elf32_Ehdr fileHeader;
|
Elf32_Addr entry;
|
Elf32_Addr entry;
|
Elf32_Off phoff;
|
Elf32_Off phoff;
|
Elf32_Half phentsize;
|
Elf32_Half phentsize;
|
Elf32_Half phnum;
|
Elf32_Half phnum;
|
int i;
|
int i;
|
unsigned int phdrBuf[MAX_PHDR_SIZE / sizeof(unsigned int)];
|
unsigned int phdrBuf[MAX_PHDR_SIZE / sizeof(unsigned int)];
|
Elf32_Phdr *phdrPtr;
|
Elf32_Phdr *phdrPtr;
|
Elf32_Word ptype;
|
Elf32_Word ptype;
|
Elf32_Off offset;
|
Elf32_Off offset;
|
Elf32_Addr address;
|
Elf32_Addr address;
|
Elf32_Word filesize;
|
Elf32_Word filesize;
|
Elf32_Word memsize;
|
Elf32_Word memsize;
|
Elf32_Word flags;
|
Elf32_Word flags;
|
Elf32_Word align;
|
Elf32_Word align;
|
unsigned char *memPtr;
|
unsigned char *memPtr;
|
int j;
|
int j;
|
|
|
readFile(ip, 0, sizeof(Elf32_Ehdr), &fileHeader);
|
readFile(ip, 0, sizeof(Elf32_Ehdr), &fileHeader);
|
if (fileHeader.e_ident[EI_MAG0] != ELFMAG0 ||
|
if (fileHeader.e_ident[EI_MAG0] != ELFMAG0 ||
|
fileHeader.e_ident[EI_MAG1] != ELFMAG1 ||
|
fileHeader.e_ident[EI_MAG1] != ELFMAG1 ||
|
fileHeader.e_ident[EI_MAG2] != ELFMAG2 ||
|
fileHeader.e_ident[EI_MAG2] != ELFMAG2 ||
|
fileHeader.e_ident[EI_MAG3] != ELFMAG3 ||
|
fileHeader.e_ident[EI_MAG3] != ELFMAG3 ||
|
fileHeader.e_ident[EI_CLASS] != ELFCLASS32 ||
|
fileHeader.e_ident[EI_CLASS] != ELFCLASS32 ||
|
fileHeader.e_ident[EI_DATA] != ELFDATA2MSB ||
|
fileHeader.e_ident[EI_DATA] != ELFDATA2MSB ||
|
fileHeader.e_type != ET_EXEC ||
|
fileHeader.e_type != ET_EXEC ||
|
fileHeader.e_machine != EM_ECO32) {
|
fileHeader.e_machine != EM_ECO32) {
|
/* file is not in ECO32-ELF executable format */
|
/* file is not in ECO32-ELF executable format */
|
return FALSE;
|
return FALSE;
|
}
|
}
|
entry = fileHeader.e_entry;
|
entry = fileHeader.e_entry;
|
phoff = fileHeader.e_phoff;
|
phoff = fileHeader.e_phoff;
|
phentsize = fileHeader.e_phentsize;
|
phentsize = fileHeader.e_phentsize;
|
phnum = fileHeader.e_phnum;
|
phnum = fileHeader.e_phnum;
|
if (debugLoadElf) {
|
if (debugLoadElf) {
|
printf("DEBUG: entry point (virtual addr) : 0x%08X\n", entry);
|
printf("DEBUG: entry point (virtual addr) : 0x%08X\n", entry);
|
printf("DEBUG: program header table at : %d\n", phoff);
|
printf("DEBUG: program header table at : %d\n", phoff);
|
printf("DEBUG: prog hdr tbl entry size : %d\n", phentsize);
|
printf("DEBUG: prog hdr tbl entry size : %d\n", phentsize);
|
printf("DEBUG: num prog hdr tbl entries : %d\n", phnum);
|
printf("DEBUG: num prog hdr tbl entries : %d\n", phnum);
|
}
|
}
|
for (i = 0 ; i < phnum; i++) {
|
for (i = 0 ; i < phnum; i++) {
|
printf("Processing program header %d\n", i);
|
printf("Processing program header %d\n", i);
|
readFile(ip, phoff + i * phentsize, phentsize, phdrBuf);
|
readFile(ip, phoff + i * phentsize, phentsize, phdrBuf);
|
phdrPtr = (Elf32_Phdr *) phdrBuf;
|
phdrPtr = (Elf32_Phdr *) phdrBuf;
|
ptype = phdrPtr->p_type;
|
ptype = phdrPtr->p_type;
|
if (ptype != PT_LOAD) {
|
if (ptype != PT_LOAD) {
|
printf(" type is %u, ignored\n", ptype);
|
printf(" type is %u, ignored\n", ptype);
|
continue;
|
continue;
|
}
|
}
|
offset = phdrPtr->p_offset;
|
offset = phdrPtr->p_offset;
|
address = phdrPtr->p_vaddr;
|
address = phdrPtr->p_vaddr;
|
filesize = phdrPtr->p_filesz;
|
filesize = phdrPtr->p_filesz;
|
memsize = phdrPtr->p_memsz;
|
memsize = phdrPtr->p_memsz;
|
flags = phdrPtr->p_flags;
|
flags = phdrPtr->p_flags;
|
align = phdrPtr->p_align;
|
align = phdrPtr->p_align;
|
if (debugLoadElf) {
|
if (debugLoadElf) {
|
printf("DEBUG: offset : 0x%08X bytes\n", offset);
|
printf("DEBUG: offset : 0x%08X bytes\n", offset);
|
printf("DEBUG: address : 0x%08X\n", address);
|
printf("DEBUG: address : 0x%08X\n", address);
|
printf("DEBUG: filesize : 0x%08X bytes\n", filesize);
|
printf("DEBUG: filesize : 0x%08X bytes\n", filesize);
|
printf("DEBUG: memsize : 0x%08X bytes\n", memsize);
|
printf("DEBUG: memsize : 0x%08X bytes\n", memsize);
|
printf("DEBUG: flags : 0x%08X\n", flags);
|
printf("DEBUG: flags : 0x%08X\n", flags);
|
printf("DEBUG: align : 0x%08X\n", align);
|
printf("DEBUG: align : 0x%08X\n", align);
|
}
|
}
|
memPtr = (unsigned char *) address;
|
memPtr = (unsigned char *) address;
|
readFile(ip, offset, filesize, memPtr);
|
readFile(ip, offset, filesize, memPtr);
|
for (j = filesize; j < memsize; j++) {
|
for (j = filesize; j < memsize; j++) {
|
memPtr[j] = 0;
|
memPtr[j] = 0;
|
}
|
}
|
printf(" segment of %u bytes read", filesize);
|
printf(" segment of %u bytes read", filesize);
|
printf(" (+ %u bytes zeroed)", memsize - filesize);
|
printf(" (+ %u bytes zeroed)", memsize - filesize);
|
printf(", vaddr = 0x%08X\n", address);
|
printf(", vaddr = 0x%08X\n", address);
|
}
|
}
|
*entryPointPtr = entry;
|
*entryPointPtr = entry;
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* main program */
|
/* main program */
|
|
|
|
|
unsigned int entryPoint; /* where to continue from main() */
|
unsigned int entryPoint; /* where to continue from main() */
|
|
|
|
|
int main(void) {
|
int main(void) {
|
char line[MAX_LINE];
|
char line[MAX_LINE];
|
Dinode *ip;
|
Dinode *ip;
|
|
|
printf("\n");
|
printf("\n");
|
printf("NetBSD system loader\n");
|
printf("NetBSD system loader\n");
|
readDiskLabel();
|
readDiskLabel();
|
readSuperBlock();
|
readSuperBlock();
|
strcpy(line, DFLT_KERNEL);
|
strcpy(line, DFLT_KERNEL);
|
while (1) {
|
while (1) {
|
getLine("\nPlease enter path to kernel: ", line, MAX_LINE);
|
getLine("\nPlease enter path to kernel: ", line, MAX_LINE);
|
ip = pathToInode(line);
|
ip = pathToInode(line);
|
if (ip == NULL) {
|
if (ip == NULL) {
|
printf("'%s' not found\n", line);
|
printf("'%s' not found\n", line);
|
continue;
|
continue;
|
}
|
}
|
if ((ip->di_mode & IFMT) != IFREG) {
|
if ((ip->di_mode & IFMT) != IFREG) {
|
printf("'%s' is not a regular file\n", line);
|
printf("'%s' is not a regular file\n", line);
|
continue;
|
continue;
|
}
|
}
|
printf("Loading '%s'...\n", line);
|
printf("Loading '%s'...\n", line);
|
if (!loadElf(ip, &entryPoint)) {
|
if (!loadElf(ip, &entryPoint)) {
|
printf("'%s' cannot be loaded\n", line);
|
printf("'%s' cannot be loaded\n", line);
|
continue;
|
continue;
|
}
|
}
|
/* kernel successfully loaded */
|
/* kernel successfully loaded */
|
break;
|
break;
|
}
|
}
|
printf("Starting '%s' at address 0x%08X...\n", line, entryPoint);
|
printf("Starting '%s' at address 0x%08X...\n", line, entryPoint);
|
return 0;
|
return 0;
|
}
|
}
|
|
|