⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 boot.c

📁 操作系统引导监控程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	boot 2.5.0 - Load and start Minix.		Author: Kees J. Bot
 *								27 Dec 1991
 *
 * Copyright 1996 Kees J. Bot, All rights reserved.
 * This package may be freely used and modified except that changes that
 * do not increase the functionality or that are incompatible with the
 * original may not be released to the public without permission from the
 * author.  Use of so called "C beautifiers" is explicitly prohibited.
 */

char version[]=		"2.5";

#define nil 0
#define _POSIX_SOURCE	1
#define _MINIX		1
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <a.out.h>
#include <minix/config.h>
#include <minix/const.h>
#include <minix/type.h>
#include <minix/minlib.h>
#include <kernel/const.h>
#include <kernel/type.h>
#include <ibm/partition.h>
#include "rawfs.h"
#undef EXTERN
#define EXTERN	/* Empty */
#include "boot.h"

#define arraysize(a)		(sizeof(a) / sizeof((a)[0]))
#define arraylimit(a)		((a) + arraysize(a))
#define between(a, c, z)	((unsigned) ((c) - (a)) <= ((z) - (a)))

void printk(char *fmt, ...);
#define	printf	printk

char *bios_err(int err)
/* Translate BIOS error code to a readable string.  (This is a rare trait
 * known as error checking and reporting.  Take a good look at it, you won't
 * see it often.)
 */
{
	static struct errlist {
		short	err;
		char	*what;
	} errlist[] = {
#if !DOS
		{ 0x00, "No error" },
		{ 0x01, "Invalid command" },
		{ 0x02, "Address mark not found" },
		{ 0x03, "Disk write-protected" },
		{ 0x04, "Sector not found" },
		{ 0x05, "Reset failed" },
		{ 0x06, "Floppy disk removed" },
		{ 0x07, "Bad parameter table" },
		{ 0x08, "DMA overrun" },
		{ 0x09, "DMA crossed 64 KB boundary" },
		{ 0x0A, "Bad sector flag" },
		{ 0x0B, "Bad track flag" },
		{ 0x0C, "Media type not found" },
		{ 0x0D, "Invalid number of sectors on format" },
		{ 0x0E, "Control data address mark detected" },
		{ 0x0F, "DMA arbitration level out of range" },
		{ 0x10, "Uncorrectable CRC or ECC data error" },
		{ 0x11, "ECC corrected data error" },
		{ 0x20, "Controller failed" },
		{ 0x40, "Seek failed" },
		{ 0x80, "Disk timed-out" },
		{ 0xAA, "Drive not ready" },
		{ 0xBB, "Undefined error" },
		{ 0xCC, "Write fault" },
		{ 0xE0, "Status register error" },
		{ 0xFF, "Sense operation failed" }
#else /* DOS */
		{ 0x00, "No error" },
		{ 0x01, "Function number invalid" },
		{ 0x02, "File not found" },
		{ 0x03, "Path not found" },
		{ 0x04, "Too many open files" },
		{ 0x05, "I/O error" },
		{ 0x06, "Invalid handle" },
		{ 0x0C, "Access code invalid" },
#endif /* DOS */
	};
	struct errlist *errp;

	for (errp= errlist; errp < arraylimit(errlist); errp++) {
		if (errp->err == err) return errp->what;
	}
	return "Unknown error";
}

char *unix_err(int err)
/* Translate the few errors rawfs can give. */
{
	switch (err) {
	case ENOENT:	return "No such file or directory";
	case ENOTDIR:	return "Not a directory";
	default:	return "Unknown error";
	}
}

void rwerr(char *rw, off_t sec, int err)
{
	printf("\n%s error 0x%02x (%s) at sector %ld absolute\n",
		rw, err, bios_err(err), sec);
}

void readerr(off_t sec, int err)	{ rwerr("Read", sec, err); }
void writerr(off_t sec, int err)	{ rwerr("Write", sec, err); }

/* Readblock support for rawfs.c */

#define CACHE_SIZE	32	/* More than enough. */

struct cache_entry {
	u32_t	block;
	u32_t	addr;
} cache[CACHE_SIZE];

#if !DOS
int cache_live= 0;

void init_cache(void)
/* Initialize the block cache. */
{
	struct cache_entry *pc;
	u32_t addr= FREEPOS;

	for (pc= cache; pc < arraylimit(cache); pc++) {
		pc->block= -1;
		pc->addr= addr;
		addr+= BLOCK_SIZE;
	}

	cache_live= 1;	/* Turn it on. */
}

void invalidate_cache(void)
/* The cache can't be used when Minix is loaded. */
{
	cache_live= 0;
}

#else /* DOS */
/* We can't fool around with random memory under DOS. */
#define cache_live 0
void init_cache(void) {}
void invalidate_cache(void) {}
#endif /* DOS */

void readblock(off_t blk, char *buf)
/* Read blocks for the rawfs package with caching.  Wins 2 seconds. */
{
	int r= 0;
	u32_t sec= lowsec + blk * RATIO;

	if (!cache_live) {
		/* Cache invalidated, load block directly in place. */
		r= readsectors(mon2abs(buf), sec, 1 * RATIO);
	} else {
		/* Search through the cache from 0 up.  Move the one found
		 * to the front of the cache, then optionally read a block.
		 */
		struct cache_entry *pc, lifo, tmp;

		for (pc= cache; pc < arraylimit(cache); pc++) {
			tmp= *pc;
			*pc= lifo;
			lifo= tmp;
			if (lifo.block == blk) break;
		}
		cache[0]= lifo;

		if (cache[0].block != blk) {
			r= readsectors(cache[0].addr, sec, 1 * RATIO);
			cache[0].block= blk;
		}
		raw_copy(mon2abs(buf), cache[0].addr, BLOCK_SIZE);
	}
	if (r != 0) { readerr(sec, r); exit(1); }
}

char *readline(void)
/* Read a line including a newline with echoing. */
{
	char *line;
	size_t i, z;
	int c;

	i= 0;
	z= 20;
	line= malloc(z * sizeof(char));

	do {
		c= getchar();

		if (strchr("\b\177\25\30", c) != nil) {
			/* Backspace, DEL, ctrl-U, or ctrl-X. */
			do {
				if (i == 0) break;
				printf("\b \b");
				i--;
			} while (c == '\25' || c == '\30');
		} else
		if (c < ' ' && c != '\n') {
			putchar('\7');
		} else {
			putchar(c);
			line[i++]= c;
			if (i == z) {
				z*= 2;
				line= realloc(line, z * sizeof(char));
			}
		}
	} while (c != '\n');
	line[i]= 0;
	return line;
}

int sugar(char *tok)
/* Recognize special tokens. */
{
	return strchr("=(){};\n", tok[0]) != nil;
}

char *onetoken(char **aline, int arg)
/* Returns a string with one token for tokenize.  Arg is true when reading
 * between ( and ).
 */
{
	char *line= *aline;
	size_t n;
	char *tok;

	/* Skip spaces and runs of newlines. */
	while (*line == ' ' || (*line == '\n' && line[1] == '\n')) line++;

	*aline= line;

	/* Don't do odd junk (nor the terminating 0!). */
	if ((unsigned) *line < ' ' && *line != '\n') return nil;

	if (arg) {
		/* Function argument, anything goes except ). */
		int depth= 0;

		while ((unsigned) *line >= ' ') {
			if (*line == '(') depth++;
			if (*line == ')' && --depth < 0) break;
			line++;
		}
		while (line > *aline && line[-1] == ' ') line--;
	} else
	if (sugar(line)) {
		/* Single character token. */
		line++;
	} else {
		/* Multicharacter token. */
		do line++; while ((unsigned) *line > ' ' && !sugar(line));
	}
	n= line - *aline;
	tok= malloc((n + 1) * sizeof(char));
	memcpy(tok, *aline, n);
	tok[n]= 0;
	if (tok[0] == '\n') tok[0]= ';';	/* ';' same as '\n' */

	*aline= line;
	return tok;
}

/* Typed commands form strings of tokens. */

typedef struct token {
	struct token	*next;	/* Next in a command chain. */
	char		*token;
} token;

token **tokenize(token **acmds, char *line, int *fundef)
/* Takes a line apart to form tokens.  The tokens are inserted into a command
 * chain at *acmds.  Tokenize returns a reference to where another line could
 * be added.  The fundef variable holds the state tokenize is in when decoding
 * a multiline function definition.  It is nonzero when more must be read.
 * Tokenize looks at spaces as token separators, and recognizes only
 * ';', '=', '(', ')' '{', '}', and '\n' as single character tokens.
 */
{
	int fd= *fundef;
	char *tok;
	token *newcmd;
	static char funsugar[]= { '(', 0, ')', '{', '}' };

	while ((tok= onetoken(&line, fd == 1)) != nil) {
		if (fd == 1) {
			fd++;	/* Function argument. */
		} else
		if (funsugar[fd] == tok[0]) {
			/* Recognize next token as part of a function def. */
			fd= tok[0] == '}' ? 0 : fd + 1;
		} else
		if (fd != 0) {
			if (tok[0] == ';' && fd == 3) {
				/* Kill separator between ')' and '{'. */
				free(tok);
				continue;
			}
			/* Syntax error unless between '{' and '}'. */
			if (fd != 4) fd= 0;
		}
		newcmd= malloc(sizeof(*newcmd));
		newcmd->token= tok;
		newcmd->next= *acmds;
		*acmds= newcmd;
		acmds= &newcmd->next;
	}
	*fundef= fd;
	return acmds;
}

token *cmds;		/* String of commands to execute. */
int err;		/* Set on an error. */

char *poptoken(void)
/* Pop one token off the command chain. */
{
	token *cmd= cmds;
	char *tok= cmd->token;

	cmds= cmd->next;
	free(cmd);

	return tok;
}

void voidtoken(void)
/* Remove one token from the command chain. */
{
	free(poptoken());
}

void interrupt(void)
/* Clean up after an ESC has been typed. */
{
	printf("[ESC]\n");
	while (peekchar() == ESC) (void) getchar();
	err= 1;
}

int activate;

struct biosdev {
	char name[6];
	int device, primary, secondary;
} bootdev, tmpdev;

struct part_entry boot_part;
char dskpars[DSKPARSIZE]=	/* 360K floppy disk parameters (for now). */
	{ 0xDF, 0x02, 25, 2,  9, 0x2A, 0xFF, 0x50, 0xF6, 15, 8 };

void migrate(void)
/* Copy the boot program to the far end of memory, this must be done asap to
 * put the data area cleanly inside a 64K chunk (no DMA problems).
 */
{
	u32_t oldaddr= caddr;
	u32_t memsize= get_memsize() * 1024L;
	u32_t newaddr= memsize - runsize;
#if !DOS
	u32_t dma64k= (memsize - 1) & ~0xFFFFL;
	vector dskbase;

	/* Check if data segment crosses a 64k boundary. */
	if (newaddr + (daddr - caddr) < dma64k) newaddr= dma64k - runsize;

	/* Get some variables into my address space before they get mashed. */
	if (device < 0x80) {
		/* Floppy disk parameters. */
		raw_copy(mon2abs(&dskbase), DSKBASE * sizeof(vector),
							sizeof(vector));
		raw_copy(mon2abs(dskpars), vec2abs(&dskbase),
							DSKPARSIZE);
	} else {
		/* Hard disk partition table entry into boot_part. */
		raw_copy(mon2abs(&boot_part), vec2abs(&rem_part),
							sizeof(boot_part));
	}
#endif /* !DOS */

	/* Set the new caddr for relocate. */
	caddr= newaddr;

	/* Copy code and data. */
	raw_copy(newaddr, oldaddr, runsize);

	relocate();	/* Make the copy running. */

#if !DOS
	/* Set the parameters for the boot device using global variables
	 * device and dskpars.  (This particular call should not fail.)
	 */
	(void) dev_geometry();
#endif /* !DOS */
}

int get_master(char *master, struct part_entry **table, u32_t pos)
/* Read a master boot sector and its partition table. */
{
	int r, n;
	struct part_entry *pe, **pt;

	if ((r= readsectors(mon2abs(master), pos, 1)) != 0) return r;

	pe= (struct part_entry *) (master + PART_TABLE_OFF);
	for (pt= table; pt < table + NR_PARTITIONS; pt++) *pt= pe++;

	/* DOS has the misguided idea that partition tables must be sorted. */
	if (pos != 0) return 0;		/* But only the primary. */

	n= NR_PARTITIONS;
	do {
		for (pt= table; pt < table + NR_PARTITIONS-1; pt++) {
			if (pt[0]->sysind == NO_PART
				|| (pt[0]->lowsec > pt[1]->lowsec
						&& pt[1]->sysind != NO_PART)) {
				pe= pt[0]; pt[0]= pt[1]; pt[1]= pe;
			}
		}
	} while (--n > 0);
	return 0;
}

void initialize(void)
{
	char master[SECTOR_SIZE];
	struct part_entry *table[NR_PARTITIONS];
	int r, p;
	u32_t masterpos;
	static char sub[]= "a";

#if !DOS
	/* Find out what the boot device and partition was. */
	bootdev.name[0]= 0;
	bootdev.device= device;
	bootdev.primary= -1;
	bootdev.secondary= -1;

	if (device < 0x80) {
		/* Floppy. */
		strcpy(bootdev.name, "fd");
		strcat(bootdev.name, u2a(bootdev.device));
		return;
	}

	/* Get the partition table from the very first sector, and determine
	 * the partition we booted from.  Migrate() was so nice to put the
	 * partition table entry of the booted partition in boot_part.
	 */

	/* The only thing really needed from the booted partition: */
	lowsec= boot_part.lowsec;

	masterpos= 0;	/* Master bootsector position. */

	for (;;) {
		/* Extract the partition table from the master boot sector. */
		if ((r= get_master(master, table, masterpos)) != 0) {
			readerr(masterpos, r); exit(1);
		}

		/* See if you can find "lowsec" back. */
		for (p= 0; p < NR_PARTITIONS; p++) {
			if (lowsec - table[p]->lowsec < table[p]->size) break;
		}

		if (lowsec == table[p]->lowsec) {	/* Found! */
			if (bootdev.primary < 0)
				bootdev.primary= p;
			else
				bootdev.secondary= p;
			break;
		}

		if (p == NR_PARTITIONS || bootdev.primary >= 0) {
			/* The boot partition cannot be named, this only means
			 * that "bootdev" doesn't work.
			 */
			bootdev.device= -1;
			return;
		}

		/* See if the primary partition is subpartitioned. */
		bootdev.primary= p;
		masterpos= table[p]->lowsec;
	}
	strcpy(bootdev.name, "hd");
	strcat(bootdev.name, u2a((device - 0x80) * (1 + NR_PARTITIONS)
						+ 1 + bootdev.primary));
	sub[0]= 'a' + bootdev.secondary;
	if (bootdev.secondary >= 0) strcat(bootdev.name, sub);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -