📄 boot.c
字号:
#else /* DOS */
/* Initialize under DOS: Open virtual disk to boot Minix from, grab
* extended memory, etc.
*/
char *argp, *vdisk;
/* Parse the command line. */
argp= PSP + 0x81;
argp[PSP[0x80]]= 0;
while (between('\1', *argp, ' ')) argp++;
vdisk= argp;
while (!between('\0', *argp, ' ')) argp++;
while (between('\1', *argp, ' ')) *argp++= 0;
if (*argp != 0 || *vdisk == 0) {
printf("\nUsage: boot <vdisk>\n");
exit(1);
}
if ((r= dos_open(vdisk)) != 0) {
printf("\n%s: Error %02x (%s)\n", vdisk, r, bios_err(r));
exit(1);
}
/* Find the active partition on the virtual disk. */
if ((r= get_master(master, table, 0)) != 0) {
readerr(0, r); exit(1);
}
strcpy(bootdev.name, "dosd0");
bootdev.primary= -1;
for (p= 0; p < NR_PARTITIONS; p++) {
if (table[p]->bootind != 0 && table[p]->sysind == MINIX_PART) {
bootdev.primary= p;
bootdev.name[4]= '1' + p;
lowsec= table[p]->lowsec;
break;
}
}
#endif /* DOS */
}
char null[]= ""; /* This kludge saves lots of memory. */
void sfree(char *s)
/* Free a non-null string. */
{
if (s != nil && s != null) free(s);
}
char *copystr(char *s)
/* Copy a non-null string using malloc. */
{
char *c;
if (*s == 0) return null;
c= malloc((strlen(s) + 1) * sizeof(char));
strcpy(c, s);
return c;
}
int is_default(environment *e)
{
return (e->flags & E_SPECIAL) && e->defval == nil;
}
environment **searchenv(char *name)
{
environment **aenv= &env;
while (*aenv != nil && strcmp((*aenv)->name, name) != 0) {
aenv= &(*aenv)->next;
}
return aenv;
}
#define b_getenv(name) (*searchenv(name))
/* Return the environment *structure* belonging to name, or nil if not found. */
char *b_value(char *name)
/* The value of a variable. */
{
environment *e= b_getenv(name);
return e == nil || !(e->flags & E_VAR) ? nil : e->value;
}
char *b_body(char *name)
/* The value of a function. */
{
environment *e= b_getenv(name);
return e == nil || !(e->flags & E_FUNCTION) ? nil : e->value;
}
int b_setenv(int flags, char *name, char *arg, char *value)
/* Change the value of an environment variable. Returns the flags of the
* variable if you are not allowed to change it, 0 otherwise.
*/
{
environment **aenv, *e;
if (*(aenv= searchenv(name)) == nil) {
e= malloc(sizeof(*e));
e->name= copystr(name);
e->flags= flags;
e->defval= nil;
e->next= nil;
*aenv= e;
} else {
e= *aenv;
/* Don't touch reserved names and don't change special
* variables to functions or vv.
*/
if (e->flags & E_RESERVED || (e->flags & E_SPECIAL
&& (e->flags & E_FUNCTION) != (flags & E_FUNCTION)
)) return e->flags;
e->flags= (e->flags & E_STICKY) | flags;
if (is_default(e)) {
e->defval= e->value;
} else {
sfree(e->value);
}
sfree(e->arg);
}
e->arg= copystr(arg);
e->value= copystr(value);
return 0;
}
int b_setvar(int flags, char *name, char *value)
/* Set variable or simple function. */
{
return b_setenv(flags, name, null, value);
}
void b_unset(char *name)
/* Remove a variable from the environment. A special variable is reset to
* its default value.
*/
{
environment **aenv, *e;
if ((e= *(aenv= searchenv(name))) == nil) return;
if (e->flags & E_SPECIAL) {
if (e->defval != nil) {
sfree(e->arg);
e->arg= null;
sfree(e->value);
e->value= e->defval;
e->defval= nil;
}
} else {
sfree(e->name);
sfree(e->arg);
sfree(e->value);
*aenv= e->next;
free(e);
}
}
long a2l(char *a)
/* Cheap atol(). */
{
int sign= 1;
long n= 0;
if (*a == '-') { sign= -1; a++; }
while (between('0', *a, '9')) n= n * 10 + (*a++ - '0');
return sign * n;
}
char *ul2a(u32_t n)
/* Transform a long number to ascii digits. */
{
static char num[3 * sizeof(n)];
char *a= arraylimit(num) - 1;
do *--a = (n % 10) + '0'; while ((n/= 10) > 0);
return a;
}
char *u2a(U16_t n)
/* Transform a short number to ascii digits. */
{
return ul2a(n);
}
unsigned a2x(char *a)
/* Ascii to hex. */
{
unsigned n= 0;
int c;
for (;;) {
c= *a;
if (between('0', c, '9')) c= c - '0' + 0x0;
else
if (between('A', c, 'F')) c= c - 'A' + 0xA;
else
if (between('a', c, 'f')) c= c - 'a' + 0xa;
else
break;
n= (n<<4) | c;
a++;
}
return n;
}
void get_parameters(void)
{
char params[SECTOR_SIZE + 1];
token **acmds;
int r, fundef= 0;
static char bus_type[][4] = {
"xt", "at", "mca"
};
static char vid_type[][4] = {
"mda", "cga", "ega", "ega", "vga", "vga"
};
static char vid_chrome[][6] = {
"mono", "color"
};
/* Variables that Minix needs: */
b_setvar(E_SPECIAL|E_VAR|E_DEV, "rootdev", "ram");
b_setvar(E_SPECIAL|E_VAR|E_DEV, "ramimagedev", "bootdev");
b_setvar(E_SPECIAL|E_VAR, "ramsize", "0");
b_setvar(E_SPECIAL|E_VAR, "processor", u2a(getprocessor()));
b_setvar(E_SPECIAL|E_VAR, "bus", bus_type[get_bus()]);
b_setvar(E_SPECIAL|E_VAR, "memsize", u2a(get_memsize()));
b_setvar(E_SPECIAL|E_VAR, "emssize", ul2a(get_ext_memsize()));
b_setvar(E_SPECIAL|E_VAR, "video", vid_type[get_video()]);
b_setvar(E_SPECIAL|E_VAR, "chrome", vid_chrome[get_video() & 1]);
/* Variables boot needs: */
b_setvar(E_SPECIAL|E_VAR, "image", "minix");
b_setvar(E_SPECIAL|E_FUNCTION, "main", "menu");
/* Default menu function: */
b_setenv(E_RESERVED|E_FUNCTION, "\1", "=,Start Minix", "boot");
/* Reserved names: */
b_setvar(E_RESERVED, "boot", null);
b_setvar(E_RESERVED, "menu", null);
b_setvar(E_RESERVED, "set", null);
b_setvar(E_RESERVED, "unset", null);
b_setvar(E_RESERVED, "save", null);
b_setvar(E_RESERVED, "ls", null);
b_setvar(E_RESERVED, "echo", null);
b_setvar(E_RESERVED, "trap", null);
b_setvar(E_RESERVED, "help", null);
b_setvar(E_RESERVED, "exit", null);
/* Tokenize bootparams sector. */
if ((r= readsectors(mon2abs(params), lowsec+PARAMSEC, 1)) != 0) {
readerr(lowsec+PARAMSEC, r);
exit(1);
}
params[SECTOR_SIZE]= 0;
acmds= tokenize(&cmds, params, &fundef);
/* Stuff the default action into the command chain. */
(void) tokenize(acmds, ":;main", &fundef);
}
void remote_code(void)
/* A rebooting Minix returns a bit of code for the monitor. */
{
if (reboot_code != 0) {
char code[SECTOR_SIZE + 2];
int fundef= 0;
raw_copy(mon2abs(code), reboot_code, SECTOR_SIZE);
code[SECTOR_SIZE]= 0;
strcat(code, ";");
(void) tokenize(&cmds, code, &fundef);
reboot_code= 0;
}
}
char *addptr;
void addparm(char *n)
{
while (*n != 0 && *addptr != 0) *addptr++ = *n++;
}
void save_parameters(void)
/* Save nondefault environment variables to the bootparams sector. */
{
environment *e;
char params[SECTOR_SIZE + 1];
int r;
/* Default filling: */
memset(params, '\n', SECTOR_SIZE);
/* Don't touch the 0! */
params[SECTOR_SIZE]= 0;
addptr= params;
for (e= env; e != nil; e= e->next) {
if (e->flags & E_RESERVED || is_default(e)) continue;
addparm(e->name);
if (e->flags & E_FUNCTION) {
addparm("(");
addparm(e->arg);
addparm("){");
} else {
addparm((e->flags & (E_DEV|E_SPECIAL)) != E_DEV
? "=" : "=d ");
}
addparm(e->value);
if (e->flags & E_FUNCTION) addparm("}");
if (*addptr == 0) {
printf("The environment is too big\n");
return;
}
*addptr++= '\n';
}
/* Save the parameters on disk. */
if ((r= writesectors(mon2abs(params), lowsec+PARAMSEC, 1)) != 0) {
writerr(lowsec+PARAMSEC, r);
printf("Can't save environment\n");
}
}
void show_env(void)
/* Show the environment settings. */
{
environment *e;
for (e= env; e != nil; e= e->next) {
if (e->flags & E_RESERVED) continue;
if (e->flags & E_FUNCTION) {
printf("%s(%s) {%s}\n", e->name, e->arg, e->value);
} else {
printf(is_default(e) ? "%s = (%s)\n" : "%s = %s\n",
e->name, e->value);
}
}
}
int numprefix(char *s, char **ps)
/* True iff s is a string of digits. *ps will be set to the first nondigit
* if non-nil, otherwise the string should end.
*/
{
char *n= s;
while (between('0', *n, '9')) n++;
if (n == s) return 0;
if (ps == nil) return *n == 0;
*ps= n;
return 1;
}
int numeric(char *s)
{
return numprefix(s, (char **) nil);
}
/* Device numbers of standard Minix devices. */
#define DEV_RAM 0x0100
#define DEV_FD0 0x0200
#define DEV_HD0 0x0300
#define DEV_SD0 0x0A00
#define minor_1a 128
dev_t name2dev(char *name)
/* Translate, say, /dev/hd3 to a device number. If the name can't be
* found on the boot device, then do some guesswork. The global structure
* "tmpdev" will be filled in based on the name, so that "boot hd6" knows
* what device to boot without interpreting device numbers.
*/
{
dev_t dev;
ino_t ino;
int drive;
struct stat st;
char *n, *s;
/* "boot *hd3" means: make partition 3 active before you boot it. */
if ((activate= (name[0] == '*'))) name++;
/* The special name "bootdev" must be translated to the boot device. */
if (strcmp(name, "bootdev") == 0) {
if (bootdev.device == -1) {
printf("The boot device could not be named\n");
errno= 0;
return -1;
}
name= bootdev.name;
}
/* If our boot device doesn't have a file system, or we want to know
* what a name means for the BIOS, then we need to interpret the
* device name ourselves: "fd" = floppy, "hd" = hard disk, etc.
*/
tmpdev.device= tmpdev.primary= tmpdev.secondary= -1;
dev= -1;
n= name;
if (strncmp(n, "/dev/", 5) == 0) n+= 5;
if (strcmp(n, "ram") == 0) {
dev= DEV_RAM;
} else
if (n[0] == 'f' && n[1] == 'd' && numeric(n+2)) {
/* Floppy. */
tmpdev.device= a2l(n+2);
dev= DEV_FD0 + tmpdev.device;
} else
if ((n[0] == 'h' || n[0] == 's') && n[1] == 'd' && numprefix(n+2, &s)
&& (*s == 0 || (between('a', *s, 'd') && s[1] == 0))
) {
/* Hard disk. */
dev= a2l(n+2);
tmpdev.device= dev / (1 + NR_PARTITIONS);
tmpdev.primary= (dev % (1 + NR_PARTITIONS)) - 1;
if (*s != 0) {
/* Subpartition. */
tmpdev.secondary= *s - 'a';
dev= minor_1a
+ (tmpdev.device * NR_PARTITIONS
+ tmpdev.primary) * NR_PARTITIONS
+ tmpdev.secondary;
}
tmpdev.device+= 0x80;
dev+= n[0] == 'h' ? DEV_HD0 : DEV_SD0;
}
/* Look the name up on the boot device for the UNIX device number. */
if (fsok) {
/* The current working directory is "/dev". */
ino= r_lookup(r_lookup(ROOT_INO, "dev"), name);
if (ino != 0) {
/* Name has been found, extract the device number. */
r_stat(ino, &st);
if (!S_ISBLK(st.st_mode)) {
printf("%s is not a block device\n", name);
errno= 0;
return (dev_t) -1;
}
dev= st.st_rdev;
}
}
if (tmpdev.primary < 0) activate= 0; /* Careful now! */
if (dev == -1) {
printf("Can't recognize '%s' as a device\n", name);
errno= 0;
}
return dev;
}
#if !DOS
#define B_NODEV -1
#define B_NOSIG -2
int exec_bootstrap(dev_t dev)
/* Load boot sector from the disk or floppy described by tmpdev and execute it.
* The floppy parameters may not be right for the floppy we want to read, but
* reading sector 0 seems to be no problem.
*/
{
int r, n, dirty= 0;
char master[SECTOR_SIZE];
struct part_entry *table[NR_PARTITIONS], dummy, *active= &dummy;
u32_t masterpos;
device= tmpdev.device;
if (!dev_geometry()) return B_NODEV;
active->lowsec= 0;
/* Select a partition table entry. */
while (tmpdev.primary >= 0) {
masterpos= active->lowsec;
if ((r= get_master(master, table, masterpos)) != 0) return r;
active= table[tmpdev.primary];
/* How does one check a partition table entry? */
if (active->sysind == NO_PART) return B_NOSIG;
tmpdev.primary= tmpdev.secondary;
tmpdev.secondary= -1;
}
if (activate && !active->bootind) {
for (n= 0; n < NR_PARTITIONS; n++) table[n]->bootind= 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -