📄 boot.c
字号:
/* boot 1.5.4 - Load and start Minix. Author: Kees J. Bot */char version[]= "1.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/partition.h>#include <minix/boot.h>#include <minix/type.h>#include <kernel/const.h>#include <kernel/type.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 printf printkchar *bios_err(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 { unsigned char err; char *what; } errlist[] = { { 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" } }; struct errlist *errp; for (errp= errlist; errp < arraylimit(errlist); errp++) if (errp->err == err) return errp->what; return "Unknown error";}char *unix_err(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(rw, sec, err) 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(sec, err) off_t sec; int err; { rwerr("Read", sec, err); }void writerr(sec, err) off_t sec; int err; { rwerr("Write", sec, err); }/* Readblock support for rawfs.c */#define CACHE_SIZE 32 /* More than enough. */int cache_live= 0;struct cache_entry { u32_t block; u16_t seg;} cache[CACHE_SIZE];void init_cache()/* Initialize the block cache. */{ struct cache_entry *pc; u16_t seg= FREESEG; for (pc= cache; pc < arraylimit(cache); pc++) { pc->block= -1; pc->seg= seg; seg+= BLOCK_SIZE/HCLICK_SIZE; } cache_live= 1; /* Turn it on. */}void invalidate_cache()/* The cache can't be used when Minix is loaded. */{ cache_live= 0;}void readblock(blk, buf) 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((u16_t) buf, dseg, 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(0, cache[0].seg, sec, 1 * RATIO); cache[0].block= blk; } raw_copy((u16_t) buf, dseg, 0, cache[0].seg, BLOCK_SIZE); } if (r != 0) { readerr(sec, r); reboot(); }}char *readline()/* Read a line including a newline with echoing. */{ char *line; size_t i= 0, z; int c; line= (char *) malloc((z= 20) * 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) line= (char *) realloc((void *) line, (z*= 2) * sizeof(char)); } } while (c != '\n'); line[i]= 0; return line;}int sugar(tok) char *tok;/* Recognize special tokens. */{ return strchr("=(){};\n", tok[0]) != nil;}char *onetoken(aline, arg) 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. */ while (*line == ' ') 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= (char *) malloc((n + 1) * sizeof(char)); memcpy((void *) tok, (void *) *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(acmds, line, fundef) token **acmds; /* Splice tokenized line into this list. */ char *line; /* Characters to be tokenized. */ int *fundef; /* Keeps state when forming a function def. *//* 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((void *) tok); continue; } /* Syntax error unless between '{' and '}'. */ if (fd != 4) fd= 0; } newcmd= (token *) 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. */char *poptoken()/* Pop one token off the command chain. */{ token *cmd= cmds; char *tok= cmd->token; cmds= cmd->next; free((void *) cmd); return tok;}void voidtoken()/* Remove one token from the command chain. */{ free((void *) poptoken());}void void_cmds()/* Void the whole list. */{ while (cmds != nil) voidtoken();}void interrupt()/* Clean up after an ESC has been typed. */{ printf("[ESC]\n"); while (peekchar() == ESC) (void) getchar(); /* Delete leftover commands. */ void_cmds();}struct biosdev { int device, primary, secondary;} bootdev, tmpdev;int activate;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()/* Copy 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). */{ u16_t oldseg= cseg; u16_t size= (runsize + HCLICK_SIZE - 1) >> HCLICK_SHIFT; u16_t memsize= get_low_memsize() * (1024 / HCLICK_SIZE); u16_t dma64k= (memsize - 1) & 0xF000; u16_t newseg= memsize - size; vector dskbase; /* Check if data segment crosses a 64k boundary. */ if (newseg + (dseg - cseg) < dma64k) newseg= dma64k - size; /* Get some variables into my address space before they get mashed. */ if (device < 0x80) { /* Floppy disk parameters. */ raw_copy((u16_t) &dskbase, dseg, (u16_t) (DSKBASE * sizeof(vector)), 0, sizeof(vector)); raw_copy((u16_t) dskpars, dseg, dskbase.offset, dskbase.segment, DSKPARSIZE); } else { /* Hard disk partition table entry into boot_part. */ raw_copy((u16_t) &boot_part, dseg, rem_part.offset, rem_part.segment, sizeof(boot_part)); } /* Set the new cseg for relocate. */ cseg= newseg; /* Copy code and data in large chunks. */ do { u16_t chunk= size < 0x0FFF ? size : 0x0FFF; raw_copy(0, newseg, 0, oldseg, chunk << HCLICK_SHIFT); oldseg+= chunk; newseg+= chunk; size-= chunk; } while (size > 0); relocate(); /* Make the copy running. */ /* Set the parameters for the boot device using global variables * device and dskpars. (This particular call should not fail.) */ (void) dev_geometry();}int get_master(master, table, pos) 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((u16_t) master, dseg, 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(){ char master[SECTOR_SIZE]; struct part_entry *table[NR_PARTITIONS]; int r, p; u32_t masterpos; /* Find out what the boot device and partition was. */ bootdev.device= device; bootdev.primary= -1; bootdev.secondary= -1; if (device < 0x80) 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); reboot(); } /* 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -