Initial revision

This commit is contained in:
Ben Gras
2005-04-21 14:53:53 +00:00
commit 9865aeaa79
2264 changed files with 411685 additions and 0 deletions

116
boot/Makefile Executable file
View File

@@ -0,0 +1,116 @@
# Makefile for the boot monitor package.
SYS = ..
CC = exec cc
CC86 = exec cc -mi86 -Was-ncc
CFLAGS = -I$(SYS)
LIBS = -lsys
LD = $(CC) -s -.o
LD86 = $(CC86) -.o
BIN = /usr/bin
MDEC = /usr/mdec
all: bootblock boot edparams masterboot jumpboot installboot addaout
dos: boot.com mkfile.com
bootblock: bootblock.s
$(LD86) -com -o $@ bootblock.s
masterboot: masterboot.s
$(LD86) -com -o $@ masterboot.s
jumpboot: jumpboot.s
$(LD86) -com -o $@ jumpboot.s
boot.o: boot.c
$(CC86) $(CFLAGS) -c boot.c
bootimage.o: bootimage.c
$(CC86) $(CFLAGS) -c bootimage.c
rawfs86.o: rawfs.c rawfs.o
ln -f rawfs.c rawfs86.c
$(CC86) $(CFLAGS) -c rawfs86.c
rm rawfs86.c
-cmp -s rawfs.o rawfs86.o && ln -f rawfs.o rawfs86.o
boot: boothead.s boot.o bootimage.o rawfs86.o
$(LD86) -o $@ \
boothead.s boot.o bootimage.o rawfs86.o $(LIBS)
install -S 16kb boot
edparams.o: boot.c
ln -f boot.c edparams.c
$(CC) $(CFLAGS) -DUNIX -c edparams.c
rm edparams.c
edparams: edparams.o rawfs.o
$(CC) $(CFLAGS) $(STRIP) -o $@ edparams.o rawfs.o
install -S 16kw edparams
dosboot.o: boot.c
$(CC86) $(CFLAGS) -DDOS -o $@ -c boot.c
doshead.o: doshead.s
$(CC) -mi386 -o $@ -c doshead.s
dosboot: doshead.o dosboot.o bootimage.o rawfs86.o
$(LD86) -com -o $@ \
doshead.o dosboot.o bootimage.o rawfs86.o $(LIBS)
boot.com: dosboot
./a.out2com dosboot boot.com
mkfile: mkfhead.s mkfile.c
$(LD) -.o -mi86 -com -o $@ mkfhead.s mkfile.c $(LIBS)
mkfile.com: mkfile
./a.out2com mkfile mkfile.com
installboot: installboot.o rawfs.o
$(CC) $(STRIP) -o installboot installboot.o rawfs.o
install -S 6kw installboot
addaout: addaout.o
$(CC) -o addaout addaout.o
installboot.o bootimage.o: image.h
boot.o bootimage.o dosboot.o edparams.o: boot.h
rawfs.o rawfs86.o installboot.o boot.o bootimage.o: rawfs.h
install: $(MDEC)/bootblock $(MDEC)/boot $(MDEC)/masterboot \
$(MDEC)/jumpboot $(BIN)/installboot $(BIN)/edparams
dosinstall: $(MDEC)/boot.com $(MDEC)/mkfile.com
$(MDEC)/bootblock: bootblock
install -cs -o bin -m 644 $? $@
$(MDEC)/boot: boot
install -cs -o bin -m 644 $? $@
$(MDEC)/boot.com: boot.com
install -c -m 644 $? $@
$(MDEC)/mkfile.com: mkfile.com
install -c -m 644 $? $@
$(MDEC)/masterboot: masterboot
install -cs -o bin -m 644 $? $@
$(MDEC)/jumpboot: jumpboot
install -cs -o bin -m 644 $? $@
$(BIN)/installboot: installboot
install -cs -o bin $? $@
$(BIN)/addaout: addaout
install -cs -o bin $? $@
$(BIN)/edparams: edparams
install -cs -o bin $? $@
clean:
rm -f *.bak *.o
rm -f bootblock addaout installboot boot masterboot jumpboot edparams
rm -f dosboot boot.com mkfile mkfile.com

25
boot/a.out2com Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/sh
#
# a.out2com - Minix a.out to DOS .COM Author: Kees J. Bot
# 17 Jun 1995
# Transform a Minix a.out to the COM format of MS-DOS,
# the executable must be common I&D with 256 scratch bytes at the start of
# the text segment to make space for the Program Segment Prefix. The Minix
# a.out header and these 256 bytes are removed to make a COM file.
case $# in
2) aout="$1"
com="$2"
;;
*) echo "Usage: $0 <a.out> <dos.com>" >&2
exit 1
esac
size "$aout" >/dev/null || exit
set `size "$aout" | sed 1d`
count=`expr \( $1 + $2 - 256 + 31 \) / 32`
exec dd if="$aout" of="$com" bs=32 skip=9 count=$count conv=silent
#
# $PchId: a.out2com,v 1.3 1998/08/01 09:13:01 philip Exp $

127
boot/addaout.c Normal file
View File

@@ -0,0 +1,127 @@
/* A small utility to append an a.out header to an arbitrary file. This allows
* inclusion of arbitrary data in the boot image, so that it is magically
* loaded as a RAM disk. The a.out header is structured as follows:
*
* a_flags: A_IMG to indicate this is not an executable
*
* Created: April 2005, Jorrit N. Herder
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <a.out.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#define INPUT_FILE 1
#define OUTPUT_FILE 2
/* Report problems. */
void report(char *problem, char *message)
{
fprintf(stderr, "%s:\n", problem);
fprintf(stderr, " %s\n\n", message);
}
int copy_data(int srcfd, int dstfd)
{
char buf[8192];
ssize_t n;
int total=0;
/* Copy the little bytes themselves. (Source from cp.c). */
while ((n= read(srcfd, buf, sizeof(buf))) > 0) {
char *bp = buf;
ssize_t r;
while (n > 0 && (r= write(dstfd, bp, n)) > 0) {
bp += r;
n -= r;
total += r;
}
if (r <= 0) {
if (r == 0) {
fprintf(stderr, "Warning: EOF writing to output file.\n");
return(-1);
}
}
}
return(total);
}
/* Main program. */
int main(int argc, char **argv)
{
struct exec aout;
struct stat stin;
int fdin, fdout;
char * bp;
int n,r;
int total_size=0;
int result;
/* Check if command line arguments are present, or print usage. */
if (argc!=3) {
printf("Invalid arguments. Usage:\n");
printf(" %s <input_file> <output_file>\n",argv[0]);
return(1);
}
/* Check if we can open the input and output file. */
if (stat(argv[INPUT_FILE], &stin) != 0) {
report("Couldn't get status of input file", strerror(errno));
return(1);
}
if ((fdin = open(argv[INPUT_FILE], O_RDONLY)) < 0) {
report("Couldn't open input file", strerror(errno));
return(1);
}
if ((fdout = open(argv[OUTPUT_FILE], O_WRONLY|O_CREAT|O_TRUNC,
stin.st_mode & 0777)) < 0) {
report("Couldn't open output file", strerror(errno));
return(1);
}
/* Copy input file to output file, but leave space for a.out header. */
lseek(fdout, sizeof(aout), SEEK_SET);
total_size = copy_data(fdin, fdout);
if (total_size < 0) {
report("Aborted", "Output file may be truncated.");
return(1);
} else if (total_size == 0) {
report("Aborted without prepending header", "No data in input file.");
return(1);
}
/* Build a.out header and write to output file. */
memset(&aout, 0, sizeof(struct exec));
aout.a_magic[0] = A_MAGIC0;
aout.a_magic[1] = A_MAGIC1;
aout.a_flags |= A_IMG;
aout.a_hdrlen = sizeof(aout);
aout.a_text = 0;
aout.a_data = total_size;
aout.a_bss = 0;
aout.a_total = aout.a_hdrlen + aout.a_data;
bp = (char *) &aout;
n = sizeof(aout);
lseek(fdout, 0, SEEK_SET);
while (n > 0 && (r= write(fdout, bp, n)) > 0) {
bp += r;
n -= r;
}
printf("Prepended data file (%u bytes) with a.out header.\n", total_size);
printf("Done.\n");
return(0);
}

1930
boot/boot.c Executable file

File diff suppressed because it is too large Load Diff

209
boot/boot.h Executable file
View File

@@ -0,0 +1,209 @@
/* boot.h - Info between different parts of boot. Author: Kees J. Bot
*/
#ifndef DEBUG
#define DEBUG 0
#endif
/* Constants describing the metal: */
#define SECTOR_SIZE 512
#define SECTOR_SHIFT 9
#define RATIO(b) ((b) / SECTOR_SIZE)
#define PARAMSEC 1 /* Sector containing boot parameters. */
#define DSKBASE 0x1E /* Floppy disk parameter vector. */
#define DSKPARSIZE 11 /* There are this many bytes of parameters. */
#define ESC '\33' /* Escape key. */
#define HEADERPOS 0x00600L /* Place for an array of struct exec's. */
#define FREEPOS 0x08000L /* Memory from FREEPOS to caddr is free to
* play with.
*/
#if BIOS
#define MSEC_PER_TICK 55 /* Clock does 18.2 ticks per second. */
#define TICKS_PER_DAY 0x1800B0L /* After 24 hours it wraps. */
#endif
#if UNIX
#define MSEC_PER_TICK 1000 /* Clock does 18.2 ticks per second. */
#define TICKS_PER_DAY 86400L /* Doesn't wrap, but that doesn't matter. */
#endif
#define BOOTPOS 0x07C00L /* Bootstraps are loaded here. */
#define SIGNATURE 0xAA55 /* Proper bootstraps have this signature. */
#define SIGNATOFF 510 /* Offset within bootblock. */
/* BIOS video modes. */
#define MONO_MODE 0x07 /* 80x25 monochrome. */
#define COLOR_MODE 0x03 /* 80x25 color. */
/* Variables shared with boothead.s: */
#ifndef EXTERN
#define EXTERN extern
#endif
typedef struct vector { /* 8086 vector */
u16_t offset;
u16_t segment;
} vector;
EXTERN vector rem_part; /* Boot partition table entry. */
EXTERN u32_t caddr, daddr; /* Code and data address of the boot program. */
EXTERN u32_t runsize; /* Size of this program. */
EXTERN u16_t device; /* Drive being booted from. */
typedef struct { /* One chunk of free memory. */
u32_t base; /* Start byte. */
u32_t size; /* Number of bytes. */
} memory;
EXTERN memory mem[3]; /* List of available memory. */
EXTERN int mon_return; /* Monitor stays in memory? */
typedef struct bios_env
{
u16_t ax;
u16_t bx;
u16_t cx;
u16_t flags;
} bios_env_t;
#define FL_CARRY 0x0001 /* carry flag */
/* Functions defined by boothead.s: */
void exit(int code);
/* Exit the monitor. */
u32_t mon2abs(void *ptr);
/* Local monitor address to absolute address. */
u32_t vec2abs(vector *vec);
/* Vector to absolute address. */
void raw_copy(u32_t dstaddr, u32_t srcaddr, u32_t count);
/* Copy bytes from anywhere to anywhere. */
u16_t get_word(u32_t addr);
/* Get a word from anywhere. */
void put_word(u32_t addr, U16_t word);
/* Put a word anywhere. */
void relocate(void);
/* Switch to a copy of this program. */
int dev_open(void), dev_close(void);
/* Open device and determine params / close device. */
int dev_boundary(u32_t sector);
/* True if sector is on a track boundary. */
int readsectors(u32_t bufaddr, u32_t sector, U8_t count);
/* Read 1 or more sectors from "device". */
int writesectors(u32_t bufaddr, u32_t sector, U8_t count);
/* Write 1 or more sectors to "device". */
int getch(void);
/* Read a keypress. */
void ungetch(int c);
/* Undo a keypress. */
int escape(void);
/* True if escape typed. */
void putch(int c);
/* Send a character to the screen. */
#if BIOS
void pause(void);
/* Wait for an interrupt. */
void serial_init(int line);
#endif /* Enable copying console I/O to a serial line. */
void set_mode(unsigned mode);
void clear_screen(void);
/* Set video mode / clear the screen. */
u16_t get_bus(void);
/* System bus type, XT, AT, or MCA. */
u16_t get_video(void);
/* Display type, MDA to VGA. */
u32_t get_tick(void);
/* Current value of the clock tick counter. */
void bootstrap(int device, struct part_entry *entry);
/* Execute a bootstrap routine for a different O.S. */
void minix(u32_t koff, u32_t kcs, u32_t kds,
char *bootparams, size_t paramsize, u32_t aout);
/* Start Minix. */
void int15(bios_env_t *);
/* Shared between boot.c and bootimage.c: */
/* Sticky attributes. */
#define E_SPECIAL 0x01 /* These are known to the program. */
#define E_DEV 0x02 /* The value is a device name. */
#define E_RESERVED 0x04 /* May not be set by user, e.g. 'boot' */
#define E_STICKY 0x07 /* Don't go once set. */
/* Volatile attributes. */
#define E_VAR 0x08 /* Variable */
#define E_FUNCTION 0x10 /* Function definition. */
/* Variables, functions, and commands. */
typedef struct environment {
struct environment *next;
char flags;
char *name; /* name = value */
char *arg; /* name(arg) {value} */
char *value;
char *defval; /* Safehouse for default values. */
} environment;
EXTERN environment *env; /* Lists the environment. */
char *b_value(char *name); /* Get/set the value of a variable. */
int b_setvar(int flags, char *name, char *value);
void parse_code(char *code); /* Parse boot monitor commands. */
extern int fsok; /* True if the boot device contains an FS. */
EXTERN u32_t lowsec; /* Offset to the file system on the boot device. */
/* Called by boot.c: */
void bootminix(void); /* Load and start a Minix image. */
/* Called by bootimage.c: */
void readerr(off_t sec, int err);
/* Report a read error. */
char *ul2a(u32_t n, unsigned b), *ul2a10(u32_t n);
/* Transform u32_t to ASCII at base b or base 10. */
long a2l(char *a);
/* Cheap atol(). */
unsigned a2x(char *a);
/* ASCII to hex. */
dev_t name2dev(char *name);
/* Translate a device name to a device number. */
int numprefix(char *s, char **ps);
/* True for a numeric prefix. */
int numeric(char *s);
/* True for a numeric string. */
char *unix_err(int err);
/* Give a descriptive text for some UNIX errors. */
int run_trailer(void);
/* Run the trailer function. */
#if DOS
/* The monitor runs under MS-DOS. */
extern char PSP[256]; /* Program Segment Prefix. */
EXTERN char *vdisk; /* Name of the virtual disk. */
EXTERN char *drun; /* Initial command from DOS command line. */
#else
/* The monitor uses only the BIOS. */
#define DOS 0
#endif
void readblock(off_t, char *, int);
/*
* $PchId: boot.h,v 1.12 2002/02/27 19:42:45 philip Exp $
*/

231
boot/bootblock.s Executable file
View File

@@ -0,0 +1,231 @@
! Bootblock 1.5 - Minix boot block. Author: Kees J. Bot
! 21 Dec 1991
!
! When the PC is powered on, it will try to read the first sector of floppy
! disk 0 at address 0x7C00. If this fails due to the absence of flexible
! magnetic media, it will read the master boot record from the first sector
! of the hard disk. This sector not only contains executable code, but also
! the partition table of the hard disk. When executed, it will select the
! active partition and load the first sector of that at address 0x7C00.
! This file contains the code that is eventually read from either the floppy
! disk, or the hard disk partition. It is just smart enough to load /boot
! from the boot device into memory at address 0x10000 and execute that. The
! disk addresses for /boot are patched into this code by installboot as 24-bit
! sector numbers and 8-bit sector counts above enddata upwards. /boot is in
! turn smart enough to load the different parts of the Minix kernel into
! memory and execute them to finally get Minix started.
!
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
BOOTSEG = 0x1000 ! Secondary boot code segment.
BOOTOFF = 0x0030 ! Offset into /boot above header
BUFFER = 0x0600 ! First free memory
LOWSEC = 8 ! Offset of logical first sector in partition
! table
! Variables addressed using bp register
device = 0 ! The boot device
lowsec = 2 ! Offset of boot partition within drive
secpcyl = 6 ! Sectors per cylinder = heads * sectors
.text
! Start boot procedure.
boot:
xor ax, ax ! ax = 0x0000, the vector segment
mov ds, ax
cli ! Ignore interrupts while setting stack
mov ss, ax ! ss = ds = vector segment
mov sp, #LOADOFF ! Usual place for a bootstrap stack
sti
push ax
push ax ! Push a zero lowsec(bp)
push dx ! Boot device in dl will be device(bp)
mov bp, sp ! Using var(bp) is one byte cheaper then var.
push es
push si ! es:si = partition table entry if hard disk
mov di, #LOADOFF+sectors ! char *di = sectors;
testb dl, dl ! Winchester disks if dl >= 0x80
jge floppy
winchester:
! Get the offset of the first sector of the boot partition from the partition
! table. The table is found at es:si, the lowsec parameter at offset LOWSEC.
eseg
les ax, LOWSEC(si) ! es:ax = LOWSEC+2(si):LOWSEC(si)
mov lowsec+0(bp), ax ! Low 16 bits of partition's first sector
mov lowsec+2(bp), es ! High 16 bits of partition's first sector
! Get the drive parameters, the number of sectors is bluntly written into the
! floppy disk sectors/track array.
movb ah, #0x08 ! Code for drive parameters
int 0x13 ! dl still contains drive
andb cl, #0x3F ! cl = max sector number (1-origin)
movb (di), cl ! Number of sectors per track
incb dh ! dh = 1 + max head number (0-origin)
jmp loadboot
! Floppy:
! Execute three read tests to determine the drive type. Test for each floppy
! type by reading the last sector on the first track. If it fails, try a type
! that has less sectors. Therefore we start with 1.44M (18 sectors) then 1.2M
! (15 sectors) ending with 720K/360K (both 9 sectors).
next: inc di ! Next number of sectors per track
floppy: xorb ah, ah ! Reset drive
int 0x13
movb cl, (di) ! cl = number of last sector on track
cmpb cl, #9 ! No need to do the last 720K/360K test
je success
! Try to read the last sector on track 0
mov es, lowsec(bp) ! es = vector segment (lowsec = 0)
mov bx, #BUFFER ! es:bx buffer = 0x0000:0x0600
mov ax, #0x0201 ! Read sector, #sectors = 1
xorb ch, ch ! Track 0, last sector
xorb dh, dh ! Drive dl, head 0
int 0x13
jc next ! Error, try the next floppy type
success:movb dh, #2 ! Load number of heads for multiply
loadboot:
! Load /boot from the boot device
movb al, (di) ! al = (di) = sectors per track
mulb dh ! dh = heads, ax = heads * sectors
mov secpcyl(bp), ax ! Sectors per cylinder = heads * sectors
mov ax, #BOOTSEG ! Segment to load /boot into
mov es, ax
xor bx, bx ! Load first sector at es:bx = BOOTSEG:0x0000
mov si, #LOADOFF+addresses ! Start of the boot code addresses
load:
mov ax, 1(si) ! Get next sector number: low 16 bits
movb dl, 3(si) ! Bits 16-23 for your up to 8GB partition
xorb dh, dh ! dx:ax = sector within partition
add ax, lowsec+0(bp)
adc dx, lowsec+2(bp)! dx:ax = sector within drive
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
jae bigdisk
div secpcyl(bp) ! ax = cylinder, dx = sector within cylinder
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
movb ch, dl ! ch = low 8 bits of cylinder
divb (di) ! al = head, ah = sector (0-origin)
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
shr dx, #1
shr dx, #1 ! dl[6..7] = high cylinder
orb dl, ah ! dl[0..5] = sector (0-origin)
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
incb cl ! cl[0..5] = sector (1-origin)
movb dh, al ! dh = al = head
movb dl, device(bp) ! dl = device to read
movb al, (di) ! Sectors per track - Sector number (0-origin)
subb al, ah ! = Sectors left on this track
cmpb al, (si) ! Compare with # sectors to read
jbe read ! Can't read past the end of a cylinder?
movb al, (si) ! (si) < sectors left on this track
read: push ax ! Save al = sectors to read
movb ah, #0x02 ! Code for disk read (all registers in use now!)
int 0x13 ! Call the BIOS for a read
pop cx ! Restore al in cl
jmp rdeval
bigdisk:
movb cl, (si) ! Number of sectors to read
push si ! Save si
mov si, #LOADOFF+ext_rw ! si = extended read/write parameter packet
movb 2(si), cl ! Fill in # blocks to transfer
mov 4(si), bx ! Buffer address
mov 8(si), ax ! Starting block number = dx:ax
mov 10(si), dx
movb dl, device(bp) ! dl = device to read
movb ah, #0x42 ! Extended read
int 0x13
pop si ! Restore si to point to the addresses array
!jmp rdeval
rdeval:
jc error ! Jump on disk read error
movb al, cl ! Restore al = sectors read
addb bh, al ! bx += 2 * al * 256 (add bytes read)
addb bh, al ! es:bx = where next sector must be read
add 1(si), ax ! Update address by sectors read
adcb 3(si), ah ! Don't forget bits 16-23 (add ah = 0)
subb (si), al ! Decrement sector count by sectors read
jnz load ! Not all sectors have been read
add si, #4 ! Next (address, count) pair
cmpb ah, (si) ! Done when no sectors to read
jnz load ! Read next chunk of /boot
done:
! Call /boot, assuming a long a.out header (48 bytes). The a.out header is
! usually short (32 bytes), but to be sure /boot has two entry points:
! One at offset 0 for the long, and one at offset 16 for the short header.
! Parameters passed in registers are:
!
! dl = Boot-device.
! es:si = Partition table entry if hard disk.
!
pop si ! Restore es:si = partition table entry
pop es ! dl is still loaded
jmpf BOOTOFF, BOOTSEG ! jmp to sec. boot (skipping header).
! Read error: print message, hang forever
error:
mov si, #LOADOFF+errno+1
prnum: movb al, ah ! Error number in ah
andb al, #0x0F ! Low 4 bits
cmpb al, #10 ! A-F?
jb digit ! 0-9!
addb al, #7 ! 'A' - ':'
digit: addb (si), al ! Modify '0' in string
dec si
movb cl, #4 ! Next 4 bits
shrb ah, cl
jnz prnum ! Again if digit > 0
mov si, #LOADOFF+rderr ! String to print
print: lodsb ! al = *si++ is char to be printed
testb al, al ! Null byte marks end
hang: jz hang ! Hang forever waiting for CTRL-ALT-DEL
movb ah, #0x0E ! Print character in teletype mode
mov bx, #0x0001 ! Page 0, foreground color
int 0x10 ! Call BIOS VIDEO_IO
jmp print
.data
rderr: .ascii "Read error "
errno: .ascii "00 \0"
errend:
! Floppy disk sectors per track for the 1.44M, 1.2M and 360K/720K types:
sectors:
.data1 18, 15, 9
! Extended read/write commands require a parameter packet.
ext_rw:
.data1 0x10 ! Length of extended r/w packet
.data1 0 ! Reserved
.data2 0 ! Blocks to transfer (to be filled in)
.data2 0 ! Buffer address offset (tbfi)
.data2 BOOTSEG ! Buffer address segment
.data4 0 ! Starting block number low 32 bits (tbfi)
.data4 0 ! Starting block number high 32 bits
.align 2
addresses:
! The space below this is for disk addresses for a 38K /boot program (worst
! case, i.e. file is completely fragmented). It should be enough.

1497
boot/boothead.s Executable file

File diff suppressed because it is too large Load Diff

712
boot/bootimage.c Executable file
View File

@@ -0,0 +1,712 @@
/* bootimage.c - Load an image and start it. Author: Kees J. Bot
* 19 Jan 1992
*/
#define BIOS 1 /* Can only be used under the BIOS. */
#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/syslib.h>
#include <kernel/const.h>
#include <kernel/type.h>
#include <ibm/partition.h>
#include "rawfs.h"
#include "image.h"
#include "boot.h"
static int block_size = 0;
#define click_shift clck_shft /* 7 char clash with click_size. */
/* Some kernels have extra features: */
#define K_I386 0x0001 /* Make the 386 transition before you call me. */
#define K_CLAIM 0x0002 /* I will acquire my own bss pages, thank you. */
#define K_CHMEM 0x0004 /* This kernel listens to chmem for its stack size. */
#define K_HIGH 0x0008 /* Load mm, fs, etc. in extended memory. */
#define K_HDR 0x0010 /* No need to patch sizes, kernel uses the headers. */
#define K_RET 0x0020 /* Returns to the monitor on reboot. */
#define K_INT86 0x0040 /* Requires generic INT support. */
#define K_MEML 0x0080 /* Pass a list of free memory. */
#define K_BRET 0x0100 /* New monitor code on shutdown in boot parameters. */
#define K_ALL 0x01FF /* All feature bits this monitor supports. */
/* Data about the different processes. */
#define PROCESS_MAX 16 /* Must match the space in kernel/mpx.x */
#define KERNEL 0 /* The first process is the kernel. */
#define FS 2 /* The third must be fs. */
struct process { /* Per-process memory adresses. */
u32_t entry; /* Entry point. */
u32_t cs; /* Code segment. */
u32_t ds; /* Data segment. */
u32_t data; /* To access the data segment. */
u32_t end; /* End of this process, size = (end - cs). */
} process[PROCESS_MAX];
int n_procs; /* Number of processes. */
/* Magic numbers in process' data space. */
#define MAGIC_OFF 0 /* Offset of magic # in data seg. */
#define CLICK_OFF 2 /* Offset in kernel text to click_shift. */
#define FLAGS_OFF 4 /* Offset in kernel text to flags. */
#define KERNEL_D_MAGIC 0x526F /* Kernel magic number. */
/* Offsets of sizes to be patched into kernel and fs. */
#define P_SIZ_OFF 0 /* Process' sizes into kernel data. */
#define P_INIT_OFF 4 /* Init cs & sizes into fs data. */
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
void pretty_image(char *image)
/* Pretty print the name of the image to load. Translate '/' and '_' to
* space, first letter goes uppercase. An 'r' before a digit prints as
* 'revision'. E.g. 'minix/1.6.16r10' -> 'Minix 1.6.16 revision 10'.
* The idea is that the part before the 'r' is the official Minix release
* and after the 'r' you can put version numbers for your own changes.
*/
{
int up= 0, c;
while ((c= *image++) != 0) {
if (c == '/' || c == '_') c= ' ';
if (c == 'r' && between('0', *image, '9')) {
printf(" revision ");
continue;
}
if (!up && between('a', c, 'z')) c= c - 'a' + 'A';
if (between('A', c, 'Z')) up= 1;
putch(c);
}
}
void raw_clear(u32_t addr, u32_t count)
/* Clear "count" bytes at absolute address "addr". */
{
static char zeros[128];
u32_t dst;
u32_t zct;
zct= sizeof(zeros);
if (zct > count) zct= count;
raw_copy(addr, mon2abs(&zeros), zct);
count-= zct;
while (count > 0) {
dst= addr + zct;
if (zct > count) zct= count;
raw_copy(dst, addr, zct);
count-= zct;
zct*= 2;
}
}
/* Align a to a multiple of n (a power of 2): */
#define align(a, n) (((u32_t)(a) + ((u32_t)(n) - 1)) & ~((u32_t)(n) - 1))
unsigned click_shift;
unsigned click_size; /* click_size = Smallest kernel memory object. */
unsigned k_flags; /* Not all kernels are created equal. */
u32_t reboot_code; /* Obsolete reboot code return pointer. */
int params2params(char *params, size_t psize)
/* Repackage the environment settings for the kernel. */
{
size_t i, n;
environment *e;
char *name, *value;
dev_t dev;
i= 0;
for (e= env; e != nil; e= e->next) {
name= e->name;
value= e->value;
if (!(e->flags & E_VAR)) continue;
if (e->flags & E_DEV) {
if ((dev= name2dev(value)) == -1) return 0;
value= ul2a10((u16_t) dev);
}
n= i + strlen(name) + 1 + strlen(value) + 1;
if (n < psize) {
strcpy(params + i, name);
strcat(params + i, "=");
strcat(params + i, value);
}
i= n;
}
if (!(k_flags & K_MEML)) {
/* Require old memory size variables. */
value= ul2a10((mem[0].base + mem[0].size) / 1024);
n= i + 7 + 1 + strlen(value) + 1;
if (n < psize) {
strcpy(params + i, "memsize=");
strcat(params + i, value);
}
i= n;
value= ul2a10(mem[1].size / 1024);
n= i + 7 + 1 + strlen(value) + 1;
if (n < psize) {
strcpy(params + i, "emssize=");
strcat(params + i, value);
}
i= n;
}
if (i >= psize) {
printf("Too many boot parameters\n");
return 0;
}
params[i]= 0; /* End marked with empty string. */
return 1;
}
void patch_sizes(void)
/* Patch sizes of each process into kernel data space, kernel ds into kernel
* text space, and sizes of init into data space of fs. All the patched
* numbers are based on the kernel click size, not hardware segments.
*/
{
u16_t text_size, data_size;
int i;
struct process *procp, *initp;
u32_t doff;
if (k_flags & K_HDR) return; /* Uses the headers. */
/* Patch text and data sizes of the processes into kernel data space.
*/
doff= process[KERNEL].data + P_SIZ_OFF;
for (i= 0; i < n_procs; i++) {
procp= &process[i];
text_size= (procp->ds - procp->cs) >> click_shift;
data_size= (procp->end - procp->ds) >> click_shift;
/* Two words per process, the text and data size: */
put_word(doff, text_size); doff+= 2;
put_word(doff, data_size); doff+= 2;
initp= procp; /* The last process must be init. */
}
if (k_flags & (K_HIGH|K_MEML)) return; /* Doesn't need FS patching. */
/* Patch cs and sizes of init into fs data. */
put_word(process[FS].data + P_INIT_OFF+0, initp->cs >> click_shift);
put_word(process[FS].data + P_INIT_OFF+2, text_size);
put_word(process[FS].data + P_INIT_OFF+4, data_size);
}
int selected(char *name)
/* True iff name has no label or the proper label. */
{
char *colon, *label;
int cmp;
if ((colon= strchr(name, ':')) == nil) return 1;
if ((label= b_value("label")) == nil) return 1;
*colon= 0;
cmp= strcmp(label, name);
*colon= ':';
return cmp == 0;
}
u32_t proc_size(struct image_header *hdr)
/* Return the size of a process in sectors as found in an image. */
{
u32_t len= hdr->process.a_text;
if (hdr->process.a_flags & A_PAL) len+= hdr->process.a_hdrlen;
if (hdr->process.a_flags & A_SEP) len= align(len, SECTOR_SIZE);
len= align(len + hdr->process.a_data, SECTOR_SIZE);
return len >> SECTOR_SHIFT;
}
off_t image_off, image_size;
u32_t (*vir2sec)(u32_t vsec); /* Where is a sector on disk? */
u32_t file_vir2sec(u32_t vsec)
/* Translate a virtual sector number to an absolute disk sector. */
{
off_t blk;
if(!block_size) { errno = 0; return -1; }
if ((blk= r_vir2abs(vsec / RATIO(block_size))) == -1) {
errno= EIO;
return -1;
}
return blk == 0 ? 0 : lowsec + blk * RATIO(block_size) + vsec % RATIO(block_size);
}
u32_t flat_vir2sec(u32_t vsec)
/* Simply add an absolute sector offset to vsec. */
{
return lowsec + image_off + vsec;
}
char *get_sector(u32_t vsec)
/* Read a sector "vsec" from the image into memory and return its address.
* Return nil on error. (This routine tries to read an entire track, so
* the next request is usually satisfied from the track buffer.)
*/
{
u32_t sec;
int r;
static char buf[32 * SECTOR_SIZE];
static size_t count; /* Number of sectors in the buffer. */
static u32_t bufsec; /* First Sector now in the buffer. */
if (vsec == 0) count= 0; /* First sector; initialize. */
if ((sec= (*vir2sec)(vsec)) == -1) return nil;
if (sec == 0) {
/* A hole. */
count= 0;
memset(buf, 0, SECTOR_SIZE);
return buf;
}
/* Can we return a sector from the buffer? */
if ((sec - bufsec) < count) {
return buf + ((size_t) (sec - bufsec) << SECTOR_SHIFT);
}
/* Not in the buffer. */
count= 0;
bufsec= sec;
/* Read a whole track if possible. */
while (++count < 32 && !dev_boundary(bufsec + count)) {
vsec++;
if ((sec= (*vir2sec)(vsec)) == -1) break;
/* Consecutive? */
if (sec != bufsec + count) break;
}
/* Actually read the sectors. */
if ((r= readsectors(mon2abs(buf), bufsec, count)) != 0) {
readerr(bufsec, r);
count= 0;
errno= 0;
return nil;
}
return buf;
}
int get_clickshift(u32_t ksec, struct image_header *hdr)
/* Get the click shift and special flags from kernel text. */
{
char *textp;
if ((textp= get_sector(ksec)) == nil) return 0;
if (hdr->process.a_flags & A_PAL) textp+= hdr->process.a_hdrlen;
click_shift= * (u16_t *) (textp + CLICK_OFF);
k_flags= * (u16_t *) (textp + FLAGS_OFF);
if ((k_flags & ~K_ALL) != 0) {
printf("%s requires features this monitor doesn't offer\n",
hdr->name);
return 0;
}
if (click_shift < HCLICK_SHIFT || click_shift > 16) {
printf("%s click size is bad\n", hdr->name);
errno= 0;
return 0;
}
click_size= 1 << click_shift;
return 1;
}
int get_segment(u32_t *vsec, long *size, u32_t *addr, u32_t limit)
/* Read *size bytes starting at virtual sector *vsec to memory at *addr. */
{
char *buf;
size_t cnt, n;
cnt= 0;
while (*size > 0) {
if (cnt == 0) {
if ((buf= get_sector((*vsec)++)) == nil) return 0;
cnt= SECTOR_SIZE;
}
if (*addr + click_size > limit) { errno= ENOMEM; return 0; }
n= click_size;
if (n > cnt) n= cnt;
raw_copy(*addr, mon2abs(buf), n);
*addr+= n;
*size-= n;
buf+= n;
cnt-= n;
}
/* Zero extend to a click. */
n= align(*addr, click_size) - *addr;
raw_clear(*addr, n);
*addr+= n;
*size-= n;
return 1;
}
void exec_image(char *image)
/* Get a Minix image into core, patch it up and execute. */
{
int i;
struct image_header hdr;
char *buf;
u32_t vsec, addr, limit, aout, n;
struct process *procp; /* Process under construction. */
long a_text, a_data, a_bss, a_stack;
int banner= 0;
long processor= a2l(b_value("processor"));
u16_t mode;
char *console;
char params[SECTOR_SIZE];
extern char *sbrk(int);
/* The stack is pretty deep here, so check if heap and stack collide. */
(void) sbrk(0);
printf("\nLoading ");
pretty_image(image);
printf(".\n\n");
vsec= 0; /* Load this sector from image next. */
addr= mem[0].base; /* Into this memory block. */
limit= mem[0].base + mem[0].size;
if (limit > caddr) limit= caddr;
/* Allocate and clear the area where the headers will be placed. */
aout = (limit -= PROCESS_MAX * A_MINHDR);
/* Clear the area where the headers will be placed. */
raw_clear(aout, PROCESS_MAX * A_MINHDR);
/* Read the many different processes: */
for (i= 0; vsec < image_size; i++) {
if (i == PROCESS_MAX) {
printf("There are more then %d programs in %s\n",
PROCESS_MAX, image);
errno= 0;
return;
}
procp= &process[i];
/* Read header. */
for (;;) {
if ((buf= get_sector(vsec++)) == nil) return;
memcpy(&hdr, buf, sizeof(hdr));
if (BADMAG(hdr.process)) { errno= ENOEXEC; return; }
/* Check the optional label on the process. */
if (selected(hdr.name)) break;
/* Bad label, skip this process. */
vsec+= proc_size(&hdr);
}
/* Sanity check: an 8086 can't run a 386 kernel. */
if (hdr.process.a_cpu == A_I80386 && processor < 386) {
printf("You can't run a 386 kernel on this 80%ld\n",
processor);
errno= 0;
return;
}
/* Get the click shift from the kernel text segment. */
if (i == KERNEL) {
if (!get_clickshift(vsec, &hdr)) return;
addr= align(addr, click_size);
}
/* Save a copy of the header for the kernel, with a_syms
* misused as the address where the process is loaded at.
*/
hdr.process.a_syms= addr;
raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR);
if (!banner) {
printf(" cs ds text data bss");
if (k_flags & K_CHMEM) printf(" stack");
putch('\n');
banner= 1;
}
/* Segment sizes. */
a_text= hdr.process.a_text;
a_data= hdr.process.a_data;
a_bss= hdr.process.a_bss;
if (k_flags & K_CHMEM) {
a_stack= hdr.process.a_total - a_data - a_bss;
if (!(hdr.process.a_flags & A_SEP)) a_stack-= a_text;
} else {
a_stack= 0;
}
/* Collect info about the process to be. */
procp->cs= addr;
/* Process may be page aligned so that the text segment contains
* the header, or have an unmapped zero page against vaxisms.
*/
procp->entry= hdr.process.a_entry;
if (hdr.process.a_flags & A_PAL) a_text+= hdr.process.a_hdrlen;
if (hdr.process.a_flags & A_UZP) procp->cs-= click_size;
/* Separate I&D: two segments. Common I&D: only one. */
if (hdr.process.a_flags & A_SEP) {
/* Read the text segment. */
if (!get_segment(&vsec, &a_text, &addr, limit)) return;
/* The data segment follows. */
procp->ds= addr;
if (hdr.process.a_flags & A_UZP) procp->ds-= click_size;
procp->data= addr;
} else {
/* Add text to data to form one segment. */
procp->data= addr + a_text;
procp->ds= procp->cs;
a_data+= a_text;
}
printf("%06lx %06lx %7ld %7ld %7ld",
procp->cs, procp->ds,
hdr.process.a_text, hdr.process.a_data,
hdr.process.a_bss
);
if (k_flags & K_CHMEM) printf(" %8ld", a_stack);
printf(" %s\n", hdr.name);
/* Read the data segment. */
if (!get_segment(&vsec, &a_data, &addr, limit)) return;
/* Make space for bss and stack unless... */
if (i != KERNEL && (k_flags & K_CLAIM)) a_bss= a_stack= 0;
/* Note that a_data may be negative now, but we can look at it
* as -a_data bss bytes.
*/
/* Compute the number of bss clicks left. */
a_bss+= a_data;
n= align(a_bss, click_size);
a_bss-= n;
/* Zero out bss. */
if (addr + n > limit) { errno= ENOMEM; return; }
raw_clear(addr, n);
addr+= n;
/* And the number of stack clicks. */
a_stack+= a_bss;
n= align(a_stack, click_size);
a_stack-= n;
/* Add space for the stack. */
addr+= n;
/* Process endpoint. */
procp->end= addr;
if (i == 0 && (k_flags & K_HIGH)) {
/* Load the rest in extended memory. */
addr= mem[1].base;
limit= mem[1].base + mem[1].size;
}
}
if ((n_procs= i) == 0) {
printf("There are no programs in %s\n", image);
errno= 0;
return;
}
/* Check the kernel magic number. */
if (get_word(process[KERNEL].data + MAGIC_OFF) != KERNEL_D_MAGIC) {
printf("Kernel magic number is incorrect\n");
errno= 0;
return;
}
/* Patch sizes, etc. into kernel data. */
patch_sizes();
#if !DOS
if (!(k_flags & K_MEML)) {
/* Copy the a.out headers to the old place. */
raw_copy(HEADERPOS, aout, PROCESS_MAX * A_MINHDR);
}
#endif
/* Run the trailer function just before starting Minix. */
if (!run_trailer()) { errno= 0; return; }
/* Translate the boot parameters to what Minix likes best. */
if (!params2params(params, sizeof(params))) { errno= 0; return; }
/* Set the video to the required mode. */
if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) {
mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE :
MONO_MODE;
}
set_mode(mode);
/* Close the disk. */
(void) dev_close();
/* Minix. */
minix(process[KERNEL].entry, process[KERNEL].cs,
process[KERNEL].ds, params, sizeof(params), aout);
if (!(k_flags & K_BRET)) {
extern u32_t reboot_code;
raw_copy(mon2abs(params), reboot_code, sizeof(params));
}
parse_code(params);
/* Return from Minix. Things may have changed, so assume nothing. */
fsok= -1;
errno= 0;
}
ino_t latest_version(char *version, struct stat *stp)
/* Recursively read the current directory, selecting the newest image on
* the way up. (One can't use r_stat while reading a directory.)
*/
{
char name[NAME_MAX + 1];
ino_t ino, newest;
time_t mtime;
if ((ino= r_readdir(name)) == 0) { stp->st_mtime= 0; return 0; }
newest= latest_version(version, stp);
mtime= stp->st_mtime;
r_stat(ino, stp);
if (S_ISREG(stp->st_mode) && stp->st_mtime > mtime) {
newest= ino;
strcpy(version, name);
} else {
stp->st_mtime= mtime;
}
return newest;
}
char *select_image(char *image)
/* Look image up on the filesystem, if it is a file then we're done, but
* if its a directory then we want the newest file in that directory. If
* it doesn't exist at all, then see if it is 'number:number' and get the
* image from that absolute offset off the disk.
*/
{
ino_t image_ino;
struct stat st;
image= strcpy(malloc((strlen(image) + 1 + NAME_MAX + 1)
* sizeof(char)), image);
if (fsok == -1) fsok= r_super(&block_size) != 0;
if (!fsok || (image_ino= r_lookup(ROOT_INO, image)) == 0) {
char *size;
if (numprefix(image, &size) && *size++ == ':'
&& numeric(size)) {
vir2sec= flat_vir2sec;
image_off= a2l(image);
image_size= a2l(size);
strcpy(image, "Minix");
return image;
}
if (!fsok)
printf("No image selected\n");
else
printf("Can't load %s: %s\n", image, unix_err(errno));
goto bail_out;
}
r_stat(image_ino, &st);
if (!S_ISREG(st.st_mode)) {
char *version= image + strlen(image);
char dots[NAME_MAX + 1];
if (!S_ISDIR(st.st_mode)) {
printf("%s: %s\n", image, unix_err(ENOTDIR));
goto bail_out;
}
(void) r_readdir(dots);
(void) r_readdir(dots); /* "." & ".." */
*version++= '/';
*version= 0;
if ((image_ino= latest_version(version, &st)) == 0) {
printf("There are no images in %s\n", image);
goto bail_out;
}
r_stat(image_ino, &st);
}
vir2sec= file_vir2sec;
image_size= (st.st_size + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
return image;
bail_out:
free(image);
return nil;
}
void bootminix(void)
/* Load Minix and run it. (Given the size of this program it is surprising
* that it ever gets to that.)
*/
{
char *image;
if ((image= select_image(b_value("image"))) == nil) return;
exec_image(image);
switch (errno) {
case ENOEXEC:
printf("%s contains a bad program header\n", image);
break;
case ENOMEM:
printf("Not enough memory to load %s\n", image);
break;
case EIO:
printf("Unsuspected EOF on %s\n", image);
case 0:
/* No error or error already reported. */;
}
free(image);
}
/*
* $PchId: bootimage.c,v 1.10 2002/02/27 19:39:09 philip Exp $
*/

1369
boot/doshead.s Executable file

File diff suppressed because it is too large Load Diff

13
boot/image.h Executable file
View File

@@ -0,0 +1,13 @@
/* image.h - Info between installboot and boot. Author: Kees J. Bot
*/
#define IM_NAME_MAX 63
struct image_header {
char name[IM_NAME_MAX + 1]; /* Null terminated. */
struct exec process;
};
/*
* $PchId: image.h,v 1.4 1995/11/27 22:23:12 philip Exp $
*/

833
boot/installboot.c Executable file
View File

@@ -0,0 +1,833 @@
/* installboot 3.0 - Make a device bootable Author: Kees J. Bot
* 21 Dec 1991
*
* Either make a device bootable or make an image from kernel, mm, fs, etc.
*/
#define nil 0
#define _POSIX_SOURCE 1
#define _MINIX 1
#include <stdio.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <a.out.h>
#include <minix/config.h>
#include <minix/const.h>
#include <minix/partition.h>
#include <minix/u64.h>
#include "rawfs.h"
#include "image.h"
#define BOOTBLOCK 0 /* Of course */
#define SECTOR_SIZE 512 /* Disk sector size. */
#define RATIO(b) ((b)/SECTOR_SIZE)
#define SIGNATURE 0xAA55 /* Boot block signature. */
#define BOOT_MAX 64 /* Absolute maximum size of secondary boot */
#define SIGPOS 510 /* Where to put signature word. */
#define PARTPOS 446 /* Offset to the partition table in a master
* boot block.
*/
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
#define control(c) between('\0', (c), '\37')
#define BOOT_BLOCK_SIZE 1024
void report(char *label)
/* installboot: label: No such file or directory */
{
fprintf(stderr, "installboot: %s: %s\n", label, strerror(errno));
}
void fatal(char *label)
{
report(label);
exit(1);
}
char *basename(char *name)
/* Return the last component of name, stripping trailing slashes from name.
* Precondition: name != "/". If name is prefixed by a label, then the
* label is copied to the basename too.
*/
{
static char base[IM_NAME_MAX];
char *p, *bp= base;
if ((p= strchr(name, ':')) != nil) {
while (name <= p && bp < base + IM_NAME_MAX - 1)
*bp++ = *name++;
}
for (;;) {
if ((p= strrchr(name, '/')) == nil) { p= name; break; }
if (*++p != 0) break;
*--p= 0;
}
while (*p != 0 && bp < base + IM_NAME_MAX - 1) *bp++ = *p++;
*bp= 0;
return base;
}
void bread(FILE *f, char *name, void *buf, size_t len)
/* Read len bytes. Don't dare return without them. */
{
if (len > 0 && fread(buf, len, 1, f) != 1) {
if (ferror(f)) fatal(name);
fprintf(stderr, "installboot: Unexpected EOF on %s\n", name);
exit(1);
}
}
void bwrite(FILE *f, char *name, void *buf, size_t len)
{
if (len > 0 && fwrite(buf, len, 1, f) != 1) fatal(name);
}
long total_text= 0, total_data= 0, total_bss= 0;
int making_image= 0;
void read_header(int talk, char *proc, FILE *procf, struct image_header *ihdr)
/* Read the a.out header of a program and check it. If procf happens to be
* nil then the header is already in *image_hdr and need only be checked.
*/
{
int n, big= 0;
static int banner= 0;
struct exec *phdr= &ihdr->process;
if (procf == nil) {
/* Header already present. */
n= phdr->a_hdrlen;
} else {
memset(ihdr, 0, sizeof(*ihdr));
/* Put the basename of proc in the header. */
strncpy(ihdr->name, basename(proc), IM_NAME_MAX);
/* Read the header. */
n= fread(phdr, sizeof(char), A_MINHDR, procf);
if (ferror(procf)) fatal(proc);
}
if (n < A_MINHDR || BADMAG(*phdr)) {
fprintf(stderr, "installboot: %s is not an executable\n", proc);
exit(1);
}
/* Get the rest of the exec header. */
if (procf != nil) {
bread(procf, proc, ((char *) phdr) + A_MINHDR,
phdr->a_hdrlen - A_MINHDR);
}
if (talk && !banner) {
printf(" text data bss size\n");
banner= 1;
}
if (talk) {
printf("%8ld%8ld%8ld%9ld %s\n",
phdr->a_text, phdr->a_data, phdr->a_bss,
phdr->a_text + phdr->a_data + phdr->a_bss, proc);
}
total_text+= phdr->a_text;
total_data+= phdr->a_data;
total_bss+= phdr->a_bss;
if (phdr->a_cpu == A_I8086) {
long data= phdr->a_data + phdr->a_bss;
if (!(phdr->a_flags & A_SEP)) data+= phdr->a_text;
if (phdr->a_text >= 65536) big|= 1;
if (data >= 65536) big|= 2;
}
if (big) {
fprintf(stderr,
"%s will crash, %s%s%s segment%s larger then 64K\n",
proc,
big & 1 ? "text" : "",
big == 3 ? " and " : "",
big & 2 ? "data" : "",
big == 3 ? "s are" : " is");
}
}
void padimage(char *image, FILE *imagef, int n)
/* Add n zeros to image to pad it to a sector boundary. */
{
while (n > 0) {
if (putc(0, imagef) == EOF) fatal(image);
n--;
}
}
#define align(n) (((n) + ((SECTOR_SIZE) - 1)) & ~((SECTOR_SIZE) - 1))
void copyexec(char *proc, FILE *procf, char *image, FILE *imagef, long n)
/* Copy n bytes from proc to image padded to fill a sector. */
{
int pad, c;
/* Compute number of padding bytes. */
pad= align(n) - n;
while (n > 0) {
if ((c= getc(procf)) == EOF) {
if (ferror(procf)) fatal(proc);
fprintf(stderr, "installboot: premature EOF on %s\n",
proc);
exit(1);
}
if (putc(c, imagef) == EOF) fatal(image);
n--;
}
padimage(image, imagef, pad);
}
void make_image(char *image, char **procv)
/* Collect a set of files in an image, each "segment" is nicely padded out
* to SECTOR_SIZE, so it may be read from disk into memory without trickery.
*/
{
FILE *imagef, *procf;
char *proc, *file;
int procn;
struct image_header ihdr;
struct exec phdr;
struct stat st;
making_image= 1;
if ((imagef= fopen(image, "w")) == nil) fatal(image);
for (procn= 0; (proc= *procv++) != nil; procn++) {
/* Remove the label from the file name. */
if ((file= strchr(proc, ':')) != nil) file++; else file= proc;
/* Real files please, may need to seek. */
if (stat(file, &st) < 0
|| (errno= EISDIR, !S_ISREG(st.st_mode))
|| (procf= fopen(file, "r")) == nil
) fatal(proc);
/* Read a.out header. */
read_header(1, proc, procf, &ihdr);
/* Scratch. */
phdr= ihdr.process;
/* The symbol table is always stripped off. */
ihdr.process.a_syms= 0;
ihdr.process.a_flags &= ~A_NSYM;
/* Write header padded to fill a sector */
bwrite(imagef, image, &ihdr, sizeof(ihdr));
padimage(image, imagef, SECTOR_SIZE - sizeof(ihdr));
/* A page aligned executable needs the header in text. */
if (phdr.a_flags & A_PAL) {
rewind(procf);
phdr.a_text+= phdr.a_hdrlen;
}
/* Copy text and data of proc to image. */
if (phdr.a_flags & A_SEP) {
/* Separate I&D: pad text & data separately. */
copyexec(proc, procf, image, imagef, phdr.a_text);
copyexec(proc, procf, image, imagef, phdr.a_data);
} else {
/* Common I&D: keep text and data together. */
copyexec(proc, procf, image, imagef,
phdr.a_text + phdr.a_data);
}
/* Done with proc. */
(void) fclose(procf);
}
/* Done with image. */
if (fclose(imagef) == EOF) fatal(image);
printf(" ------ ------ ------ -------\n");
printf("%8ld%8ld%8ld%9ld total\n",
total_text, total_data, total_bss,
total_text + total_data + total_bss);
}
void extractexec(FILE *imagef, char *image, FILE *procf, char *proc,
long count, off_t *alen)
/* Copy a segment of an executable. It is padded to a sector in image. */
{
char buf[SECTOR_SIZE];
while (count > 0) {
bread(imagef, image, buf, sizeof(buf));
*alen-= sizeof(buf);
bwrite(procf, proc, buf,
count < sizeof(buf) ? (size_t) count : sizeof(buf));
count-= sizeof(buf);
}
}
void extract_image(char *image)
/* Extract the executables from an image. */
{
FILE *imagef, *procf;
off_t len;
struct stat st;
struct image_header ihdr;
struct exec phdr;
char buf[SECTOR_SIZE];
if (stat(image, &st) < 0) fatal(image);
/* Size of the image. */
len= S_ISREG(st.st_mode) ? st.st_size : -1;
if ((imagef= fopen(image, "r")) == nil) fatal(image);
while (len != 0) {
/* Extract a program, first sector is an extended header. */
bread(imagef, image, buf, sizeof(buf));
len-= sizeof(buf);
memcpy(&ihdr, buf, sizeof(ihdr));
phdr= ihdr.process;
/* Check header. */
read_header(1, ihdr.name, nil, &ihdr);
if ((procf= fopen(ihdr.name, "w")) == nil) fatal(ihdr.name);
if (phdr.a_flags & A_PAL) {
/* A page aligned process contains a header in text. */
phdr.a_text+= phdr.a_hdrlen;
} else {
bwrite(procf, ihdr.name, &ihdr.process, phdr.a_hdrlen);
}
/* Extract text and data segments. */
if (phdr.a_flags & A_SEP) {
extractexec(imagef, image, procf, ihdr.name,
phdr.a_text, &len);
extractexec(imagef, image, procf, ihdr.name,
phdr.a_data, &len);
} else {
extractexec(imagef, image, procf, ihdr.name,
phdr.a_text + phdr.a_data, &len);
}
if (fclose(procf) == EOF) fatal(ihdr.name);
}
}
int rawfd; /* File descriptor to open device. */
char *rawdev; /* Name of device. */
void readblock(off_t blk, char *buf, int block_size)
/* For rawfs, so that it can read blocks. */
{
int n;
if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
|| (n= read(rawfd, buf, block_size)) < 0
) fatal(rawdev);
if (n < block_size) {
fprintf(stderr, "installboot: Unexpected EOF on %s\n", rawdev);
exit(1);
}
}
void writeblock(off_t blk, char *buf, int block_size)
/* Add a function to write blocks for local use. */
{
if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
|| write(rawfd, buf, block_size) < 0
) fatal(rawdev);
}
int raw_install(char *file, off_t *start, off_t *len, int block_size)
/* Copy bootcode or an image to the boot device at the given absolute disk
* block number. This "raw" installation is used to place bootcode and
* image on a disk without a filesystem to make a simple boot disk. Useful
* in automated scripts for J. Random User.
* Note: *len == 0 when an image is read. It is set right afterwards.
*/
{
static char buf[MAX_BLOCK_SIZE]; /* Nonvolatile block buffer. */
FILE *f;
off_t sec;
unsigned long devsize;
static int banner= 0;
struct partition entry;
/* See if the device has a maximum size. */
devsize= -1;
if (ioctl(rawfd, DIOCGETP, &entry) == 0) devsize= cv64ul(entry.size);
if ((f= fopen(file, "r")) == nil) fatal(file);
/* Copy sectors from file onto the boot device. */
sec= *start;
do {
int off= sec % RATIO(BOOT_BLOCK_SIZE);
if (fread(buf + off * SECTOR_SIZE, 1, SECTOR_SIZE, f) == 0)
break;
if (sec >= devsize) {
fprintf(stderr,
"installboot: %s can't be attached to %s\n",
file, rawdev);
return 0;
}
if (off == RATIO(BOOT_BLOCK_SIZE) - 1) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
} while (++sec != *start + *len);
if (ferror(f)) fatal(file);
(void) fclose(f);
/* Write a partial block, this may be the last image. */
if (sec % RATIO(BOOT_BLOCK_SIZE) != 0) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
if (!banner) {
printf(" sector length\n");
banner= 1;
}
*len= sec - *start;
printf("%8ld%8ld %s\n", *start, *len, file);
*start= sec;
return 1;
}
enum howto { FS, BOOT };
void make_bootable(enum howto how, char *device, char *bootblock,
char *bootcode, char **imagev)
/* Install bootblock on the bootsector of device with the disk addresses to
* bootcode patched into the data segment of bootblock. "How" tells if there
* should or shoudn't be a file system on the disk. The images in the imagev
* vector are added to the end of the device.
*/
{
char buf[MAX_BLOCK_SIZE + 256], *adrp, *parmp;
struct fileaddr {
off_t address;
int count;
} bootaddr[BOOT_MAX + 1], *bap= bootaddr;
struct exec boothdr;
struct image_header dummy;
struct stat st;
ino_t ino;
off_t sector, max_sector;
FILE *bootf;
off_t addr, fssize, pos, len;
char *labels, *label, *image;
int nolabel;
int block_size = 0;
/* Open device and set variables for readblock. */
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
/* Read and check the superblock. */
fssize= r_super(&block_size);
switch (how) {
case FS:
if (fssize == 0) {
fprintf(stderr,
"installboot: %s is not a Minix file system\n",
device);
exit(1);
}
break;
case BOOT:
if (fssize != 0) {
int s;
printf("%s contains a file system!\n", device);
printf("Scribbling in 10 seconds");
for (s= 0; s < 10; s++) {
fputc('.', stdout);
fflush(stdout);
sleep(1);
}
fputc('\n', stdout);
}
fssize= 1; /* Just a boot block. */
}
if (how == FS) {
/* See if the boot code can be found on the file system. */
if ((ino= r_lookup(ROOT_INO, bootcode)) == 0) {
if (errno != ENOENT) fatal(bootcode);
}
} else {
/* Boot code must be attached at the end. */
ino= 0;
}
if (ino == 0) {
/* For a raw installation, we need to copy the boot code onto
* the device, so we need to look at the file to be copied.
*/
if (stat(bootcode, &st) < 0) fatal(bootcode);
if ((bootf= fopen(bootcode, "r")) == nil) fatal(bootcode);
} else {
/* Boot code is present in the file system. */
r_stat(ino, &st);
/* Get the header from the first block. */
if ((addr= r_vir2abs((off_t) 0)) == 0) {
boothdr.a_magic[0]= !A_MAGIC0;
} else {
readblock(addr, buf, block_size);
memcpy(&boothdr, buf, sizeof(struct exec));
}
bootf= nil;
dummy.process= boothdr;
}
/* See if it is an executable (read_header does the check). */
read_header(0, bootcode, bootf, &dummy);
boothdr= dummy.process;
if (bootf != nil) fclose(bootf);
/* Get all the sector addresses of the secondary boot code. */
max_sector= (boothdr.a_hdrlen + boothdr.a_text
+ boothdr.a_data + SECTOR_SIZE - 1) / SECTOR_SIZE;
if (max_sector > BOOT_MAX * RATIO(block_size)) {
fprintf(stderr, "installboot: %s is way too big\n", bootcode);
exit(0);
}
/* Determine the addresses to the boot code to be patched into the
* boot block.
*/
bap->count= 0; /* Trick to get the address recording going. */
for (sector= 0; sector < max_sector; sector++) {
if (ino == 0) {
addr= fssize + (sector / RATIO(block_size));
} else
if ((addr= r_vir2abs(sector / RATIO(block_size))) == 0) {
fprintf(stderr, "installboot: %s has holes!\n",
bootcode);
exit(1);
}
addr= (addr * RATIO(block_size)) + (sector % RATIO(block_size));
/* First address of the addresses array? */
if (bap->count == 0) bap->address= addr;
/* Paste sectors together in a multisector read. */
if (bap->address + bap->count == addr)
bap->count++;
else {
/* New address. */
bap++;
bap->address= addr;
bap->count= 1;
}
}
(++bap)->count= 0; /* No more. */
/* Get the boot block and patch the pieces in. */
readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
if ((bootf= fopen(bootblock, "r")) == nil) fatal(bootblock);
read_header(0, bootblock, bootf, &dummy);
boothdr= dummy.process;
if (boothdr.a_text + boothdr.a_data +
4 * (bap - bootaddr) + 1 > PARTPOS) {
fprintf(stderr,
"installboot: %s + addresses to %s don't fit in the boot sector\n",
bootblock, bootcode);
fprintf(stderr,
"You can try copying/reinstalling %s to defragment it\n",
bootcode);
exit(1);
}
/* All checks out right. Read bootblock into the boot block! */
bread(bootf, bootblock, buf, boothdr.a_text + boothdr.a_data);
(void) fclose(bootf);
/* Patch the addresses in. */
adrp= buf + (int) (boothdr.a_text + boothdr.a_data);
for (bap= bootaddr; bap->count != 0; bap++) {
*adrp++= bap->count;
*adrp++= (bap->address >> 0) & 0xFF;
*adrp++= (bap->address >> 8) & 0xFF;
*adrp++= (bap->address >> 16) & 0xFF;
}
/* Zero count stops bootblock's reading loop. */
*adrp++= 0;
if (bap > bootaddr+1) {
printf("%s and %d addresses to %s patched into %s\n",
bootblock, (int)(bap - bootaddr), bootcode, device);
}
/* Boot block signature. */
buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
/* Sector 2 of the boot block is used for boot parameters, initially
* filled with null commands (newlines). Initialize it only if
* necessary.
*/
for (parmp= buf + SECTOR_SIZE; parmp < buf + 2*SECTOR_SIZE; parmp++) {
if (*imagev != nil || (control(*parmp) && *parmp != '\n')) {
/* Param sector must be initialized. */
memset(buf + SECTOR_SIZE, '\n', SECTOR_SIZE);
break;
}
}
/* Offset to the end of the file system to add boot code and images. */
pos= fssize * RATIO(block_size);
if (ino == 0) {
/* Place the boot code onto the boot device. */
len= max_sector;
if (!raw_install(bootcode, &pos, &len, block_size)) {
if (how == FS) {
fprintf(stderr,
"\t(Isn't there a copy of %s on %s that can be used?)\n",
bootcode, device);
}
exit(1);
}
}
parmp= buf + SECTOR_SIZE;
nolabel= 0;
if (how == BOOT) {
/* A boot only disk needs to have floppies swapped. */
strcpy(parmp,
"trailer()echo \\nInsert the root diskette then hit RETURN\\n\\w\\c\n");
parmp+= strlen(parmp);
}
while ((labels= *imagev++) != nil) {
/* Place each kernel image on the boot device. */
if ((image= strchr(labels, ':')) != nil)
*image++= 0;
else {
if (nolabel) {
fprintf(stderr,
"installboot: Only one image can be the default\n");
exit(1);
}
nolabel= 1;
image= labels;
labels= nil;
}
len= 0;
if (!raw_install(image, &pos, &len, block_size)) exit(1);
if (labels == nil) {
/* Let this image be the default. */
sprintf(parmp, "image=%ld:%ld\n", pos-len, len);
parmp+= strlen(parmp);
}
while (labels != nil) {
/* Image is prefixed by a comma separated list of
* labels. Define functions to select label and image.
*/
label= labels;
if ((labels= strchr(labels, ',')) != nil) *labels++ = 0;
sprintf(parmp,
"%s(%c){label=%s;image=%ld:%ld;echo %s kernel selected;menu}\n",
label,
between('A', label[0], 'Z')
? label[0]-'A'+'a' : label[0],
label, pos-len, len, label);
parmp+= strlen(parmp);
}
if (parmp > buf + block_size) {
fprintf(stderr,
"installboot: Out of parameter space, too many images\n");
exit(1);
}
}
/* Install boot block. */
writeblock((off_t) BOOTBLOCK, buf, 1024);
if (pos > fssize * RATIO(block_size)) {
/* Tell the total size of the data on the device. */
printf("%16ld (%ld kb) total\n", pos,
(pos + RATIO(block_size) - 1) / RATIO(block_size));
}
}
void install_master(char *device, char *masterboot, char **guide)
/* Booting a hard disk is a two stage process: The master bootstrap in sector
* 0 loads the bootstrap from sector 0 of the active partition which in turn
* starts the operating system. This code installs such a master bootstrap
* on a hard disk. If guide[0] is non-null then the master bootstrap is
* guided into booting a certain device.
*/
{
FILE *masf;
unsigned long size;
struct stat st;
static char buf[MAX_BLOCK_SIZE];
/* Open device. */
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
/* Open the master boot code. */
if ((masf= fopen(masterboot, "r")) == nil) fatal(masterboot);
/* See if the user is cloning a device. */
if (fstat(fileno(masf), &st) >=0 && S_ISBLK(st.st_mode))
size= PARTPOS;
else {
/* Read and check header otherwise. */
struct image_header ihdr;
read_header(1, masterboot, masf, &ihdr);
size= ihdr.process.a_text + ihdr.process.a_data;
}
if (size > PARTPOS) {
fprintf(stderr, "installboot: %s is too big\n", masterboot);
exit(1);
}
/* Read the master boot block, patch it, write. */
readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
memset(buf, 0, PARTPOS);
(void) bread(masf, masterboot, buf, size);
if (guide[0] != nil) {
/* Fixate partition to boot. */
char *keys= guide[0];
char *logical= guide[1];
size_t i;
int logfd;
u32_t offset;
struct partition geometry;
/* A string of digits to be seen as keystrokes. */
i= 0;
do {
if (!between('0', keys[i], '9')) {
fprintf(stderr,
"installboot: bad guide keys '%s'\n",
keys);
exit(1);
}
} while (keys[++i] != 0);
if (size + i + 1 > PARTPOS) {
fprintf(stderr,
"installboot: not enough space after '%s' for '%s'\n",
masterboot, keys);
exit(1);
}
memcpy(buf + size, keys, i);
size += i;
buf[size]= '\r';
if (logical != nil) {
if ((logfd= open(logical, O_RDONLY)) < 0
|| ioctl(logfd, DIOCGETP, &geometry) < 0
) {
fatal(logical);
}
offset= div64u(geometry.base, SECTOR_SIZE);
if (size + 5 > PARTPOS) {
fprintf(stderr,
"installboot: not enough space "
"after '%s' for '%s' and an offset "
"to '%s'\n",
masterboot, keys, logical);
exit(1);
}
buf[size]= '#';
memcpy(buf+size+1, &offset, 4);
}
}
/* Install signature. */
buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
writeblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
}
void usage(void)
{
fprintf(stderr,
"Usage: installboot -i(mage) image kernel mm fs ... init\n"
" installboot -(e)x(tract) image\n"
" installboot -d(evice) device bootblock boot [image ...]\n"
" installboot -b(oot) device bootblock boot image ...\n"
" installboot -m(aster) device masterboot [keys [logical]]\n");
exit(1);
}
int isoption(char *option, char *test)
/* Check if the option argument is equals "test". Also accept -i as short
* for -image, and the special case -x for -extract.
*/
{
if (strcmp(option, test) == 0) return 1;
if (option[0] != '-' && strlen(option) != 2) return 0;
if (option[1] == test[1]) return 1;
if (option[1] == 'x' && test[1] == 'e') return 1;
return 0;
}
int main(int argc, char **argv)
{
if (argc < 2) usage();
if (argc >= 4 && isoption(argv[1], "-image")) {
make_image(argv[2], argv + 3);
} else
if (argc == 3 && isoption(argv[1], "-extract")) {
extract_image(argv[2]);
} else
if (argc >= 5 && isoption(argv[1], "-device")) {
make_bootable(FS, argv[2], argv[3], argv[4], argv + 5);
} else
if (argc >= 6 && isoption(argv[1], "-boot")) {
make_bootable(BOOT, argv[2], argv[3], argv[4], argv + 5);
} else
if ((4 <= argc && argc <= 6) && isoption(argv[1], "-master")) {
install_master(argv[2], argv[3], argv + 4);
} else {
usage();
}
exit(0);
}
/*
* $PchId: installboot.c,v 1.10 2000/08/13 22:07:50 philip Exp $
*/

261
boot/jumpboot.s Executable file
View File

@@ -0,0 +1,261 @@
! jumpboot 1.0 - Jump to another bootstrap Author: Kees J. Bot
! 14 Apr 1999
!
! This code may be placed into any free boot sector, like the first sector
! of an extended partition, a file system partition other than the root,
! or even the master bootstrap. It will load and run another bootstrap whose
! disk, partition, and slice number (not necessarily all three) are patched
! into this code by installboot. If the ALT key is held down when this code
! is booted then you can type the disk, partition, and slice numbers manually.
! The manual interface is default if no numbers are patched in by installboot.
!
o32 = 0x66 ! This assembler doesn't know 386 extensions
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
BUFFER = 0x0600 ! First free memory
PART_TABLE = 446 ! Location of partition table within master
PENTRYSIZE = 16 ! Size of one partition table entry
MAGIC = 510 ! Location of the AA55 magic number
! <ibm/partition.h>:
MINIX_PART = 0x81
sysind = 4
lowsec = 8
.text
! Find and load another bootstrap and jump to it.
jumpboot:
xor ax, ax
mov ds, ax
mov es, ax
cli
mov ss, ax ! ds = es = ss = Vector segment
mov sp, #LOADOFF
sti
! Move this code to safety, then jump to it.
mov si, sp ! si = start of this code
mov di, #BUFFER ! di = Buffer area
mov cx, #512/2 ! One sector
cld
rep movs
jmpf BUFFER+migrate, 0 ! To safety
migrate:
mov bp, #BUFFER+guide ! Patched guiding characters
altkey:
movb ah, #0x02 ! Keyboard shift status
int 0x16
testb al, #0x08 ! Bit 3 = ALT key
jz noalt ! ALT key pressed?
again:
mov bp, #zero ! Ignore patched stuff
noalt:
! Follow guide characters to find the boot partition.
call print
.ascii "d?\b\0" ! Initial greeting
! Disk number?
disk:
movb dl, #0x80 - 0x30 ! Prepare to add an ASCII digit
call getch ! Get number to tell which disk
addb dl, al ! dl = 0x80 + (al - '0')
jns n0nboot ! Result should be >= 0x80
mov si, #BUFFER+zero-lowsec ! si = where lowsec(si) is zero
cmpb (bp), #0x23 ! Next guide character is '#'?
jne notlogical
lea si, 1-lowsec(bp) ! Logical sector offset follows '#'
notlogical:
call load ! Load chosen sector of chosen disk
cmpb (bp), #0x23
je boot ! Run bootstrap if a logical is chosen
call print ! Intro to partition number
.ascii "p?\b\0"
part:
call getch ! Get character to tell partition
call gettable ! Get partition table
call sort ! Sort partition table
call choose_load ! Compute chosen entry and load
cmpb sysind(si), #MINIX_PART ! Minix subpartition table possible?
jne waitboot
call print ! Intro to slice number
.ascii "s?\b\0"
slice:
call getch ! Get character to tell slice
call gettable ! Get partition table
call choose_load ! Compute chosen entry and load
waitboot:
call print ! Intro to nothing
.ascii " ?\b\0"
call getch ! Supposed to type RETURN now
n0nboot:jmp nonboot ! Sorry, can't go further
! Get a character, either the patched-in, or one from the keyboard.
getch:
movb al, (bp) ! Get patched-in character
testb al, al
jz getkey
inc bp
jmp gotkey
getkey: xorb ah, ah ! Wait for keypress
int 0x16
gotkey: testb dl, dl ! Ignore CR if disk number not yet set
jns putch
cmpb al, #0x0D ! Carriage return?
je boot
!jmp putch
! Print a character
putch: movb ah, #0x0E ! Print character in teletype mode
mov bx, #0x0001 ! Page 0, foreground color
int 0x10
ret
! Print a message.
print: mov cx, si ! Save si
pop si ! si = String following 'call print'
prnext: lodsb ! al = *si++ is char to be printed
testb al, al ! Null marks end
jz prdone
call putch
jmp prnext
prdone: xchg si, cx ! Restore si
jmp (cx) ! Continue after the string
! Return typed (or in patched data) means to run the bootstrap now in core!
boot:
call print ! Make line on screen look proper
.ascii "\b \r\n\0"
jmp LOADOFF-BUFFER ! Jump to LOADOFF
! Compute address of chosen partition entry from choice al into si, then
! continue to load the boot sector of that partition.
choose_load:
subb al, #0x30 ! al -= '0'
cmpb al, #4 ! Only four partitions
ja n0nboot
movb ah, #PENTRYSIZE
mulb ah ! al *= PENTRYSIZE
add ax, #BUFFER+PART_TABLE
mov si, ax ! si = &part_table[al - '0']
movb al, sysind(si) ! System indicator
testb al, al ! Unused partition?
jz n0nboot
!jmp load ! Continue to load boot sector
! Load boot sector of the current partition.
load:
push dx ! Save drive code
push es ! Next call sets es
movb ah, #0x08 ! Code for drive parameters
int 0x13
pop es
andb cl, #0x3F ! cl = max sector number (1-origin)
incb dh ! dh = 1 + max head number (0-origin)
movb al, cl ! al = cl = sectors per track
mulb dh ! dh = heads, ax = heads * sectors
mov bx, ax ! bx = sectors per cylinder = heads * sectors
mov ax, lowsec+0(si)
mov dx, lowsec+2(si) ! dx:ax = sector within drive
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
jae bigdisk
div bx ! ax = cylinder, dx = sector within cylinder
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
movb ch, dl ! ch = low 8 bits of cylinder
divb cl ! al = head, ah = sector (0-origin)
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
shr dx, #1
shr dx, #1 ! dl[6..7] = high cylinder
orb dl, ah ! dl[0..5] = sector (0-origin)
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
incb cl ! cl[0..5] = sector (1-origin)
pop dx ! Restore drive code in dl
movb dh, al ! dh = al = head
mov bx, #LOADOFF ! es:bx = where sector is loaded
mov ax, #0x0201 ! ah = Code for read / al = one sector
int 0x13
jmp rdeval ! Evaluate read result
bigdisk:
mov bx, dx ! bx:ax = dx:ax = sector to read
pop dx ! Restore drive code in dl
push si ! Save si
mov si, #BUFFER+ext_rw ! si = extended read/write parameter packet
mov 8(si), ax ! Starting block number = bx:ax
mov 10(si), bx
movb ah, #0x42 ! Extended read
int 0x13
pop si ! Restore si to point to partition entry
!jmp rdeval
rdeval:
jnc rdok
rderr:
call print
.ascii "\r\nRead error\r\n\0"
jmp again
rdok:
cmp LOADOFF+MAGIC, #0xAA55
je sigok ! Signature ok?
nonboot:
call print
.ascii "\r\nNot bootable\r\n\0"
jmp again
sigok:
ret
! Get the partition table into my space.
gettable:
mov si, #LOADOFF+PART_TABLE
mov di, #BUFFER+PART_TABLE
mov cx, #4*PENTRYSIZE/2
rep movs
ret
! Sort the partition table.
sort:
mov cx, #4 ! Four times is enough to sort
bubble: mov si, #BUFFER+PART_TABLE ! First table entry
bubble1:lea di, PENTRYSIZE(si) ! Next entry
cmpb sysind(si), ch ! Partition type, nonzero when in use
jz exchg ! Unused entries sort to the end
inuse: mov bx, lowsec+0(di)
sub bx, lowsec+0(si) ! Compute di->lowsec - si->lowsec
mov bx, lowsec+2(di)
sbb bx, lowsec+2(si)
jae order ! In order if si->lowsec <= di->lowsec
exchg: movb bl, (si)
xchgb bl, PENTRYSIZE(si) ! Exchange entries byte by byte
movb (si), bl
inc si
cmp si, di
jb exchg
order: mov si, di
cmp si, #BUFFER+PART_TABLE+3*PENTRYSIZE
jb bubble1
loop bubble
ret
.data
! Extended read/write commands require a parameter packet.
ext_rw:
.data1 0x10 ! Length of extended r/w packet
.data1 0 ! Reserved
.data2 1 ! Blocks to transfer (just one)
.data2 LOADOFF ! Buffer address offset
.data2 0 ! Buffer address segment
.data4 0 ! Starting block number low 32 bits (tbfi)
zero: .data4 0 ! Starting block number high 32 bits
.align 2
guide:
! Guide characters and possibly a logical partition number patched here by
! installboot, up to 6 bytes maximum.

218
boot/masterboot.s Executable file
View File

@@ -0,0 +1,218 @@
! masterboot 2.0 - Master boot block code Author: Kees J. Bot
!
! This code may be placed in the first sector (the boot sector) of a floppy,
! hard disk or hard disk primary partition. There it will perform the
! following actions at boot time:
!
! - If the booted device is a hard disk and one of the partitions is active
! then the active partition is booted.
!
! - Otherwise the next floppy or hard disk device is booted, trying them one
! by one.
!
! To make things a little clearer, the boot path might be:
! /dev/fd0 - Floppy disk containing data, tries fd1 then d0
! [/dev/fd1] - Drive empty
! /dev/c0d0 - Master boot block, selects active partition 2
! /dev/c0d0p2 - Submaster, selects active subpartition 0
! /dev/c0d0p2s0 - Minix bootblock, reads Boot Monitor /boot
! Minix - Started by /boot from a kernel image in /minix
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
BUFFER = 0x0600 ! First free memory
PART_TABLE = 446 ! Location of partition table within this code
PENTRYSIZE = 16 ! Size of one partition table entry
MAGIC = 510 ! Location of the AA55 magic number
! <ibm/partition>.h:
bootind = 0
sysind = 4
lowsec = 8
.text
! Find active (sub)partition, load its first sector, run it.
master:
xor ax, ax
mov ds, ax
mov es, ax
cli
mov ss, ax ! ds = es = ss = Vector segment
mov sp, #LOADOFF
sti
! Copy this code to safety, then jump to it.
mov si, sp ! si = start of this code
push si ! Also where we'll return to eventually
mov di, #BUFFER ! Buffer area
mov cx, #512/2 ! One sector
cld
rep movs
jmpf BUFFER+migrate, 0 ! To safety
migrate:
! Find the active partition
findactive:
testb dl, dl
jns nextdisk ! No bootable partitions on floppies
mov si, #BUFFER+PART_TABLE
find: cmpb sysind(si), #0 ! Partition type, nonzero when in use
jz nextpart
testb bootind(si), #0x80 ! Active partition flag in bit 7
jz nextpart ! It's not active
loadpart:
call load ! Load partition bootstrap
jc error1 ! Not supposed to fail
bootstrap:
ret ! Jump to the master bootstrap
nextpart:
add si, #PENTRYSIZE
cmp si, #BUFFER+PART_TABLE+4*PENTRYSIZE
jb find
! No active partition, tell 'em
call print
.ascii "No active partition\0"
jmp reboot
! There are no active partitions on this drive, try the next drive.
nextdisk:
incb dl ! Increment dl for the next drive
testb dl, dl
js nexthd ! Hard disk if negative
int 0x11 ! Get equipment configuration
shl ax, #1 ! Highest floppy drive # in bits 6-7
shl ax, #1 ! Now in bits 0-1 of ah
andb ah, #0x03 ! Extract bits
cmpb dl, ah ! Must be dl <= ah for drive to exist
ja nextdisk ! Otherwise try disk 0 eventually
call load0 ! Read the next floppy bootstrap
jc nextdisk ! It failed, next disk please
ret ! Jump to the next master bootstrap
nexthd: call load0 ! Read the hard disk bootstrap
error1: jc error ! No disk?
ret
! Load sector 0 from the current device. It's either a floppy bootstrap or
! a hard disk master bootstrap.
load0:
mov si, #BUFFER+zero-lowsec ! si = where lowsec(si) is zero
!jmp load
! Load sector lowsec(si) from the current device. The obvious head, sector,
! and cylinder numbers are ignored in favour of the more trustworthy absolute
! start of partition.
load:
mov di, #3 ! Three retries for floppy spinup
retry: push dx ! Save drive code
push es
push di ! Next call destroys es and di
movb ah, #0x08 ! Code for drive parameters
int 0x13
pop di
pop es
andb cl, #0x3F ! cl = max sector number (1-origin)
incb dh ! dh = 1 + max head number (0-origin)
movb al, cl ! al = cl = sectors per track
mulb dh ! dh = heads, ax = heads * sectors
mov bx, ax ! bx = sectors per cylinder = heads * sectors
mov ax, lowsec+0(si)
mov dx, lowsec+2(si)! dx:ax = sector within drive
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
jae bigdisk
div bx ! ax = cylinder, dx = sector within cylinder
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
movb ch, dl ! ch = low 8 bits of cylinder
divb cl ! al = head, ah = sector (0-origin)
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
shr dx, #1
shr dx, #1 ! dl[6..7] = high cylinder
orb dl, ah ! dl[0..5] = sector (0-origin)
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
incb cl ! cl[0..5] = sector (1-origin)
pop dx ! Restore drive code in dl
movb dh, al ! dh = al = head
mov bx, #LOADOFF ! es:bx = where sector is loaded
mov ax, #0x0201 ! Code for read, just one sector
int 0x13 ! Call the BIOS for a read
jmp rdeval ! Evaluate read result
bigdisk:
mov bx, dx ! bx:ax = dx:ax = sector to read
pop dx ! Restore drive code in dl
push si ! Save si
mov si, #BUFFER+ext_rw ! si = extended read/write parameter packet
mov 8(si), ax ! Starting block number = bx:ax
mov 10(si), bx
movb ah, #0x42 ! Extended read
int 0x13
pop si ! Restore si to point to partition entry
!jmp rdeval
rdeval:
jnc rdok ! Read succeeded
cmpb ah, #0x80 ! Disk timed out? (Floppy drive empty)
je rdbad
dec di
jl rdbad ! Retry count expired
xorb ah, ah
int 0x13 ! Reset
jnc retry ! Try again
rdbad: stc ! Set carry flag
ret
rdok: cmp LOADOFF+MAGIC, #0xAA55
jne nosig ! Error if signature wrong
ret ! Return with carry still clear
nosig: call print
.ascii "Not bootable\0"
jmp reboot
! A read error occurred, complain and hang
error:
mov si, #LOADOFF+errno+1
prnum: movb al, ah ! Error number in ah
andb al, #0x0F ! Low 4 bits
cmpb al, #10 ! A-F?
jb digit ! 0-9!
addb al, #7 ! 'A' - ':'
digit: addb (si), al ! Modify '0' in string
dec si
movb cl, #4 ! Next 4 bits
shrb ah, cl
jnz prnum ! Again if digit > 0
call print
.ascii "Read error "
errno: .ascii "00\0"
!jmp reboot
reboot:
call print
.ascii ". Hit any key to reboot.\0"
xorb ah, ah ! Wait for keypress
int 0x16
call print
.ascii "\r\n\0"
int 0x19
! Print a message.
print: pop si ! si = String following 'call print'
prnext: lodsb ! al = *si++ is char to be printed
testb al, al ! Null marks end
jz prdone
movb ah, #0x0E ! Print character in teletype mode
mov bx, #0x0001 ! Page 0, foreground color
int 0x10
jmp prnext
prdone: jmp (si) ! Continue after the string
.data
! Extended read/write commands require a parameter packet.
ext_rw:
.data1 0x10 ! Length of extended r/w packet
.data1 0 ! Reserved
.data2 1 ! Blocks to transfer (just one)
.data2 LOADOFF ! Buffer address offset
.data2 0 ! Buffer address segment
.data4 0 ! Starting block number low 32 bits (tbfi)
zero: .data4 0 ! Starting block number high 32 bits

137
boot/mkfhead.s Executable file
View File

@@ -0,0 +1,137 @@
! Mkfhead.s - DOS & BIOS support for mkfile.c Author: Kees J. Bot
! 9 May 1998
!
! This file contains the startup and low level support for the MKFILE.COM
! utility. See doshead.ack.s for more comments on .COM files.
!
.sect .text; .sect .rom; .sect .data; .sect .bss
.sect .text
.define _PSP
_PSP:
.space 256 ! Program Segment Prefix
mkfile:
cld ! C compiler wants UP
xor ax, ax ! Zero
mov di, _edata ! Start of bss is at end of data
mov cx, _end ! End of bss (begin of heap)
sub cx, di ! Number of bss bytes
shr cx, 1 ! Number of words
rep stos ! Clear bss
xor cx, cx ! cx = argc
xor bx, bx
push bx ! argv[argc] = NULL
movb bl, (_PSP+0x80) ! Argument byte count
0: movb _PSP+0x81(bx), ch ! Null terminate
dec bx
js 9f
cmpb _PSP+0x81(bx), 0x20 ! Whitespace?
jbe 0b
1: dec bx ! One argument character
js 2f
cmpb _PSP+0x81(bx), 0x20 ! More argument characters?
ja 1b
2: lea ax, _PSP+0x81+1(bx) ! Address of argument
push ax ! argv[n]
inc cx ! argc++;
test bx, bx
jns 0b ! More arguments?
9: movb _PSP+0x81(bx), ch ! Make a null string
lea ax, _PSP+0x81(bx)
push ax ! to use as argv[0]
inc cx ! Final value of argc
mov ax, sp
push ax ! argv
push cx ! argc
call _main ! main(argc, argv)
push ax
call _exit ! exit(main(argc, argv))
! int creat(const char *path, mode_t mode)
! Create a file with the old creat() call.
.define _creat
_creat:
mov bx, sp
mov dx, 2(bx) ! Filename
xor cx, cx ! Ignore mode, always read-write
movb ah, 0x3C ! "CREAT"
dos: int 0x21 ! ax = creat(path, 0666);
jc seterrno
ret
seterrno:
mov (_errno), ax ! Set errno to the DOS error code
mov ax, -1
cwd ! return -1L;
ret
! int open(const char *path, int oflag)
! Open a file with the oldfashioned two-argument open() call.
.define _open
_open:
mov bx, sp
mov dx, 2(bx) ! Filename
movb al, 4(bx) ! O_RDONLY, O_WRONLY, O_RDWR
movb ah, 0x3D ! "OPEN"
jmp dos
! int close(int fd)
! Close an open file.
.define _close
_close:
mov bx, sp
mov bx, 2(bx) ! bx = file handle
movb ah, 0x3E ! "CLOSE"
jmp dos
! void exit(int status)
! void _exit(int status)
! Return to DOS.
.define _exit, __exit, ___exit
_exit:
__exit:
___exit:
pop ax
pop ax ! al = status
movb ah, 0x4C ! "EXIT"
int 0x21
hlt
! ssize_t read(int fd, void *buf, size_t n)
! Read bytes from an open file.
.define _read
_read:
mov bx, sp
mov cx, 6(bx)
mov dx, 4(bx)
mov bx, 2(bx)
movb ah, 0x3F ! "READ"
jmp dos
! ssize_t write(int fd, const void *buf, size_t n)
! Write bytes to an open file.
.define _write
_write:
mov bx, sp
mov cx, 6(bx)
mov dx, 4(bx)
mov bx, 2(bx)
movb ah, 0x40 ! "WRITE"
jmp dos
! off_t lseek(int fd, off_t offset, int whence)
! Set file position for read or write.
.define _lseek
_lseek:
mov bx, sp
movb al, 8(bx) ! SEEK_SET, SEEK_CUR, SEEK_END
mov dx, 4(bx)
mov cx, 6(bx) ! cx:dx = offset
mov bx, 2(bx)
movb ah, 0x42 ! "LSEEK"
jmp dos
!
! $PchId: mkfhead.ack.s,v 1.3 1999/01/14 21:17:06 philip Exp $

180
boot/mkfile.c Executable file
View File

@@ -0,0 +1,180 @@
/* mkfile 1.0 - create a file under DOS for use as a Minix "disk".
* Author: Kees J. Bot
* 9 May 1998
*/
#define nil 0
#include <sys/types.h>
#include <string.h>
#include <limits.h>
/* Stuff normally found in <unistd.h>, <errno.h>, etc. */
extern int errno;
int creat(const char *file, int mode);
int open(const char *file, int oflag);
off_t lseek(int fd, off_t offset, int whence);
ssize_t write(int fd, const char *buf, size_t len);
void exit(int status);
int printf(const char *fmt, ...);
#define O_WRONLY 1
#define SEEK_SET 0
#define SEEK_END 2
/* Kernel printf requires a putk() function. */
int putk(int c)
{
char ch = c;
if (c == 0) return;
if (c == '\n') putk('\r');
(void) write(2, &ch, 1);
}
static void usage(void)
{
printf("Usage: mkfile <size>[gmk] <file>\n"
"(Example sizes, all 50 meg: 52428800, 51200k, 50m)\n");
exit(1);
}
char *strerror(int err)
/* Translate some DOS error numbers to text. */
{
static struct errlist {
int err;
char *what;
} errlist[] = {
{ 0, "No error" },
{ 1, "Function number invalid" },
{ 2, "File not found" },
{ 3, "Path not found" },
{ 4, "Too many open files" },
{ 5, "Access denied" },
{ 6, "Invalid handle" },
{ 12, "Access code invalid" },
{ 39, "Insufficient disk space" },
};
struct errlist *ep;
static char unknown[]= "Error 65535";
unsigned e;
char *p;
for (ep= errlist; ep < errlist + sizeof(errlist)/sizeof(errlist[0]);
ep++) {
if (ep->err == err) return ep->what;
}
p= unknown + sizeof(unknown) - 1;
e= err;
do *--p= '0' + (e % 10); while ((e /= 10) > 0);
strcpy(unknown + 6, p);
return unknown;
}
int main(int argc, char **argv)
{
int i;
static char buf[512];
unsigned long size, mul;
off_t offset;
char *cp;
int fd;
char *file;
if (argc != 3) usage();
cp= argv[1];
size= 0;
while ((unsigned) (*cp - '0') < 10) {
unsigned d= *cp++ - '0';
if (size <= (ULONG_MAX-9) / 10) {
size= size * 10 + d;
} else {
size= ULONG_MAX;
}
}
if (cp == argv[1]) usage();
while (*cp != 0) {
mul = 1;
switch (*cp++) {
case 'G':
case 'g': mul *= 1024;
case 'M':
case 'm': mul *= 1024;
case 'K':
case 'k': mul *= 1024;
case 'B':
case 'b': break;
default: usage();
}
if (size <= ULONG_MAX / mul) {
size *= mul;
} else {
size= ULONG_MAX;
}
}
if (size > 1024L*1024*1024) {
printf("mkfile: A file size over 1G is a bit too much\n");
exit(1);
}
/* Open existing file, or create a new file. */
file= argv[2];
if ((fd= open(file, O_WRONLY)) < 0) {
if (errno == 2) {
fd= creat(file, 0666);
}
}
if (fd < 0) {
printf("mkfile: Can't open %s: %s\n", file, strerror(errno));
exit(1);
}
/* How big is the file now? */
if ((offset= lseek(fd, 0, SEEK_END)) == -1) {
printf("mkfile: Can't seek in %s: %s\n", file, strerror(errno));
exit(1);
}
if (offset == 0 && size == 0) exit(0); /* Huh? */
/* Write the first bit if the file is zero length. This is necessary
* to circumvent a DOS bug by extending a new file by lseek. We also
* want to make sure there are zeros in the first sector.
*/
if (offset == 0) {
if (write(fd, buf, sizeof(buf)) == -1) {
printf("mkfile: Can't write to %s: %s\n",
file, strerror(errno));
exit(1);
}
}
/* Seek to the required size and write 0 bytes to extend/truncate the
* file to that size.
*/
if (lseek(fd, size, SEEK_SET) == -1) {
printf("mkfile: Can't seek in %s: %s\n", file, strerror(errno));
exit(1);
}
if (write(fd, buf, 0) == -1) {
printf("mkfile: Can't write to %s: %s\n",
file, strerror(errno));
exit(1);
}
/* Did the file become the required size? */
if ((offset= lseek(fd, 0, SEEK_END)) == -1) {
printf("mkfile: Can't seek in %s: %s\n", file, strerror(errno));
exit(1);
}
if (offset != size) {
printf("mkfile: Failed to extend %s. Disk full?\n", file);
exit(1);
}
return 0;
}
/*
* $PchId: mkfile.c,v 1.4 2000/08/13 22:06:40 philip Exp $
*/

350
boot/rawfs.c Executable file
View File

@@ -0,0 +1,350 @@
/* rawfs.c - Raw Minix file system support. Author: Kees J. Bot
* 23 Dec 1991
* Based on readfs by Paul Polderman
*/
#define nil 0
#define _POSIX_SOURCE 1
#define _MINIX 1
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <minix/config.h>
#include <minix/const.h>
#include <minix/type.h>
#include <servers/fs/const.h>
#include <servers/fs/type.h>
#include <servers/fs/buf.h>
#include <servers/fs/super.h>
#include <servers/fs/inode.h>
#include "rawfs.h"
void readblock(off_t blockno, char *buf, int);
/* The following code handles two file system types: Version 1 with small
* inodes and 16-bit disk addresses and Version 2 with big inodes and 32-bit
* disk addresses.
#ifdef FLEX
* To make matters worse, Minix-vmd knows about the normal Unix Version 7
* directories and directories with flexible entries.
#endif
*/
/* File system parameters. */
static unsigned nr_dzones; /* Fill these in after reading superblock. */
static unsigned nr_indirects;
static unsigned inodes_per_block;
static int block_size;
#ifdef FLEX
#include <dirent.h>
#define direct _v7_direct
#else
#include <sys/dir.h>
#endif
#if __minix_vmd
static struct v12_super_block super; /* Superblock of file system */
#define s_log_zone_size s_dummy /* Zones are obsolete. */
#else
static struct super_block super; /* Superblock of file system */
#define SUPER_V1 SUPER_MAGIC /* V1 magic has a weird name. */
#endif
#define RAWFS_MAX_BLOCK_SIZE 1024
static struct inode curfil; /* Inode of file under examination */
static char indir[RAWFS_MAX_BLOCK_SIZE]; /* Single indirect block. */
static char dindir[RAWFS_MAX_BLOCK_SIZE]; /* Double indirect block. */
static char dirbuf[RAWFS_MAX_BLOCK_SIZE]; /* Scratch/Directory block. */
#define scratch dirbuf
static block_t a_indir, a_dindir; /* Addresses of the indirects. */
static off_t dirpos; /* Reading pos in a dir. */
#define fsbuf(b) (* (struct buf *) (b))
#define zone_shift (super.s_log_zone_size) /* zone to block ratio */
off_t r_super(int *bs)
/* Initialize variables, return size of file system in blocks,
* (zero on error).
*/
{
/* Read superblock. */
readblock(1, scratch, 1024);
memcpy(&super, scratch, sizeof(super));
printf("super: %lx\n", super.s_magic);
/* Is it really a MINIX file system ? */
if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
if(super.s_magic == SUPER_V2)
super.s_block_size = 1024;
*bs = block_size = super.s_block_size;
printf("max_size: %d zones: %d imap_blocks: %d zones: %d\n",
super.s_max_size, super.s_imap_blocks,
super.s_zmap_blocks, super.s_nzones);
if(block_size < MIN_BLOCK_SIZE ||
block_size > RAWFS_MAX_BLOCK_SIZE) {
printf("bogus block size %d\n", block_size);
return 0;
}
nr_dzones= V2_NR_DZONES;
nr_indirects= V2_INDIRECTS(block_size);
inodes_per_block= V2_INODES_PER_BLOCK(block_size);
printf("v2/v3 %d ok\n", block_size);
printf("ipb %d\n", inodes_per_block);
return (off_t) super.s_zones << zone_shift;
} else
if (super.s_magic == SUPER_V1) {
*bs = block_size = 1024;
nr_dzones= V1_NR_DZONES;
nr_indirects= V1_INDIRECTS;
inodes_per_block= V1_INODES_PER_BLOCK;
printf("v1 ok\n");
return (off_t) super.s_nzones << zone_shift;
} else {
/* Filesystem not recognized as Minix. */
printf("not minix\n");
return 0;
}
}
void r_stat(Ino_t inum, struct stat *stp)
/* Return information about a file like stat(2) and remember it. */
{
block_t block;
block_t ino_block;
ino_t ino_offset;
/* Calculate start of i-list */
block = START_BLOCK + super.s_imap_blocks + super.s_zmap_blocks;
printf("r_stat: start of i-list: %d (ipb %d)\n",
block, inodes_per_block);
/* Calculate block with inode inum */
ino_block = ((inum - 1) / inodes_per_block);
ino_offset = ((inum - 1) % inodes_per_block);
block += ino_block;
printf("r_stat: block with inode: %d - readblock %d..\n", block, block_size);
/* Fetch the block */
readblock(block, scratch, block_size);
printf("r_stat: readblock done..\n", block);
if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
d2_inode *dip;
int i;
dip= &fsbuf(scratch).b_v2_ino[ino_offset];
curfil.i_mode= dip->d2_mode;
curfil.i_nlinks= dip->d2_nlinks;
curfil.i_uid= dip->d2_uid;
curfil.i_gid= dip->d2_gid;
curfil.i_size= dip->d2_size;
curfil.i_atime= dip->d2_atime;
curfil.i_mtime= dip->d2_mtime;
curfil.i_ctime= dip->d2_ctime;
for (i= 0; i < V2_NR_TZONES; i++)
curfil.i_zone[i]= dip->d2_zone[i];
} else {
d1_inode *dip;
int i;
dip= &fsbuf(scratch).b_v1_ino[ino_offset];
curfil.i_mode= dip->d1_mode;
curfil.i_nlinks= dip->d1_nlinks;
curfil.i_uid= dip->d1_uid;
curfil.i_gid= dip->d1_gid;
curfil.i_size= dip->d1_size;
curfil.i_atime= dip->d1_mtime;
curfil.i_mtime= dip->d1_mtime;
curfil.i_ctime= dip->d1_mtime;
for (i= 0; i < V1_NR_TZONES; i++)
curfil.i_zone[i]= dip->d1_zone[i];
}
curfil.i_dev= -1; /* Can't fill this in alas. */
curfil.i_num= inum;
stp->st_dev= curfil.i_dev;
stp->st_ino= curfil.i_num;
stp->st_mode= curfil.i_mode;
stp->st_nlink= curfil.i_nlinks;
stp->st_uid= curfil.i_uid;
stp->st_gid= curfil.i_gid;
stp->st_rdev= (dev_t) curfil.i_zone[0];
stp->st_size= curfil.i_size;
stp->st_atime= curfil.i_atime;
stp->st_mtime= curfil.i_mtime;
stp->st_ctime= curfil.i_ctime;
a_indir= a_dindir= 0;
dirpos= 0;
}
ino_t r_readdir(char *name)
/* Read next directory entry at "dirpos" from file "curfil". */
{
ino_t inum= 0;
int blkpos;
struct direct *dp;
if (!S_ISDIR(curfil.i_mode)) { errno= ENOTDIR; return -1; }
if(!block_size) { errno = 0; return -1; }
while (inum == 0 && dirpos < curfil.i_size) {
if ((blkpos= (int) (dirpos % block_size)) == 0) {
/* Need to fetch a new directory block. */
readblock(r_vir2abs(dirpos / block_size), dirbuf, block_size);
}
#ifdef FLEX
if (super.s_flags & S_FLEX) {
struct _fl_direct *dp;
dp= (struct _fl_direct *) (dirbuf + blkpos);
if ((inum= dp->d_ino) != 0) strcpy(name, dp->d_name);
dirpos+= (1 + dp->d_extent) * FL_DIR_ENTRY_SIZE;
continue;
}
#endif
/* Let dp point to the next entry. */
dp= (struct direct *) (dirbuf + blkpos);
if ((inum= dp->d_ino) != 0) {
/* This entry is occupied, return name. */
strncpy(name, dp->d_name, sizeof(dp->d_name));
name[sizeof(dp->d_name)]= 0;
}
dirpos+= DIR_ENTRY_SIZE;
}
return inum;
}
off_t r_vir2abs(off_t virblk)
/* Translate a block number in a file to an absolute disk block number.
* Returns 0 for a hole and -1 if block is past end of file.
*/
{
block_t b= virblk;
zone_t zone, ind_zone;
block_t z, zone_index;
int i;
if(!block_size) return -1;
/* Check if virblk within file. */
if (virblk * block_size >= curfil.i_size) return -1;
/* Calculate zone in which the datablock number is contained */
zone = (zone_t) (b >> zone_shift);
/* Calculate index of the block number in the zone */
zone_index = b - ((block_t) zone << zone_shift);
/* Go get the zone */
if (zone < (zone_t) nr_dzones) { /* direct block */
zone = curfil.i_zone[(int) zone];
z = ((block_t) zone << zone_shift) + zone_index;
return z;
}
/* The zone is not a direct one */
zone -= (zone_t) nr_dzones;
/* Is it single indirect ? */
if (zone < (zone_t) nr_indirects) { /* single indirect block */
ind_zone = curfil.i_zone[nr_dzones];
} else { /* double indirect block */
/* Fetch the double indirect block */
if ((ind_zone = curfil.i_zone[nr_dzones + 1]) == 0) return 0;
z = (block_t) ind_zone << zone_shift;
if (a_dindir != z) {
readblock(z, dindir, block_size);
a_dindir= z;
}
/* Extract the indirect zone number from it */
zone -= (zone_t) nr_indirects;
i = zone / (zone_t) nr_indirects;
ind_zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
? fsbuf(dindir).b_v2_ind[i]
: fsbuf(dindir).b_v1_ind[i];
zone %= (zone_t) nr_indirects;
}
if (ind_zone == 0) return 0;
/* Extract the datablock number from the indirect zone */
z = (block_t) ind_zone << zone_shift;
if (a_indir != z) {
readblock(z, indir, block_size);
a_indir= z;
}
zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
? fsbuf(indir).b_v2_ind[(int) zone]
: fsbuf(indir).b_v1_ind[(int) zone];
/* Calculate absolute datablock number */
z = ((block_t) zone << zone_shift) + zone_index;
return z;
}
ino_t r_lookup(Ino_t cwd, char *path)
/* Translates a pathname to an inode number. This is just a nice utility
* function, it only needs r_stat and r_readdir.
*/
{
char name[NAME_MAX+1], r_name[NAME_MAX+1];
char *n;
struct stat st;
ino_t ino;
ino= path[0] == '/' ? ROOT_INO : cwd;
for (;;) {
printf("ino %d..\n", ino);
if (ino == 0) {
errno= ENOENT;
return 0;
}
while (*path == '/') path++;
if (*path == 0) return ino;
printf("r_stat..\n");
r_stat(ino, &st);
printf("r_stat done..\n");
if (!S_ISDIR(st.st_mode)) {
errno= ENOTDIR;
return 0;
}
n= name;
while (*path != 0 && *path != '/')
if (n < name + NAME_MAX) *n++ = *path++;
*n= 0;
printf("r_readdir..\n");
while ((ino= r_readdir(r_name)) != 0
&& strcmp(name, r_name) != 0) {
printf("r_readdir %s isn't it..\n", r_name);
}
printf("after readdir loop: %s %s\n", name, r_name);
}
}
/*
* $PchId: rawfs.c,v 1.8 1999/11/05 23:14:15 philip Exp $
*/

43
boot/rawfs.h Executable file
View File

@@ -0,0 +1,43 @@
/* rawfs.h - Raw Minix file system support. Author: Kees J. Bot
*
* off_t r_super(int *block_size);
* Initialize variables, returns the size of a valid Minix
* file system blocks, but zero on error.
*
* void r_stat(ino_t file, struct stat *stp);
* Return information about a file like stat(2) and
* remembers file for the next two calls.
*
* off_t r_vir2abs(off_t virblockno);
* Translate virtual block number in file to absolute
* disk block number. Returns 0 if the file contains
* a hole, or -1 if the block lies past the end of file.
*
* ino_t r_readdir(char *name);
* Return next directory entry or 0 if there are no more.
* Returns -1 and sets errno on error.
*
* ino_t r_lookup(ino_t cwd, char *path);
* A utility function that translates a pathname to an
* inode number. It starts from directory "cwd" unless
* path starts with a '/', then from ROOT_INO.
* Returns 0 and sets errno on error.
*
* One function needs to be provided by the outside world:
*
* void readblock(off_t blockno, char *buf, int block_size);
* Read a block into the buffer. Outside world handles
* errors.
*/
#define ROOT_INO ((ino_t) 1) /* Inode nr of root dir. */
off_t r_super(int *);
void r_stat(Ino_t file, struct stat *stp);
off_t r_vir2abs(off_t virblockno);
ino_t r_readdir(char *name);
ino_t r_lookup(Ino_t cwd, char *path);
/*
* $PchId: rawfs.h,v 1.4 1996/04/19 08:16:36 philip Exp $
*/