sch@oce.nl (Jakob Schripsema) (04/27/87)
echo x - f_make.
sed 's/^X//' >f_make. <<'*-*-END-of-f_make.-*-*'
XCFLAGS= -Di8088 -w -F -T.
Xh=../h
Xl=/usr/lib
X
Xobj = main.s open.s read.s write.s pipe.s device.s \
X path.s mount.s link.s super.s inode.s cache.s filedes.s \
X stadir.s protect.s time.s misc.s utility.s table.s putc.s
X
Xfs: makefile $l/head.s $(obj) $l/libc.a $l/end.s
X# @echo "Start linking FS. /lib/cem will be removed to make space on RAM disk"
X# @rm -f /lib/cem /tmp/*
X# asld -o fs $l/head.s $(obj) $l/libc.a $l/end.s
X# @echo "FS done. Please restore /lib/cem manually"
X @echo "Start linking FS.
X @asld -o fs -T. $l/head.s $(obj) $l/libc.a $l/end.s
X @echo "FS done.
X
Xcache.s: const.h type.h $h/const.h $h/type.h
Xcache.s: $h/error.h
Xcache.s: buf.h
Xcache.s: file.h
Xcache.s: fproc.h
Xcache.s: glo.h
Xcache.s: inode.h
Xcache.s: super.h
X
Xdevice.s: const.h type.h $h/const.h $h/type.h
Xdevice.s: $h/com.h
Xdevice.s: $h/error.h
Xdevice.s: dev.h
Xdevice.s: file.h
Xdevice.s: fproc.h
Xdevice.s: glo.h
Xdevice.s: inode.h
Xdevice.s: param.h
X
Xfiledes.s: const.h type.h $h/const.h $h/type.h
Xfiledes.s: $h/error.h
Xfiledes.s: file.h
Xfiledes.s: fproc.h
Xfiledes.s: glo.h
Xfiledes.s: inode.h
X
Xinode.s: const.h type.h $h/const.h $h/type.h
Xinode.s: $h/error.h
Xinode.s: buf.h
Xinode.s: file.h
Xinode.s: fproc.h
Xinode.s: glo.h
Xinode.s: inode.h
Xinode.s: super.h
X
Xlink.s: const.h type.h $h/const.h $h/type.h
Xlink.s: $h/error.h
Xlink.s: buf.h
Xlink.s: file.h
Xlink.s: fproc.h
Xlink.s: glo.h
Xlink.s: inode.h
Xlink.s: param.h
X
Xmain.s: const.h type.h $h/const.h $h/type.h
Xmain.s: $h/callnr.h
Xmain.s: $h/com.h
Xmain.s: $h/error.h
Xmain.s: buf.h
Xmain.s: file.h
Xmain.s: fproc.h
Xmain.s: glo.h
Xmain.s: inode.h
Xmain.s: param.h
Xmain.s: super.h
X
Xmisc.s: const.h type.h $h/const.h $h/type.h
Xmisc.s: $h/callnr.h
Xmisc.s: $h/com.h
Xmisc.s: $h/error.h
Xmisc.s: buf.h
Xmisc.s: file.h
Xmisc.s: fproc.h
Xmisc.s: glo.h
Xmisc.s: inode.h
Xmisc.s: param.h
Xmisc.s: super.h
X
Xmount.s: const.h type.h $h/const.h $h/type.h
Xmount.s: $h/error.h
Xmount.s: buf.h
Xmount.s: file.h
Xmount.s: fproc.h
Xmount.s: glo.h
Xmount.s: inode.h
Xmount.s: param.h
Xmount.s: super.h
X
Xopen.s: const.h type.h $h/const.h $h/type.h
Xopen.s: $h/callnr.h
Xopen.s: $h/error.h
Xopen.s: buf.h
Xopen.s: file.h
Xopen.s: fproc.h
Xopen.s: glo.h
Xopen.s: inode.h
Xopen.s: param.h
X
Xpath.s: const.h type.h $h/const.h $h/type.h
Xpath.s: $h/error.h
Xpath.s: buf.h
Xpath.s: file.h
Xpath.s: fproc.h
Xpath.s: glo.h
Xpath.s: inode.h
Xpath.s: super.h
X
Xpipe.s: const.h type.h $h/const.h $h/type.h
Xpipe.s: $h/callnr.h
Xpipe.s: $h/com.h
Xpipe.s: $h/error.h
Xpipe.s: $h/signal.h
Xpipe.s: file.h
Xpipe.s: fproc.h
Xpipe.s: glo.h
Xpipe.s: inode.h
Xpipe.s: param.h
X
Xprotect.s: const.h type.h $h/const.h $h/type.h
Xprotect.s: $h/error.h
Xprotect.s: buf.h
Xprotect.s: file.h
Xprotect.s: fproc.h
Xprotect.s: glo.h
Xprotect.s: inode.h
Xprotect.s: param.h
Xprotect.s: super.h
X
Xputc.s: const.h type.h $h/const.h $h/type.h
Xputc.s: $h/com.h
X
Xread.s: const.h type.h $h/const.h $h/type.h
Xread.s: $h/com.h
Xread.s: $h/error.h
Xread.s: buf.h
Xread.s: file.h
Xread.s: fproc.h
Xread.s: glo.h
Xread.s: inode.h
Xread.s: param.h
Xread.s: super.h
X
Xstadir.s: const.h type.h $h/const.h $h/type.h
Xstadir.s: $h/error.h
Xstadir.s: $h/stat.h
Xstadir.s: file.h
Xstadir.s: fproc.h
Xstadir.s: glo.h
Xstadir.s: inode.h
Xstadir.s: param.h
X
Xsuper.s: const.h type.h $h/const.h $h/type.h
Xsuper.s: $h/error.h
Xsuper.s: buf.h
Xsuper.s: inode.h
Xsuper.s: super.h
X
Xtable.s: const.h type.h $h/const.h $h/type.h
Xtable.s: $h/com.h
Xtable.s: $h/callnr.h
Xtable.s: $h/error.h
Xtable.s: $h/stat.h
Xtable.s: buf.h
Xtable.s: dev.h
Xtable.s: file.h
Xtable.s: fproc.h
Xtable.s: glo.h
Xtable.s: inode.h
Xtable.s: super.h
X
Xtime.s: const.h type.h $h/const.h $h/type.h
Xtime.s: $h/callnr.h
Xtime.s: $h/com.h
Xtime.s: $h/error.h
Xtime.s: file.h
Xtime.s: fproc.h
Xtime.s: glo.h
Xtime.s: inode.h
Xtime.s: param.h
X
Xutility.s: const.h type.h $h/const.h $h/type.h
Xutility.s: $h/com.h
Xutility.s: $h/error.h
Xutility.s: buf.h
Xutility.s: file.h
Xutility.s: fproc.h
Xutility.s: glo.h
Xutility.s: inode.h
Xutility.s: param.h
Xutility.s: super.h
X
Xwrite.s: const.h type.h $h/const.h $h/type.h
Xwrite.s: $h/error.h
Xwrite.s: buf.h
Xwrite.s: file.h
Xwrite.s: fproc.h
Xwrite.s: glo.h
Xwrite.s: inode.h
Xwrite.s: super.h
*-*-END-of-f_make.-*-*
echo x - h_const.h
sed 's/^X//' >h_const.h <<'*-*-END-of-h_const.h-*-*'
X/* Copyright (C) 1987 by Prentice-Hall, Inc. Permission is hereby granted to
X * private individuals and educational institutions to modify and
X * redistribute the binary and source programs of this system to other
X * private individuals and educational institutions for educational and
X * research purposes. For corporate or commercial use, permission from
X * Prentice-Hall is required. In general, such permission will be granted,
X * subject to a few conditions.
X */
X
X#define EXTERN extern /* used in *.h files */
X#define PRIVATE static /* PRIVATE x limits the scope of x */
X#define PUBLIC /* PUBLIC is the opposite of PRIVATE */
X#define FORWARD /* some compilers require this to be 'static' */
X
X#define TRUE 1 /* used for turning integers into Booleans */
X#define FALSE 0 /* used for turning integers into Booleans */
X
X#define HZ 60 /* clock freq (software settable on IBM-PC) */
X#define BLOCK_SIZE 1024 /* # bytes in a disk block */
X#define SUPER_USER (uid) 0 /* uid of superuser */
X
X#define MAJOR 8 /* major device = (dev>>MAJOR) & 0377 */
X#define MINOR 0 /* minor device = (dev>>MINOR) & 0377 */
X
X#define NR_TASKS 8 /* number of tasks in the transfer vector */
X#define NR_PROCS 16 /* number of slots in proc table */
X#define NR_SEGS 3 /* # segments per process */
X#define T 0 /* proc[i].mem_map[T] is for text */
X#define D 1 /* proc[i].mem_map[D] is for data */
X#define S 2 /* proc[i].mem_map[S] is for stack */
X
X#define MAX_P_LONG 2147483647 /* maximum positive long, i.e. 2**31 - 1 */
X
X/* Memory is allocated in clicks. */
X#define CLICK_SIZE 0020 /* unit in which memory is allocated */
X#define CLICK_SHIFT 4 /* log2 of CLICK_SIZE */
X
X/* Process numbers of some important processes */
X#define MM_PROC_NR 0 /* process number of memory manager */
X#define FS_PROC_NR 1 /* process number of file system */
X#define INIT_PROC_NR 2 /* init -- the process that goes multiuser */
X#define LOW_USER 2 /* first user not part of operating system */
X
X/* Miscellaneous */
X#define BYTE 0377 /* mask for 8 bits */
X#define TO_USER 0 /* flag telling to copy from fs to user */
X#define FROM_USER 1 /* flag telling to copy from user to fs */
X#define READING 0 /* copy data to user */
X#define WRITING 1 /* copy data from user */
X#define ABS -999 /* this process means absolute memory */
X
X#define WORD_SIZE 2 /* number of bytes per word */
X
X#define NIL_PTR (char *) 0 /* generally useful expression */
X
X#define NO_NUM 0x8000 /* used as numerical argument to panic() */
X#define MAX_PATH 128 /* max length of path names */
X#define SIG_PUSH_BYTES 8 /* how many bytes pushed by signal */
X#define MAX_ISTACK_BYTES 1024 /* maximum initial stack size for EXEC */
X
X/* Device numbers of root (RAM) and boot (fd0) devices. */
X#define ROOT_DEV (dev_nr) 256 /* major-minor device number of root dev */
X/* bootdev fd0 : 512, hd2 : 770 */
X#define BOOT_DEV (dev_nr) 770 /* major-minor device number of boot diskette */
X
X/* Flag bits for i_mode in the inode. */
X#define I_TYPE 0170000 /* this field gives inode type */
X#define I_REGULAR 0100000 /* regular file, not dir or special */
X#define I_BLOCK_SPECIAL 0060000 /* block special file */
X#define I_DIRECTORY 0040000 /* file is a directory */
X#define I_CHAR_SPECIAL 0020000 /* character special file */
X#define I_SET_UID_BIT 0004000 /* set effective uid on exec */
X#define I_SET_GID_BIT 0002000 /* set effective gid on exec */
X#define ALL_MODES 0006777 /* all bits for user, group and others */
X#define RWX_MODES 0000777 /* mode bits for RWX only */
X#define R_BIT 0000004 /* Rwx protection bit */
X#define W_BIT 0000002 /* rWx protection bit */
X#define X_BIT 0000001 /* rwX protection bit */
X#define I_NOT_ALLOC 0000000 /* this inode is free */
*-*-END-of-h_const.h-*-*
echo x - k_const.h
sed 's/^X//' >k_const.h <<'*-*-END-of-k_const.h-*-*'
X/* General constants used by the kernel. */
X
X#ifdef i8088
X/* p_reg contains: ax, bx, cx, dx, si, di, bp, es, ds, cs, ss in that order. */
X#define NR_REGS 11 /* number of general regs in each proc slot */
X#define INIT_PSW 0x0200 /* initial psw */
X#define INIT_SP (int*)0x0010 /* initial sp: 3 words pushed by kernel */
X
X/* The following values are used in the assembly code. Do not change the
X * values of 'ES_REG', 'DS_REG', 'CS_REG', or 'SS_REG' without making the
X * corresponding changes in the assembly code.
X */
X#define ES_REG 7 /* proc[i].p_reg[ESREG] is saved es */
X#define DS_REG 8 /* proc[i].p_reg[DSREG] is saved ds */
X#define CS_REG 9 /* proc[i].p_reg[CSREG] is saved cs */
X#define SS_REG 10 /* proc[i].p_reg[SSREG] is saved ss */
X
X#define VECTOR_BYTES 284 /* bytes of interrupt vectors to save */
X#define MEM_BYTES 655360L /* memory size for /dev/mem */
X
X/* Interrupt vectors */
X#define DIVIDE_VECTOR 0 /* divide interrupt vector */
X#define CLOCK_VECTOR 8 /* clock interrupt vector */
X#define KEYBOARD_VECTOR 9 /* keyboard interrupt vector */
X#define XT_WINI_VECTOR 13 /* xt winchester interrupt vector */
X#define FLOPPY_VECTOR 14 /* floppy disk interrupt vector */
X#define PRINTER_VECTOR 15 /* line printer interrupt vector */
X#define SYS_VECTOR 32 /* system calls are made with int SYSVEC */
X#define AT_WINI_VECTOR 118 /* at winchester interrupt vector */
X
X/* The 8259A interrupt controller has to be re-enabled after each interrupt. */
X#define INT_CTL 0x20 /* I/O port for interrupt controller */
X#define INT_CTLMASK 0x21 /* setting bits in this port disables ints */
X#define INT2_CTL 0xA0 /* I/O port for second interrupt controller */
X#define INT2_MASK 0xA1 /* setting bits in this port disables ints */
X#define ENABLE 0x20 /* code used to re-enable after an interrupt */
X
X/* Hardware IDs */
X#define UNKNOWN 0 /* OS could not detect hrdware type */
X#define IBMXT 1 /* IBM XT */
X#define IBMAT 2 /* IBM AT */
X#define M24 3 /* Olivetti M24, AT&T 6300 */
X#endif
X
X#define TASK_STACK_BYTES 256 /* how many bytes for each task stack */
X#define K_STACK_BYTES 256 /* how many bytes for the kernel stack */
X
X#define RET_REG 0 /* system call return codes go in this reg */
X#define IDLE -999 /* 'cur_proc' = IDLE means nobody is running */
X
X/* The following items pertain to the 3 scheduling queues. */
X#define NQ 3 /* # of scheduling queues */
X#define TASK_Q 0 /* ready tasks are scheduled via queue 0 */
X#define SERVER_Q 1 /* ready servers are scheduled via queue 1 */
X#define USER_Q 2 /* ready users are scheduled via queue 2 */
X
X#define printf printk /* the kernel really uses printk, not printf */
*-*-END-of-k_const.h-*-*
echo x - k_floppy.c
sed 's/^X//' >k_floppy.c <<'*-*-END-of-k_floppy.c-*-*'
X/* This file contains a driver for a Floppy Disk Controller (FDC) using the
X * NEC PD765 chip. The driver supports two operations: read a block and
X * write a block. It accepts two messages, one for reading and one for
X * writing, both using message format m2 and with the same parameters:
X *
X * m_type DEVICE PROC_NR COUNT POSITION ADRRESS
X * ----------------------------------------------------------------
X * | DISK_READ | device | proc nr | bytes | offset | buf ptr |
X * |------------+---------+---------+---------+---------+---------|
X * | DISK_WRITE | device | proc nr | bytes | offset | buf ptr |
X * ----------------------------------------------------------------
X *
X * The file contains one entry point:
X *
X * floppy_task: main entry when system is brought up
X *
X * Changes:
X * 27 october 1986 by Jakob Schripsema: fdc_results fixed for 8 MHz
X * 2 februari 1987 by Jakob Schripsema: added timeout() routine
X * & reset counter
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/callnr.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "const.h"
X#include "type.h"
X#include "glo.h"
X#include "proc.h"
X
X/* I/O Ports used by floppy disk task. */
X#define DOR 0x3F2 /* motor drive control bits */
X#define FDC_STATUS 0x3F4 /* floppy disk controller status register */
X#define FDC_DATA 0x3F5 /* floppy disk controller data register */
X#define FDC_RATE 0x3F7 /* transfer rate register */
X#define DMA_ADDR 0x004 /* port for low 16 bits of DMA address */
X#define DMA_TOP 0x081 /* port for top 4 bits of 20-bit DMA addr */
X#define DMA_COUNT 0x005 /* port for DMA count (count = bytes - 1) */
X#define DMA_M2 0x00C /* DMA status port */
X#define DMA_M1 0x00B /* DMA status port */
X#define DMA_INIT 0x00A /* DMA init port */
X
X/* Status registers returned as result of operation. */
X#define ST0 0x00 /* status register 0 */
X#define ST1 0x01 /* status register 1 */
X#define ST2 0x02 /* status register 2 */
X#define ST3 0x00 /* status register 3 (return by DRIVE_SENSE) */
X#define ST_CYL 0x03 /* slot where controller reports cylinder */
X#define ST_HEAD 0x04 /* slot where controller reports head */
X#define ST_SEC 0x05 /* slot where controller reports sector */
X#define ST_PCN 0x01 /* slot where controller reports present cyl */
X
X/* Fields within the I/O ports. */
X#define MASTER 0x80 /* used to see who is master */
X#define DIRECTION 0x40 /* is FDC trying to read or write? */
X#define CTL_BUSY 0x10 /* used to see when controller is busy */
X#define CTL_ACCEPTING 0x80 /* bit pattern FDC gives when idle */
X#define MOTOR_MASK 0xF0 /* these bits control the motors in DOR */
X#define ENABLE_INT 0x0C /* used for setting DOR port */
X#define ST0_BITS 0xF8 /* check top 5 bits of seek status */
X#define ST3_FAULT 0x80 /* if this bit is set, drive is sick */
X#define ST3_WR_PROTECT 0x40 /* set when diskette is write protected */
X#define ST3_READY 0x20 /* set when drive is ready */
X#define TRANS_ST0 0x00 /* top 5 bits of ST0 for READ/WRITE */
X#define SEEK_ST0 0x20 /* top 5 bits of ST0 for SEEK */
X#define BAD_SECTOR 0x05 /* if these bits are set in ST1, recalibrate */
X#define BAD_CYL 0x1F /* if any of these bits are set, recalibrate */
X#define WRITE_PROTECT 0x02 /* bit is set if diskette is write protected */
X#define CHANGE 0xC0 /* value returned by FDC after reset */
X
X/* Floppy disk controller command bytes. */
X#define FDC_SEEK 0x0F /* command the drive to seek */
X#define FDC_READ 0xE6 /* command the drive to read */
X#define FDC_WRITE 0xC5 /* command the drive to write */
X#define FDC_SENSE 0x08 /* command the controller to tell its status */
X#define FDC_RECALIBRATE 0x07 /* command the drive to go to cyl 0 */
X#define FDC_SPECIFY 0x03 /* command the drive to accept params */
X
X/* DMA channel commands. */
X#define DMA_READ 0x46 /* DMA read opcode */
X#define DMA_WRITE 0x4A /* DMA write opcode */
X
X/* Parameters for the disk drive. */
X#define SECTOR_SIZE 512 /* physical sector size in bytes */
X#define HC_SIZE 2400 /* # sectors on a high-capacity (1.2M) disk */
X#define NR_HEADS 0x02 /* two heads (i.e., two tracks/cylinder) */
X#define DTL 0xFF /* determines data length (sector size) */
X#define SPEC1 0xDF /* first parameter to SPECIFY */
X#define SPEC2 0x02 /* second parameter to SPECIFY */
X
X#define MOTOR_OFF 3*HZ /* how long to wait before stopping motor */
X#define TIMEOUT 2*HZ /* how long to wait before aborting transfer */
X
X/* Error codes */
X#define ERR_SEEK -1 /* bad seek */
X#define ERR_TRANSFER -2 /* bad transfer */
X#define ERR_STATUS -3 /* something wrong when getting status */
X#define ERR_RECALIBRATE -4 /* recalibrate didn't work properly */
X#define ERR_WR_PROTECT -5 /* diskette is write protected */
X#define ERR_DRIVE -6 /* something wrong with a drive */
X#define ERR_TIMEOUT -7 /* timeout, drive not ready */
X
X/* Miscellaneous. */
X#define MOTOR_RUNNING 0xFF /* message type for clock interrupt */
X#define MAX_ERRORS 20 /* how often to try rd/wt before quitting */
X#define MAX_RESETS 2 /* max number of resets for 1 job */
X#define MAX_RESULTS 8 /* max number of bytes controller returns */
X#define NR_DRIVES 2 /* maximum number of drives */
X#define DIVISOR 128 /* used for sector size encoding */
X#define MAX_FDC_RETRY 100 /* max # times to try to output to FDC */
X#define NT 4 /* number of diskette/drive combinations */
X
X/* Variables. */
XPRIVATE struct floppy { /* main drive struct, one entry per drive */
X int fl_opcode; /* DISK_READ or DISK_WRITE */
X int fl_curcyl; /* current cylinder */
X int fl_procnr; /* which proc wanted this operation? */
X int fl_drive; /* drive number addressed */
X int fl_cylinder; /* cylinder number addressed */
X int fl_sector; /* sector addressed */
X int fl_head; /* head number addressed */
X int fl_count; /* byte count */
X vir_bytes fl_address; /* user virtual address */
X char fl_results[MAX_RESULTS]; /* the controller can give lots of output */
X char fl_calibration; /* CALIBRATED or UNCALIBRATED */
X char fl_density; /* 0 = 360K/360K; 1 = 360K/1.2M; 2= 1.2M/1.2M */
X} floppy[NR_DRIVES];
X
X#define UNCALIBRATED 0 /* drive needs to be calibrated at next use */
X#define CALIBRATED 1 /* no calibration needed */
X
XPRIVATE int motor_status; /* current motor status is in 4 high bits */
XPRIVATE int motor_goal; /* desired motor status is in 4 high bits */
XPRIVATE int prev_motor; /* which motor was started last */
XPRIVATE int need_reset; /* set to 1 when controller must be reset */
XPRIVATE int nresets; /* # of resets during 1 'job' */
XPRIVATE int initialized; /* set to 1 after first successful transfer */
XPRIVATE int d; /* diskette/drive combination */
XPRIVATE int active_timeout; /* used to detect timeout in transfer */
X
XPRIVATE message mess; /* message buffer for in and out */
X
XPRIVATE char len[] = {-1,0,1,-1,2,-1,-1,3,-1,-1,-1,-1,-1,-1,-1,4};
XPRIVATE char interleave[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
X
X/* Four combinations of diskette/drive are supported:
X * # Drive diskette Sectors Tracks Rotation Data-rate Comment
X * 0 360K 360K 9 40 300 RPM 250 kbps Standard PC DSDD
X * 1 720K 360K 9 40 300 RPM 250 kbps Quad density PC
X * 2 1.2M 360K 9 40 360 RPM 300 kbps PC disk in AT drive
X * 3 1.2M 1.2M 15 80 360 RPM 500 kbps AT disk in AT drive
X */
XPRIVATE int gap[NT] = {0x2A, 0x2A, 0x23, 0x1B}; /* gap size */
XPRIVATE int rate[NT] = {0x02, 0x02, 0x01, 0x00}; /* 250,300,500 kbps*/
XPRIVATE int nr_sectors[NT] = {9, 9, 9, 15}; /* sectors/track */
XPRIVATE int nr_blocks[NT] = {720, 720, 720, 2400}; /* sectors/diskette*/
XPRIVATE int steps_per_cyl[NT] = {1, 2, 2, 1}; /* 2 = dbl step */
XPRIVATE int mtr_setup[NT] = {HZ/4,HZ/4,3*HZ/4,3*HZ/4};/* in ticks */
X
X/*===========================================================================*
X * floppy_task *
X *===========================================================================*/
XPUBLIC floppy_task()
X{
X/* Main program of the floppy disk driver task. */
X
X int r, caller, proc_nr;
X extern int hw_id;
X
X if (hw_id == M24) mtr_setup[0] = 3*HZ/4;
X
X /* Here is the main loop of the disk task. It waits for a message, carries
X * it out, and sends a reply.
X */
X while (TRUE) {
X /* First wait for a request to read or write a disk block. */
X receive(ANY, &mess); /* get a request to do some work */
X if (mess.m_source < 0)
X panic("disk task got message from ", mess.m_source);
X caller = mess.m_source;
X proc_nr = mess.PROC_NR;
X
X /* Now carry out the work. */
X switch(mess.m_type) {
X case DISK_READ: r = do_rdwt(&mess); break;
X case DISK_WRITE: r = do_rdwt(&mess); break;
X default: r = EINVAL; break;
X }
X
X /* Finally, prepare and send the reply message. */
X mess.m_type = TASK_REPLY;
X mess.REP_PROC_NR = proc_nr;
X mess.REP_STATUS = r; /* # of bytes transferred or error code */
X send(caller, &mess); /* send reply to caller */
X }
X}
X
X
X/*===========================================================================*
X * do_rdwt *
X *===========================================================================*/
XPRIVATE int do_rdwt(m_ptr)
Xmessage *m_ptr; /* pointer to read or write message */
X{
X/* Carry out a read or write request from the disk. */
X register struct floppy *fp;
X int r, drive, errors, stop_motor();
X long block;
X
X /* Decode the message parameters. */
X drive = m_ptr->DEVICE;
X if (drive < 0 || drive >= NR_DRIVES) return(EIO);
X fp = &floppy[drive]; /* 'fp' points to entry for this drive */
X fp->fl_drive = drive; /* save drive number explicitly */
X fp->fl_opcode = m_ptr->m_type; /* DISK_READ or DISK_WRITE */
X if (m_ptr->POSITION % BLOCK_SIZE != 0) return(EINVAL);
X block = m_ptr->POSITION/SECTOR_SIZE;
X if (block >= HC_SIZE) return(EOF); /* sector is beyond end of 1.2M disk */
X d = fp->fl_density; /* diskette/drive combination */
X fp->fl_cylinder = (int) (block / (NR_HEADS * nr_sectors[d]));
X fp->fl_sector = (int) interleave[block % nr_sectors[d]];
X fp->fl_head = (int) (block % (NR_HEADS*nr_sectors[d]) )/nr_sectors[d];
X fp->fl_count = m_ptr->COUNT;
X fp->fl_address = (vir_bytes) m_ptr->ADDRESS;
X fp->fl_procnr = m_ptr->PROC_NR;
X if (fp->fl_count != BLOCK_SIZE) return(EINVAL);
X
X errors = 0;
X nresets = 0;
X
X /* This loop allows a failed operation to be repeated. */
X while (errors <= MAX_ERRORS) {
X
X /* If a lot of errors occur when 'initialized' is 0, it probably
X * means that we are trying at the wrong density. Try another one.
X * Increment 'errors' here since loop is aborted on error.
X */
X errors++; /* increment count once per loop cycle */
X if (errors % (MAX_ERRORS/NT) == 0) {
X d = (d + 1) % NT; /* try next density */
X fp->fl_density = d;
X need_reset = 1;
X }
X if (block >= nr_blocks[d]) continue;
X
X /* First check to see if a reset is needed. */
X if (need_reset) reset();
X if (nresets > MAX_RESETS) return(ERR_DRIVE);
X
X /* Now set up the DMA chip. */
X dma_setup(fp);
X
X /* See if motor is running; if not, turn it on and wait */
X start_motor(fp);
X
X /* If we are going to a new cylinder, perform a seek. */
X r = seek(fp);
X if (r != OK) continue; /* if error, try again */
X
X /* Perform the transfer. */
X r = transfer(fp);
X if (r == OK) break; /* if successful, exit loop */
X if (r == ERR_WR_PROTECT || r == ERR_TIMEOUT) break; /* retries won't help */
X
X }
X
X /* Start watch_dog timer to turn motor off in a few seconds */
X motor_goal = ENABLE_INT; /* when timer goes off, kill all motors */
X clock_mess(MOTOR_OFF, stop_motor);
X if (r == OK && fp->fl_cylinder > 0) initialized = 1; /* seek works */
X return(r == OK ? BLOCK_SIZE : EIO);
X}
X
X/*===========================================================================*
X * dma_setup *
X *===========================================================================*/
XPRIVATE dma_setup(fp)
Xstruct floppy *fp; /* pointer to the drive struct */
X{
X/* The IBM PC can perform DMA operations by using the DMA chip. To use it,
X * the DMA (Direct Memory Access) chip is loaded with the 20-bit memory address
X * to be read from or written to, the byte count minus 1, and a read or write
X * opcode. This routine sets up the DMA chip. Note that the chip is not
X * capable of doing a DMA across a 64K boundary (e.g., you can't read a
X * 512-byte block starting at physical address 65520).
X */
X
X int mode, low_addr, high_addr, top_addr, low_ct, high_ct, top_end;
X vir_bytes vir, ct;
X phys_bytes user_phys;
X extern phys_bytes umap();
X
X mode = (fp->fl_opcode == DISK_READ ? DMA_READ : DMA_WRITE);
X vir = (vir_bytes) fp->fl_address;
X ct = (vir_bytes) fp->fl_count;
X user_phys = umap(proc_addr(fp->fl_procnr), D, vir, ct);
X low_addr = (int) (user_phys >> 0) & BYTE;
X high_addr = (int) (user_phys >> 8) & BYTE;
X top_addr = (int) (user_phys >> 16) & BYTE;
X low_ct = (int) ( (ct - 1) >> 0) & BYTE;
X high_ct = (int) ( (ct - 1) >> 8) & BYTE;
X
X /* Check to see if the transfer will require the DMA address counter to
X * go from one 64K segment to another. If so, do not even start it, since
X * the hardware does not carry from bit 15 to bit 16 of the DMA address.
X * Also check for bad buffer address. These errors mean FS contains a bug.
X */
X if (user_phys == 0) panic("FS gave floppy disk driver bad addr", (int) vir);
X top_end = (int) (((user_phys + ct - 1) >> 16) & BYTE);
X if (top_end != top_addr) panic("Trying to DMA across 64K boundary", top_addr);
X
X /* Now set up the DMA registers. */
X lock();
X port_out(DMA_M2, mode); /* set the DMA mode */
X port_out(DMA_M1, mode); /* set it again */
X port_out(DMA_ADDR, low_addr); /* output low-order 8 bits */
X port_out(DMA_ADDR, high_addr);/* output next 8 bits */
X port_out(DMA_TOP, top_addr); /* output highest 4 bits */
X port_out(DMA_COUNT, low_ct); /* output low 8 bits of count - 1 */
X port_out(DMA_COUNT, high_ct); /* output high 8 bits of count - 1 */
X unlock();
X port_out(DMA_INIT, 2); /* initialize DMA */
X}
X
X
X/*===========================================================================*
X * start_motor *
X *===========================================================================*/
XPRIVATE start_motor(fp)
Xstruct floppy *fp; /* pointer to the drive struct */
X{
X/* Control of the floppy disk motors is a big pain. If a motor is off, you
X * have to turn it on first, which takes 1/2 second. You can't leave it on
X * all the time, since that would wear out the diskette. However, if you turn
X * the motor off after each operation, the system performance will be awful.
X * The compromise used here is to leave it on for a few seconds after each
X * operation. If a new operation is started in that interval, it need not be
X * turned on again. If no new operation is started, a timer goes off and the
X * motor is turned off. I/O port DOR has bits to control each of 4 drives.
X * Interrupts must be disabled temporarily to prevent clock interrupt from
X * turning off motors while we are testing the bits.
X */
X
X int motor_bit, running, send_mess();
X
X lock(); /* no interrupts while checking out motor */
X motor_bit = 1 << (fp->fl_drive + 4); /* bit mask for this drive */
X motor_goal = motor_bit | ENABLE_INT | fp->fl_drive;
X if (motor_status & prev_motor) motor_goal |= prev_motor;
X running = motor_status & motor_bit; /* nonzero if this motor is running */
X port_out(DOR, motor_goal);
X motor_status = motor_goal;
X prev_motor = motor_bit; /* record motor started for next time */
X unlock();
X
X /* If the motor was already running, we don't have to wait for it. */
X if (running) return; /* motor was already running */
X clock_mess(mtr_setup[d], send_mess); /* motor was not running */
X receive(CLOCK, &mess); /* wait for clock interrupt */
X}
X
X
X/*===========================================================================*
X * stop_motor *
X *===========================================================================*/
XPRIVATE stop_motor()
X{
X/* This routine is called by the clock interrupt after several seconds have
X * elapsed with no floppy disk activity. It checks to see if any drives are
X * supposed to be turned off, and if so, turns them off.
X */
X
X if ( (motor_goal & MOTOR_MASK) != (motor_status & MOTOR_MASK) ) {
X port_out(DOR, motor_goal);
X motor_status = motor_goal;
X }
X}
X
X
X/*===========================================================================*
X * seek *
X *===========================================================================*/
XPRIVATE int seek(fp)
Xstruct floppy *fp; /* pointer to the drive struct */
X{
X/* Issue a SEEK command on the indicated drive unless the arm is already
X * positioned on the correct cylinder.
X */
X
X int r;
X extern int timeout();
X
X /* Are we already on the correct cylinder? */
X if (fp->fl_calibration == UNCALIBRATED)
X if (recalibrate(fp) != OK) return(ERR_SEEK);
X if (fp->fl_curcyl == fp->fl_cylinder) return(OK);
X
X /* No. Wrong cylinder. Issue a SEEK and wait for interrupt. */
X fdc_out(FDC_SEEK); /* start issuing the SEEK command */
X fdc_out( (fp->fl_head << 2) | fp->fl_drive);
X fdc_out(fp->fl_cylinder * steps_per_cyl[d]);
X if (need_reset) return(ERR_SEEK); /* if controller is sick, abort seek */
X receive(HARDWARE, &mess);
X
X /* Interrupt has been received. Check drive status. */
X fdc_out(FDC_SENSE); /* probe FDC to make it return status */
X r = fdc_results(fp); /* get controller status bytes */
X if ( (fp->fl_results[ST0] & ST0_BITS) != SEEK_ST0) r = ERR_SEEK;
X if (fp->fl_results[ST1] != fp->fl_cylinder * steps_per_cyl[d]) r = ERR_SEEK;
X if (r != OK)
X if (recalibrate(fp) != OK) return(ERR_SEEK);
X return(r);
X}
X
X
X/*===========================================================================*
X * transfer *
X *===========================================================================*/
XPRIVATE int transfer(fp)
Xregister struct floppy *fp; /* pointer to the drive struct */
X{
X/* The drive is now on the proper cylinder. Read or write 1 block. */
X
X int r, s, op;
X extern int olivetti;
X extern int timeout();
X
X /* Never attempt a transfer if the drive is uncalibrated or motor is off. */
X if (fp->fl_calibration == UNCALIBRATED) return(ERR_TRANSFER);
X if ( ( (motor_status>>(fp->fl_drive+4)) & 1) == 0) return(ERR_TRANSFER);
X
X /* The PC-AT requires the date rate to be set to 250 or 500 kbps */
X if (hw_id == IBMAT) port_out(FDC_RATE, rate[d]);
X
X /* The command is issued by outputing 9 bytes to the controller chip. */
X op = (fp->fl_opcode == DISK_READ ? FDC_READ : FDC_WRITE);
X fdc_out(op); /* issue the read or write command */
X fdc_out( (fp->fl_head << 2) | fp->fl_drive);
X fdc_out(fp->fl_cylinder); /* tell controller which cylinder */
X fdc_out(fp->fl_head); /* tell controller which head */
X fdc_out(fp->fl_sector); /* tell controller which sector */
X fdc_out( (int) len[SECTOR_SIZE/DIVISOR]); /* sector size */
X fdc_out(nr_sectors[d]); /* tell controller how big a track is */
X fdc_out(gap[d]); /* tell controller how big sector gap is */
X fdc_out(DTL); /* tell controller about data length */
X
X /* Block, waiting for disk interrupt. */
X if (need_reset) return(ERR_TRANSFER); /* if controller is sick, abort op */
X clock_mess(TIMEOUT,timeout); /* start timer */
X active_timeout = TRUE; /* and set flag to remember this */
X
X receive(HARDWARE, &mess);
X
X /* Check for timeout */
X if (active_timeout == FALSE) return(ERR_TIMEOUT);
X active_timeout = FALSE; /* all done, forget about timeout */
X
X /* Get controller status and check for errors. */
X r = fdc_results(fp);
X if (r != OK) return(r);
X if ( (fp->fl_results[ST1] & BAD_SECTOR) || (fp->fl_results[ST2] & BAD_CYL) )
X fp->fl_calibration = UNCALIBRATED;
X if (fp->fl_results[ST1] & WRITE_PROTECT) {
X printf("Diskette in drive %d is write protected.\n", fp->fl_drive);
X return(ERR_WR_PROTECT);
X }
X if ((fp->fl_results[ST0] & ST0_BITS) != TRANS_ST0) return(ERR_TRANSFER);
X if (fp->fl_results[ST1] | fp->fl_results[ST2]) return(ERR_TRANSFER);
X
X /* Compare actual numbers of sectors transferred with expected number. */
X s = (fp->fl_results[ST_CYL] - fp->fl_cylinder) * NR_HEADS * nr_sectors[d];
X s += (fp->fl_results[ST_HEAD] - fp->fl_head) * nr_sectors[d];
X s += (fp->fl_results[ST_SEC] - fp->fl_sector);
X if (s * SECTOR_SIZE != fp->fl_count) return(ERR_TRANSFER);
X return(OK);
X}
X
X/*===========================================================================*
X * timeout *
X *===========================================================================*/
XPRIVATE int timeout()
X{
X/* The NEC 765 fdc has its ready line tied to Vcc. So it's impossible
X * to check a drives ready state. If a drive isn't ready and a read or
X * write is started in transfer(), the fdc waits until the drive gets ready.
X * This blocks both the floppy task and FS until the drive gets ready.
X * Solution :
X * Before transfer() does a receive() it starts a timeout.
X * If the timer runs out this routine is called. When no interrupt has
X * occured in the mean time (active_timeout still TRUE) the disk probably
X * isn't ready. To get the floppy task out of its deadlock the fdc is reset.
X * After a reset the fdc detects 'drive-ready' (ready line still tied to
X * Vcc !!) and generates a 'drive-status-changed' interrupt (see 765 spec.)
X * The interrupt routine sends a message to the floppy task which readies
X * the floppy task.
X * As usual the problem is with the IBM PC hardware.
X */
X
X if (active_timeout == FALSE) return; /* no work to do */
X
X /* Start fdc reset */
X lock();
X port_out(DOR, 0); /* strobe reset bit low */
X port_out(DOR, ENABLE_INT); /* strobe it high again */
X unlock(); /* interrupts allowed again */
X
X need_reset = TRUE;
X active_timeout = FALSE;
X}
X
X/*===========================================================================*
X * fdc_results *
X *===========================================================================*/
XPRIVATE int fdc_results(fp)
Xregister struct floppy *fp; /* pointer to the drive struct */
X{
X/* Extract results from the controller after an operation. */
X
X int i, j, status, ready;
X
X /* Loop, extracting bytes from FDC until it says it has no more. */
X for (i = 0; i < MAX_RESULTS; i++) {
X ready = FALSE;
X for (j = 0; j < MAX_FDC_RETRY; j++) {
X port_in(FDC_STATUS, &status);
X if (status & MASTER) {
X ready = TRUE;
X break;
X }
X }
X if (ready == FALSE) return(ERR_STATUS); /* time out */
X
X if ((status & CTL_BUSY) == 0) return(OK);
X if ((status & DIRECTION) == 0) return(ERR_STATUS);
X port_in(FDC_DATA, &status);
X fp->fl_results[i] = status & BYTE;
X }
X
X /* FDC is giving back too many results. */
X need_reset = TRUE; /* controller chip must be reset */
X return(ERR_STATUS);
X}
X
X
X/*===========================================================================*
X * fdc_out *
X *===========================================================================*/
XPRIVATE fdc_out(val)
Xint val; /* write this byte to floppy disk controller */
X{
X/* Output a byte to the controller. This is not entirely trivial, since you
X * can only write to it when it is listening, and it decides when to listen.
X * If the controller refuses to listen, the FDC chip is given a hard reset.
X */
X
X int retries, r;
X
X if (need_reset) return; /* if controller is not listening, return */
X retries = MAX_FDC_RETRY;
X
X /* It may take several tries to get the FDC to accept a command. */
X while (retries-- > 0) {
X port_in(FDC_STATUS, &r);
X r &= (MASTER | DIRECTION); /* just look at bits 2 and 3 */
X if (r != CTL_ACCEPTING) continue; /* FDC is not listening */
X port_out(FDC_DATA, val);
X return;
X }
X
X /* Controller is not listening. Hit it over the head with a hammer. */
X need_reset = TRUE;
X}
X
X
X/*===========================================================================*
X * recalibrate *
X *===========================================================================*/
XPRIVATE int recalibrate(fp)
Xregister struct floppy *fp; /* pointer tot he drive struct */
X{
X/* The floppy disk controller has no way of determining its absolute arm
X * position (cylinder). Instead, it steps the arm a cylinder at a time and
X * keeps track of where it thinks it is (in software). However, after a
X * SEEK, the hardware reads information from the diskette telling where the
X * arm actually is. If the arm is in the wrong place, a recalibration is done,
X * which forces the arm to cylinder 0. This way the controller can get back
X * into sync with reality.
X */
X
X int r;
X /* Issue the RECALIBRATE command and wait for the interrupt. */
X start_motor(fp); /* can't recalibrate with motor off */
X fdc_out(FDC_RECALIBRATE); /* tell drive to recalibrate itself */
X fdc_out(fp->fl_drive); /* specify drive */
X if (need_reset) return(ERR_SEEK); /* don't wait if controller is sick */
X receive(HARDWARE, &mess); /* wait for interrupt message */
X
X /* Determine if the recalibration succeeded. */
X fdc_out(FDC_SENSE); /* issue SENSE command to see where we are */
X r = fdc_results(fp); /* get results of the SENSE command */
X fp->fl_curcyl = -1; /* force a SEEK next time */
X if (r != OK || /* controller would not respond */
X (fp->fl_results[ST0]&ST0_BITS) != SEEK_ST0 || fp->fl_results[ST_PCN] !=0){
X /* Recalibration failed. FDC must be reset. */
X need_reset = TRUE;
X fp->fl_calibration = UNCALIBRATED;
X return(ERR_RECALIBRATE);
X } else {
X /* Recalibration succeeded. */
X fp->fl_calibration = CALIBRATED;
X return(OK);
X }
X}
X
X/*===========================================================================*
X * reset *
X *===========================================================================*/
XPRIVATE reset()
X{
X/* Issue a reset to the controller. This is done after any catastrophe,
X * like the controller refusing to respond.
X */
X
X int i, r, status;
X register struct floppy *fp;
X
X /* Disable interrupts and strobe reset bit low. */
X need_reset = FALSE;
X lock();
X motor_status = 0;
X motor_goal = 0;
X port_out(DOR, 0); /* strobe reset bit low */
X port_out(DOR, ENABLE_INT); /* strobe it high again */
X unlock(); /* interrupts allowed again */
X receive(HARDWARE, &mess); /* collect the RESET interrupt */
X
X /* Interrupt from the reset has been received. Continue resetting. */
X fp = &floppy[0]; /* use floppy[0] for scratch */
X fp->fl_results[0] = 0; /* this byte will be checked shortly */
X fdc_out(FDC_SENSE); /* did it work? */
X r = fdc_results(fp); /* get results */
X status = fp->fl_results[0] & BYTE;
X
X /* Tell FDC drive parameters. */
X fdc_out(FDC_SPECIFY); /* specify some timing parameters */
X fdc_out(SPEC1); /* step-rate and head-unload-time */
X fdc_out(SPEC2); /* head-load-time and non-dma */
X
X for (i = 0; i < NR_DRIVES; i++) floppy[i].fl_calibration = UNCALIBRATED;
X
X nresets++; /* count this reset */
X}
X
X
X/*===========================================================================*
X * clock_mess *
X *===========================================================================*/
XPRIVATE clock_mess(ticks, func)
Xint ticks; /* how many clock ticks to wait */
Xint (*func)(); /* function to call upon time out */
X{
X/* Send the clock task a message. */
X
X mess.m_type = SET_ALARM;
X mess.CLOCK_PROC_NR = FLOPPY;
X mess.DELTA_TICKS = ticks;
X mess.FUNC_TO_CALL = func;
X sendrec(CLOCK, &mess);
X}
X
X
X/*===========================================================================*
X * send_mess *
X *===========================================================================*/
XPRIVATE send_mess()
X{
X/* This routine is called when the clock task has timed out on motor startup.*/
X
X mess.m_type = MOTOR_RUNNING;
X send(FLOPPY, &mess);
X}
*-*-END-of-k_floppy.c-*-*
echo x - k_glo.h
sed 's/^X//' >k_glo.h <<'*-*-END-of-k_glo.h-*-*'
X/* Global variables used in the kernel. */
X
X/* Clocks and timers */
XEXTERN real_time realtime; /* real time clock */
XEXTERN int lost_ticks; /* incremented when clock int can't send mess*/
X
X/* Processes, signals, and messages. */
XEXTERN int cur_proc; /* current process */
XEXTERN int prev_proc; /* previous process */
XEXTERN int sig_procs; /* number of procs with p_pending != 0 */
XEXTERN message int_mess; /* interrupt routines build message here */
X
X/* CPU type. */
XEXTERN int olivetti; /* TRUE for Olivetti-style keyboard */
XEXTERN int hw_id; /* identification of hardware */
X
X/* The kernel and task stacks. */
XEXTERN struct t_stack {
X int stk[TASK_STACK_BYTES/sizeof(int)];
X} t_stack[NR_TASKS - 1]; /* task stacks; task = -1 never really runs */
X
XEXTERN char k_stack[K_STACK_BYTES]; /* The kernel stack. */
*-*-END-of-k_glo.h-*-*
echo x - k_main.c
sed 's/^X//' >k_main.c <<'*-*-END-of-k_main.c-*-*'
X/* This file contains the main program of MINIX. The routine main()
X * initializes the system and starts the ball rolling by setting up the proc
X * table, interrupt vectors, and scheduling each task to run to initialize
X * itself.
X *
X * The entries into this file are:
X * main: MINIX main program
X * unexpected_int: called when an interrupt to an unused vector < 16 occurs
X * trap: called when an unexpected trap to a vector >= 16 occurs
X * panic: abort MINIX due to a fatal error
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/callnr.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "const.h"
X#include "type.h"
X#include "glo.h"
X#include "proc.h"
X
X#define SAFETY 8 /* margin of safety for stack overflow (ints)*/
X#define VERY_BIG 39328 /* must be bigger than kernel size (clicks) */
X#define BASE 1536 /* address where MINIX starts in memory */
X#define SIZES 8 /* sizes array has 8 entries */
X#define CPU_TY1 0xFFFF /* BIOS segment that tells CPU type */
X#define CPU_TY2 0x000E /* BIOS offset that tells CPU type */
X#define PC_AT 0xFC /* IBM code for PC-AT (in BIOS at 0xFFFFE) */
X
X/*===========================================================================*
X * main *
X *===========================================================================*/
XPUBLIC main()
X{
X/* Start the ball rolling. */
X
X register struct proc *rp;
X register int t;
X vir_clicks size;
X phys_clicks base_click, mm_base, previous_base;
X phys_bytes phys_b;
X extern unsigned sizes[8]; /* table filled in by build */
X extern int color, vec_table[], get_chrome(), (*task[])();
X extern int s_call(), disk_int(), tty_int(), clock_int(), disk_int();
X extern int wini_int(), lpr_int(), surprise(), trp(), divide();
X extern phys_bytes umap();
X
X /* Set up proc table entry for user processes. Be very careful about
X * sp, since the 3 words prior to it will be clobbered when the kernel pushes
X * pc, cs, and psw onto the USER's stack when starting the user the first
X * time. This means that with initial sp = 0x10, user programs must leave
X * the words at 0x000A, 0x000C, and 0x000E free.
X */
X
X lock(); /* we can't handle interrupts yet */
X base_click = BASE >> CLICK_SHIFT;
X size = sizes[0] + sizes[1]; /* kernel text + data size in clicks */
X mm_base = base_click + size; /* place where MM starts (in clicks) */
X
X for (rp = &proc[0]; rp <= &proc[NR_TASKS+LOW_USER]; rp++) {
X for (t=0; t< NR_REGS; t++) rp->p_reg[t] = 0100*t; /* debugging */
X t = rp - proc - NR_TASKS; /* task number */
X rp->p_sp = (rp < &proc[NR_TASKS] ? t_stack[NR_TASKS+t+1].stk : INIT_SP);
X rp->p_splimit = rp->p_sp;
X if (rp->p_splimit != INIT_SP)
X rp->p_splimit -= (TASK_STACK_BYTES - SAFETY)/sizeof(int);
X rp->p_pcpsw.pc = task[t + NR_TASKS];
X if (rp->p_pcpsw.pc != 0 || t >= 0) ready(rp);
X rp->p_pcpsw.psw = INIT_PSW;
X rp->p_flags = 0;
X
X /* Set up memory map for tasks and MM, FS, INIT. */
X if (t < 0) {
X /* I/O tasks. */
X rp->p_map[T].mem_len = VERY_BIG;
X rp->p_map[T].mem_phys = base_click;
X rp->p_map[D].mem_len = VERY_BIG;
X rp->p_map[D].mem_phys = base_click + sizes[0];
X rp->p_map[S].mem_len = VERY_BIG;
X rp->p_map[S].mem_phys = base_click + sizes[0] + sizes[1];
X rp->p_map[S].mem_vir = sizes[0] + sizes[1];
X } else {
X /* MM, FS, and INIT. */
X previous_base = proc[NR_TASKS + t - 1].p_map[S].mem_phys;
X rp->p_map[T].mem_len = sizes[2*t + 2];
X rp->p_map[T].mem_phys = (t == 0 ? mm_base : previous_base);
X rp->p_map[D].mem_len = sizes[2*t + 3];
X rp->p_map[D].mem_phys = rp->p_map[T].mem_phys + sizes[2*t + 2];
X rp->p_map[S].mem_vir = sizes[2*t + 3];
X rp->p_map[S].mem_phys = rp->p_map[D].mem_phys + sizes[2*t + 3];
X }
X
X#ifdef i8088
X rp->p_reg[CS_REG] = rp->p_map[T].mem_phys;
X rp->p_reg[DS_REG] = rp->p_map[D].mem_phys;
X rp->p_reg[SS_REG] = rp->p_map[D].mem_phys;
X rp->p_reg[ES_REG] = rp->p_map[D].mem_phys;
X#endif
X }
X
X proc[NR_TASKS+(HARDWARE)].p_sp = (int *) k_stack;
X proc[NR_TASKS+(HARDWARE)].p_sp += K_STACK_BYTES/2;
X proc[NR_TASKS+(HARDWARE)].p_splimit = (int *) k_stack;
X proc[NR_TASKS+(HARDWARE)].p_splimit += SAFETY/2;
X
X for (rp = proc_addr(LOW_USER+1); rp < proc_addr(NR_PROCS); rp++)
X rp->p_flags = P_SLOT_FREE;
X
X /* Determine if display is color or monochrome and CPU type (from BIOS). */
X color = get_chrome(); /* 0 = mono, 1 = color */
X hw_id = UNKNOWN;
X t = get_byte(CPU_TY1, CPU_TY2); /* is this PC, XT, AT ... ? */
X if (t == PC_AT) hw_id = IBMAT;
X if (hw_id == UNKNOWN && is_m24() == OK) hw_id = M24;
X
X /* Save the old interrupt vectors. */
X phys_b = umap(proc_addr(HARDWARE), D, (vir_bytes) vec_table, VECTOR_BYTES);
X phys_copy(0L, phys_b, (long) VECTOR_BYTES); /* save all the vectors */
X
X /* Set up the new interrupt vectors. */
X for (t = 0; t < 16; t++) set_vec(t, surprise, base_click);
X for (t = 16; t < 256; t++) set_vec(t, trp, base_click);
X set_vec(DIVIDE_VECTOR, divide, base_click);
X set_vec(SYS_VECTOR, s_call, base_click);
X set_vec(CLOCK_VECTOR, clock_int, base_click);
X set_vec(KEYBOARD_VECTOR, tty_int, base_click);
X set_vec(FLOPPY_VECTOR, disk_int, base_click);
X set_vec(PRINTER_VECTOR, lpr_int, base_click);
X if (hw_id == IBMAT)
X set_vec(AT_WINI_VECTOR, wini_int, base_click);
X else
X set_vec(XT_WINI_VECTOR, wini_int, base_click);
X
X /* Put a ptr to proc table in a known place so it can be found in /dev/mem */
X set_vec( (BASE - 4)/4, proc, (phys_clicks) 0);
X
X bill_ptr = proc_addr(HARDWARE); /* it has to point somewhere */
X pick_proc();
X
X /* Now go to the assembly code to start running the current process. */
X port_out(INT_CTLMASK, 0); /* do not mask out any interrupts in 8259A */
X port_out(INT2_MASK, 0); /* same for second interrupt controller */
X restart();
X}
X
X
X/*===========================================================================*
X * unexpected_int *
X *===========================================================================*/
XPUBLIC unexpected_int()
X{
X/* A trap or interrupt has occurred that was not expected. */
X
X printf("Unexpected trap: vector < 16\n");
X printf("pc = 0x%x text+data+bss = 0x%x\n",proc_ptr->p_pcpsw.pc,
X proc_ptr->p_map[D].mem_len<<4);
X}
X
X
X/*===========================================================================*
X * trap *
X *===========================================================================*/
XPUBLIC trap()
X{
X/* A trap (vector >= 16) has occurred. It was not expected. */
X
X printf("\nUnexpected trap: vector >= 16 ");
X printf("This may be due to accidentally including\n");
X printf("a non-MINIX library routine that is trying to make a system call.\n");
X printf("pc = 0x%x text+data+bss = 0x%x\n",proc_ptr->p_pcpsw.pc,
X proc_ptr->p_map[D].mem_len<<4);
X}
X
X
X/*===========================================================================*
X * div_trap *
X *===========================================================================*/
XPUBLIC div_trap()
X{
X/* The divide intruction traps to vector 0 upon overflow. */
X
X printf("Trap to vector 0: divide overflow. ");
X printf("pc = 0x%x text+data+bss = 0x%x\n",proc_ptr->p_pcpsw.pc,
X proc_ptr->p_map[D].mem_len<<4);
X}
X
X
X/*===========================================================================*
X * panic *
X *===========================================================================*/
XPUBLIC panic(s,n)
Xchar *s;
Xint n;
X{
X/* The system has run aground of a fatal error. Terminate execution.
X * If the panic originated in MM or FS, the string will be empty and the
X * file system already syncked. If the panic originates in the kernel, we are
X * kind of stuck.
X */
X
X if (*s != 0) {
X printf("\nKernel panic: %s",s);
X if (n != NO_NUM) printf(" %d", n);
X printf("\n");
X }
X printf("\nType space to reboot\n");
X wreboot();
X
X}
X
X#ifdef i8088
X/*===========================================================================*
X * set_vec *
X *===========================================================================*/
XPRIVATE set_vec(vec_nr, addr, base_click)
Xint vec_nr; /* which vector */
Xint (*addr)(); /* where to start */
Xphys_clicks base_click; /* click where kernel sits in memory */
X{
X/* Set up an interrupt vector. */
X
X unsigned vec[2];
X unsigned u;
X phys_bytes phys_b;
X extern unsigned sizes[8];
X
X /* Build the vector in the array 'vec'. */
X vec[0] = (unsigned) addr;
X vec[1] = (unsigned) base_click;
X u = (unsigned) vec;
X
X /* Copy the vector into place. */
X phys_b = ( (phys_bytes) base_click + (phys_bytes) sizes[0]) << CLICK_SHIFT;
X phys_b += u;
X phys_copy(phys_b, (phys_bytes) 4*vec_nr, (phys_bytes) 4);
X}
X#endif
X
X/*===========================================================================*
X * is_m24 *
X *===========================================================================*/
XPRIVATE is_m24()
X{
X/* Reads the BIOS to to check is the hardware is a Olivetti M24
X * This routine works for BIOS versions 1.1, 1.21 and 1.36
X */
X
X char buffer[9];
X phys_bytes buffaddr;
X
X /* read copyright string at FC00:50 */
X buffaddr = umap(proc_addr(HARDWARE), D, (vir_bytes) buffer, 8);
X phys_copy(0xFC050L, buffaddr, 8L);
X
X /* test string */
X buffer[8] = '\0';
X if(strcmp(buffer,"OLIVETTI") == 0)
X return(TRUE);
X return(FALSE);
X}
*-*-END-of-k_main.c-*-*
echo x - k_make.
sed 's/^X//' >k_make. <<'*-*-END-of-k_make.-*-*'
X# The kernel directory contains files xt_wini.c and at_wini.c. Before running
X# make you must copy one of these to wini.c, depending on whether you have a
X# PC or an AT. You must do this even if you do not have a hard disk..
XCFLAGS= -Di8088 -w -F -T.
Xh=../h
Xl=/usr/lib
X
Xobj = mpx88.s main.s proc.s system.s tty.s clock.s memory.s floppy.s wini.s \
X printer.s table.s klib88.s dmp.s
X
Xkernel: makefile $(obj) $l/libc.a
X# @echo "Start linking Kernel. /lib/* will be removed to make space on RAM disk"
X# @rm -f /lib/cem /lib/cpp /tmp/*
X# @asld -o kernel $(obj) $l/libc.a $l/end.s
X# @echo "Kernel done. Please restore /lib/cem and /lib/cpp manually"
X @echo "Start linking Kernel."
X @asld -o kernel -T. $(obj) $l/libc.a $l/end.s
X @echo "Kernel done."
X
Xclock.s: const.h type.h $h/const.h $h/type.h
Xclock.s: $h/callnr.h
Xclock.s: $h/com.h
Xclock.s: $h/error.h
Xclock.s: $h/signal.h
Xclock.s: glo.h
Xclock.s: proc.h
X
Xfloppy.s: const.h type.h $h/const.h $h/type.h
Xfloppy.s: $h/callnr.h
Xfloppy.s: $h/com.h
Xfloppy.s: $h/error.h
Xfloppy.s: glo.h
Xfloppy.s: proc.h
X
X
Xdmp.s: const.h type.h $h/const.h $h/type.h
Xdmp.s: $h/callnr.h
Xdmp.s: $h/com.h
Xdmp.s: $h/error.h
Xdmp.s: glo.h
Xdmp.s: proc.h
X
Xmain.s: const.h type.h $h/const.h $h/type.h
Xmain.s: $h/callnr.h
Xmain.s: $h/com.h
Xmain.s: $h/error.h
Xmain.s: glo.h
Xmain.s: proc.h
X
Xmemory.s: const.h type.h $h/const.h $h/type.h
Xmemory.s: $h/callnr.h
Xmemory.s: $h/com.h
Xmemory.s: $h/error.h
Xmemory.s: proc.h
X
Xprinter.s: const.h type.h $h/const.h $h/type.h
Xprinter.s: $h/callnr.h
Xprinter.s: $h/com.h
Xprinter.s: $h/error.h
X
Xproc.s: const.h type.h $h/const.h $h/type.h
Xproc.s: $h/callnr.h
Xproc.s: $h/com.h
Xproc.s: $h/error.h
Xproc.s: glo.h
Xproc.s: proc.h
X
Xsystem.s: const.h type.h $h/const.h $h/type.h
Xsystem.s: $h/callnr.h
Xsystem.s: $h/com.h
Xsystem.s: $h/error.h
Xsystem.s: $h/signal.h
Xsystem.s: glo.h
Xsystem.s: proc.h
X
Xtable.s: const.h type.h $h/const.h $h/type.h
Xtable.s: glo.h
Xtable.s: proc.h
X
Xtty.s: const.h type.h $h/const.h $h/type.h
Xtty.s: $h/callnr.h
Xtty.s: $h/com.h
Xtty.s: $h/error.h
Xtty.s: $h/sgtty.h
Xtty.s: $h/signal.h
Xtty.s: glo.h
Xtty.s: proc.h
X
Xwini.s: const.h type.h $h/const.h $h/type.h
Xwini.s: $h/callnr.h
Xwini.s: $h/com.h
Xwini.s: $h/error.h
Xwini.s: proc.h
*-*-END-of-k_makmmmb d; /* sch@oce.nl (Jakob Schripsema) (04/27/87)
echo x - k_proc.c
sed 's/^X//' >k_proc.c <<'*-*-END-of-k_proc.c-*-*'
X/* This file contains essentially all of the process and message handling.
X * It has two main entry points from the outside:
X *
X * sys_call: called when a process or task does SEND, RECEIVE or SENDREC
X * interrupt: called by interrupt routines to send a message to task
X *
X * It also has five minor entry points:
X *
X * ready: put a process on one of the ready queues so it can be run
X * unready: remove a process from the ready queues
X * sched: a process has run too long; schedule another one
X * mini_send: send a message (used by interrupt signals, etc.)
X * pick_proc: pick a process to run (used by system initialization)
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/callnr.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "const.h"
X#include "type.h"
X#include "glo.h"
X#include "proc.h"
X
X/*===========================================================================*
X * interrupt *
X *===========================================================================*/
XPUBLIC interrupt(task, m_ptr)
Xint task; /* number of task to be started */
Xmessage *m_ptr; /* interrupt message to send to the task */
X{
X/* An interrupt has occurred. Schedule the task that handles it. */
X
X int i, n, old_map, this_bit;
X
X#ifdef i8088
X /* Re-enable the 8259A interrupt controller. */
X port_out(INT_CTL, ENABLE); /* this re-enables the 8259A controller chip */
X if (hw_id == IBMAT) port_out(INT2_CTL, ENABLE); /* re-enable second 8259A */
X#endif
X
X /* Try to send the interrupt message to the indicated task. */
X this_bit = 1 << (-task);
X if (mini_send(HARDWARE, task, m_ptr) != OK) {
X /* The message could not be sent to the task; it was not waiting. */
X old_map = busy_map; /* save original map of busy tasks */
X if (task == CLOCK) {
X lost_ticks++;
X } else {
X busy_map |= this_bit; /* mark task as busy */
X task_mess[-task] = m_ptr; /* record message pointer */
X }
X } else {
X /* Hardware interrupt was successfully sent as a message. */
X busy_map &= ~this_bit; /* turn off the bit in case it was on */
X old_map = busy_map;
X }
X
X /* See if any tasks that were previously busy are now listening for msgs. */
X if (old_map != 0) {
X for (i = 2; i <= NR_TASKS; i++) {
X /* Check each task looking for one with a pending interrupt. */
X if ( (old_map>>i) & 1) {
X /* Task 'i' has a pending interrupt. */
X n = mini_send(HARDWARE, -i, task_mess[i]);
X if (n == OK) busy_map &= ~(1 << i);
X }
X }
X }
X
X /* If a task has just been readied and a user is running, run the task. */
X if (rdy_head[TASK_Q] != NIL_PROC && (cur_proc >= 0 || cur_proc == IDLE))
X pick_proc();
X}
X
X
X/*===========================================================================*
X * sys_call *
X *===========================================================================*/
XPUBLIC sys_call(function, caller, src_dest, m_ptr)
Xint function; /* SEND, RECEIVE, or BOTH */
Xint caller; /* who is making this call */
Xint src_dest; /* source to receive from or dest to send to */
Xmessage *m_ptr; /* pointer to message */
X{
X/* The only system calls that exist in MINIX are sending and receiving
X * messages. These are done by trapping to the kernel with an INT instruction.
X * The trap is caught and sys_call() is called to send or receive a message (or
X * both).
X */
X
X register struct proc *rp;
X int n;
X
X /* Check for bad system call parameters. */
X rp = proc_addr(caller);
X if (src_dest < -NR_TASKS || (src_dest >= NR_PROCS && src_dest != ANY) ) {
X rp->p_reg[RET_REG] = E_BAD_SRC;
X return;
X }
X if (function != BOTH && caller >= LOW_USER) {
X rp->p_reg[RET_REG] = E_NO_PERM; /* users only do BOTH */
X return;
X }
X
X /* The parameters are ok. Do the call. */
X if (function & SEND) {
X n = mini_send(caller, src_dest, m_ptr); /* func = SEND or BOTH */
X if (function == SEND || n != OK) rp->p_reg[RET_REG] = n;
X if (n != OK) return; /* SEND failed */
X }
X
X if (function & RECEIVE) {
X n = mini_rec(caller, src_dest, m_ptr); /* func = RECEIVE or BOTH */
X rp->p_reg[RET_REG] = n;
X }
X}
X
X/*===========================================================================*
X * mini_send *
X *===========================================================================*/
XPUBLIC int mini_send(caller, dest, m_ptr)
Xint caller; /* who is trying to send a message? */
Xint dest; /* to whom is message being sent? */
Xmessage *m_ptr; /* pointer to message buffer */
X{
X/* Send a message from 'caller' to 'dest'. If 'dest' is blocked waiting for
X * this message, copy the message to it and unblock 'dest'. If 'dest' is not
X * waiting at all, or is waiting for another source, queue 'caller'.
X */
X
X register struct proc *caller_ptr, *dest_ptr, *next_ptr;
X vir_bytes vb; /* message buffer pointer as vir_bytes */
X vir_clicks vlo, vhi; /* virtual clicks containing message to send */
X vir_clicks len; /* length of data segment in clicks */
X
X /* User processes are only allowed to send to FS and MM. Check for this. */
X if (caller >= LOW_USER && (dest != FS_PROC_NR && dest != MM_PROC_NR))
X return(E_BAD_DEST);
X caller_ptr = proc_addr(caller); /* pointer to source's proc entry */
X dest_ptr = proc_addr(dest); /* pointer to destination's proc entry */
X if (dest_ptr->p_flags & P_SLOT_FREE) return(E_BAD_DEST); /* dead dest */
X
X /* Check for messages wrapping around top of memory or outside data seg. */
X len = caller_ptr->p_map[D].mem_len;
X vb = (vir_bytes) m_ptr;
X vlo = vb >> CLICK_SHIFT; /* vir click for bottom of message */
X vhi = (vb + MESS_SIZE - 1) >> CLICK_SHIFT; /* vir click for top of message */
X if (vhi < vlo || vhi - caller_ptr->p_map[D].mem_vir >= len)return(E_BAD_ADDR);
X
X /* Check to see if 'dest' is blocked waiting for this message. */
X if ( (dest_ptr->p_flags & RECEIVING) &&
X (dest_ptr->p_getfrom == ANY || dest_ptr->p_getfrom == caller) ) {
X /* Destination is indeed waiting for this message. */
X cp_mess(caller, caller_ptr->p_map[D].mem_phys, m_ptr,
X dest_ptr->p_map[D].mem_phys, dest_ptr->p_messbuf);
X dest_ptr->p_flags &= ~RECEIVING; /* deblock destination */
X if (dest_ptr->p_flags == 0) ready(dest_ptr);
X } else {
X /* Destination is not waiting. Block and queue caller. */
X if (caller == HARDWARE) return(E_OVERRUN);
X caller_ptr->p_messbuf = m_ptr;
X caller_ptr->p_flags |= SENDING;
X unready(caller_ptr);
X
X /* Process is now blocked. Put in on the destination's queue. */
X if ( (next_ptr = dest_ptr->p_callerq) == NIL_PROC) {
X dest_ptr->p_callerq = caller_ptr;
X } else {
X while (next_ptr->p_sendlink != NIL_PROC)
X next_ptr = next_ptr->p_sendlink;
X next_ptr->p_sendlink = caller_ptr;
X }
X caller_ptr->p_sendlink = NIL_PROC;
X }
X return(OK);
X}
X
X
X/*===========================================================================*
X * mini_rec *
X *===========================================================================*/
XPRIVATE int mini_rec(caller, src, m_ptr)
Xint caller; /* process trying to get message */
Xint src; /* which message source is wanted (or ANY) */
Xmessage *m_ptr; /* pointer to message buffer */
X{
X/* A process or task wants to get a message. If one is already queued,
X * acquire it and deblock the sender. If no message from the desired source
X * is available, block the caller. No need to check parameters for validity.
X * Users calls are always sendrec(), and mini_send() has checked already.
X * Calls from the tasks, MM, and FS are trusted.
X */
X
X register struct proc *caller_ptr, *sender_ptr, *prev_ptr;
X int sender;
X
X caller_ptr = proc_addr(caller); /* pointer to caller's proc structure */
X
X /* Check to see if a message from desired source is already available. */
X sender_ptr = caller_ptr->p_callerq;
X while (sender_ptr != NIL_PROC) {
X sender = sender_ptr - proc - NR_TASKS;
X if (src == ANY || src == sender) {
X /* An acceptable message has been found. */
X cp_mess(sender, sender_ptr->p_map[D].mem_phys, sender_ptr->p_messbuf,
X caller_ptr->p_map[D].mem_phys, m_ptr);
X sender_ptr->p_flags &= ~SENDING; /* deblock sender */
X if (sender_ptr->p_flags == 0) ready(sender_ptr);
X if (sender_ptr == caller_ptr->p_callerq)
X caller_ptr->p_callerq = sender_ptr->p_sendlink;
X else
X prev_ptr->p_sendlink = sender_ptr->p_sendlink;
X return(OK);
X }
X prev_ptr = sender_ptr;
X sender_ptr = sender_ptr->p_sendlink;
X }
X
X /* No suitable message is available. Block the process trying to receive. */
X caller_ptr->p_getfrom = src;
X caller_ptr->p_messbuf = m_ptr;
X caller_ptr->p_flags |= RECEIVING;
X unready(caller_ptr);
X
X /* If MM has just blocked and there are kernel signals pending, now is the
X * time to tell MM about them, since it will be able to accept the message.
X */
X if (sig_procs > 0 && caller == MM_PROC_NR && src == ANY) inform(MM_PROC_NR);
X return(OK);
X}
X
X
X/*===========================================================================*
X * pick_proc *
X *===========================================================================*/
XPUBLIC pick_proc()
X{
X/* Decide who to run now. */
X
X register int q; /* which queue to use */
X
X if (rdy_head[TASK_Q] != NIL_PROC) q = TASK_Q;
X else if (rdy_head[SERVER_Q] != NIL_PROC) q = SERVER_Q;
X else q = USER_Q;
X
X /* Set 'cur_proc' and 'proc_ptr'. If system is idle, set 'cur_proc' to a
X * special value (IDLE), and set 'proc_ptr' to point to an unused proc table
X * slot, namely, that of task -1 (HARDWARE), so save() will have somewhere to
X * deposit the registers when a interrupt occurs on an idle machine.
X * Record previous process so that when clock tick happens, the clock task
X * can find out who was running just before it began to run. (While the
X * clock task is running, 'cur_proc' = CLOCKTASK. In addition, set 'bill_ptr'
X * to always point to the process to be billed for CPU time.
X */
X prev_proc = cur_proc;
X if (rdy_head[q] != NIL_PROC) {
X /* Someone is runnable. */
X cur_proc = rdy_head[q] - proc - NR_TASKS;
X proc_ptr = rdy_head[q];
X if (cur_proc >= LOW_USER) bill_ptr = proc_ptr;
X } else {
X /* No one is runnable. */
X cur_proc = IDLE;
X proc_ptr = proc_addr(HARDWARE);
X bill_ptr = proc_ptr;
X }
X}
X
X/*===========================================================================*
X * ready *
X *===========================================================================*/
XPUBLIC ready(rp)
Xregister struct proc *rp; /* this process is now runnable */
X{
X/* Add 'rp' to the end of one of the queues of runnable processes. Three
X * queues are maintained:
X * TASK_Q - (highest priority) for runnable tasks
X * SERVER_Q - (middle priority) for MM and FS only
X * USER_Q - (lowest priority) for user processes
X */
X
X register int q; /* TASK_Q, SERVER_Q, or USER_Q */
X int r;
X
X lock(); /* disable interrupts */
X r = (rp - proc) - NR_TASKS; /* task or proc number */
X q = (r < 0 ? TASK_Q : r < LOW_USER ? SERVER_Q : USER_Q);
X
X /* See if the relevant queue is empty. */
X if (rdy_head[q] == NIL_PROC)
X rdy_head[q] = rp; /* add to empty queue */
X else
X rdy_tail[q]->p_nextready = rp; /* add to tail of nonempty queue */
X rdy_tail[q] = rp; /* new entry has no successor */
X rp->p_nextready = NIL_PROC;
X restore(); /* restore interrupts to previous state */
X}
X
X
X/*===========================================================================*
X * unready *
X *===========================================================================*/
XPUBLIC unready(rp)
Xregister struct proc *rp; /* this process is no longer runnable */
X{
X/* A process has blocked. */
X
X register struct proc *xp;
X int r, q;
X
X lock(); /* disable interrupts */
X r = rp - proc - NR_TASKS;
X q = (r < 0 ? TASK_Q : r < LOW_USER ? SERVER_Q : USER_Q);
X if ( (xp = rdy_head[q]) == NIL_PROC) return;
X if (xp == rp) {
X /* Remove head of queue */
X rdy_head[q] = xp->p_nextready;
X pick_proc();
X } else {
X /* Search body of queue. A process can be made unready even if it is
X * not running by being sent a signal that kills it.
X */
X while (xp->p_nextready != rp)
X if ( (xp = xp->p_nextready) == NIL_PROC) return;
X xp->p_nextready = xp->p_nextready->p_nextready;
X while (xp->p_nextready != NIL_PROC) xp = xp->p_nextready;
X rdy_tail[q] = xp;
X }
X restore(); /* restore interrupts to previous state */
X}
X
X
X/*===========================================================================*
X * sched *
X *===========================================================================*/
XPUBLIC sched()
X{
X/* The current process has run too long. If another low priority (user)
X * process is runnable, put the current process on the end of the user queue,
X * possibly promoting another user to head of the queue.
X */
X
X lock(); /* disable interrupts */
X if (rdy_head[USER_Q] == NIL_PROC) {
X restore(); /* restore interrupts to previous state */
X return;
X }
X
X /* One or more user processes queued. */
X rdy_tail[USER_Q]->p_nextready = rdy_head[USER_Q];
X rdy_tail[USER_Q] = rdy_head[USER_Q];
X rdy_head[USER_Q] = rdy_head[USER_Q]->p_nextready;
X rdy_tail[USER_Q]->p_nextready = NIL_PROC;
X pick_proc();
X restore(); /* restore interrupts to previous state */
X}
*-*-END-of-k_proc.c-*-*
echo x - k_tty.c
sed 's/^X//' >k_tty.c <<'*-*-END-of-k_tty.c-*-*'
X/*
X * Kernel debugging routine
X */
X
X/*===========================================================================*
X * wfc *
X *===========================================================================*/
X
Xwfc()
X{
X/* routine to wait for a character from the console. used for kernel debugging */
X
X tty_driver_buf[0] = 0;
X while(tty_driver_buf[0] == 0);
X tty_driver_buf[0] = 0;
X}
*-*-END-of-k_tty.c-*-*
echo x - k_wini.c
sed 's/^X//' >k_wini.c <<'*-*-END-of-k_wini.c-*-*'
X/* This file contains a driver for the IBM or DTC winchester controller.
X * It was written by Adri Koppes.
X *
X * The driver supports two operations: read a block and
X * write a block. It accepts two messages, one for reading and one for
X * writing, both using message format m2 and with the same parameters:
X *
X * m_type DEVICE PROC_NR COUNT POSITION ADRRESS
X * ----------------------------------------------------------------
X * | DISK_READ | device | proc nr | bytes | offset | buf ptr |
X * |------------+---------+---------+---------+---------+---------|
X * | DISK_WRITE | device | proc nr | bytes | offset | buf ptr |
X * ----------------------------------------------------------------
X *
X * The file contains one entry point:
X *
X * winchester_task: main entry when system is brought up
X *
X * TODO :
X * change struct param into struct disk
X * struct disk should contain controller address of
X * controller associated with each disk
X * rewrite init routines from scratch
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/callnr.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "const.h"
X#include "type.h"
X#include "proc.h"
X
X/* I/O Ports used by winchester disk task. */
X#define WIN_DATA 0x320 /* winchester disk controller data register */
X#define WIN_STATUS 0x321 /* winchester disk controller status register */
X#define WIN_SELECT 0x322 /* winchester disk controller select port */
X#define WIN_DMA 0x323 /* winchester disk controller dma register */
X#define DMA_ADDR 0x006 /* port for low 16 bits of DMA address */
X#define DMA_TOP 0x082 /* port for top 4 bits of 20-bit DMA addr */
X#define DMA_COUNT 0x007 /* port for DMA count (count = bytes - 1) */
X#define DMA_M2 0x00C /* DMA status port */
X#define DMA_M1 0x00B /* DMA status port */
X#define DMA_INIT 0x00A /* DMA init port */
X
X/* Winchester disk controller command bytes. */
X#define WIN_RECALIBRATE 0x01 /* command for the drive to recalibrate */
X#define WIN_SENSE 0x03 /* command for the controller to get its status */
X#define WIN_READ 0x08 /* command for the drive to read */
X#define WIN_WRITE 0x0a /* command for the drive to write */
X#define WIN_SPECIFY 0x0C /* command for the controller to accept params */
X#define WIN_ECC_READ 0x0D /* command for the controller to read ecc length */
X
X#define DMA_INT 3 /* Command with dma and interrupt */
X#define INT 2 /* Command with interrupt, no dma */
X#define NO_DMA_INT 0 /* Command without dma and interrupt */
X#define CTRL_BYTE 5 /* Control byte for controller */
X
X/* DMA channel commands. */
X#define DMA_READ 0x47 /* DMA read opcode */
X#define DMA_WRITE 0x4B /* DMA write opcode */
X
X/* Parameters for the disk drive. */
X#define SECTOR_SIZE 512 /* physical sector size in bytes */
X#define NR_SECTORS 0x11 /* number of sectors per track */
X
X/* Error codes */
X#define ERR -1 /* general error */
X
X/* Miscellaneous. */
X#define MAX_ERRORS 4 /* how often to try rd/wt before quitting */
X#define MAX_RESULTS 4 /* max number of bytes controller returns */
X#define NR_DEVICES 10 /* maximum number of drives */
X#define MAX_WIN_RETRY 10000 /* max # times to try to output to WIN */
X#define PART_TABLE 0x1C6 /* IBM partition table starts here in sect 0 */
X#define DEV_PER_DRIVE 5 /* hd0 + hd1 + hd2 + hd3 + hd4 = 5 */
X
X/* Variables. */
XPRIVATE struct wini { /* main drive struct, one entry per drive */
X int wn_opcode; /* DISK_READ or DISK_WRITE */
X int wn_procnr; /* which proc wanted this operation? */
X int wn_drive; /* drive number addressed */
X int wn_cylinder; /* cylinder number addressed */
X int wn_sector; /* sector addressed */
X int wn_head; /* head number addressed */
X int wn_heads; /* maximum number of heads */
X long wn_low; /* lowest cylinder of partition */
X long wn_size; /* size of partition in blocks */
X int wn_count; /* byte count */
X vir_bytes wn_address; /* user virtual address */
X char wn_results[MAX_RESULTS]; /* the controller can give lots of output */
X} wini[NR_DEVICES];
X
XPRIVATE int w_need_reset = FALSE; /* set to 1 when controller must be reset */
XPRIVATE int nr_drives; /* Number of drives */
X
XPRIVATE message w_mess; /* message buffer for in and out */
X
XPRIVATE int command[6]; /* Common command block */
X
XPRIVATE unsigned char buf[BLOCK_SIZE]; /* Buffer used by the startup routine */
X
XPRIVATE struct param {
X int nr_cyl; /* Number of cylinders */
X int nr_heads; /* Number of heads */
X int reduced_wr; /* First cylinder with reduced write current */
X int wr_precomp; /* First cylinder with write precompensation */
X int max_ecc; /* Maximum ECC burst length */
X} param0, param1;
X
X/*===========================================================================*
X * winchester_task *
X *===========================================================================*/
XPUBLIC winchester_task()
X{
X/* Main program of the winchester disk driver task. */
X
X int r, caller, proc_nr;
X
X /* First initialize the controller */
X init_param();
X
X /* Here is the main loop of the disk task. It waits for a message, carries
X * it out, and sends a reply.
X */
X
X while (TRUE) {
X /* First wait for a request to read or write a disk block. */
X receive(ANY, &w_mess); /* get a request to do some work */
X if (w_mess.m_source < 0) {
X printf("winchester task got message from %d ", w_mess.m_source);
X continue;
X }
X caller = w_mess.m_source;
X proc_nr = w_mess.PROC_NR;
X
X /* Now carry out the work. */
X switch(w_mess.m_type) {
X case DISK_READ:
X case DISK_WRITE: r = w_do_rdwt(&w_mess); break;
X default: r = EINVAL; break;
X }
X
X /* Finally, prepare and send the reply message. */
X w_mess.m_type = TASK_REPLY;
X w_mess.REP_PROC_NR = proc_nr;
X
X w_mess.REP_STATUS = r; /* # of bytes transferred or error code */
X send(caller, &w_mess); /* send reply to caller */
X }
X}
X
X
X/*===========================================================================*
X * w_do_rdwt *
X *===========================================================================*/
XPRIVATE int w_do_rdwt(m_ptr)
Xmessage *m_ptr; /* pointer to read or write w_message */
X{
X/* Carry out a read or write request from the disk. */
X register struct wini *wn;
X int r, device, errors = 0;
X long sector;
X
X /* Decode the w_message parameters. */
X device = m_ptr->DEVICE;
X if (device < 0 || device >= NR_DEVICES)
X return(EIO);
X if (m_ptr->COUNT != BLOCK_SIZE)
X return(EINVAL);
X wn = &wini[device]; /* 'wn' points to entry for this drive */
X wn->wn_drive = device/DEV_PER_DRIVE; /* save drive number */
X if (wn->wn_drive >= nr_drives)
X return(EIO);
X wn->wn_opcode = m_ptr->m_type; /* DISK_READ or DISK_WRITE */
X if (m_ptr->POSITION % BLOCK_SIZE != 0)
X return(EINVAL);
X sector = m_ptr->POSITION/SECTOR_SIZE;
X if ((sector+BLOCK_SIZE/SECTOR_SIZE) > wn->wn_size)
X return(EOF);
X sector += wn->wn_low;
X wn->wn_cylinder = sector / (wn->wn_heads * NR_SECTORS);
X wn->wn_sector = (sector % NR_SECTORS);
X wn->wn_head = (sector % (wn->wn_heads * NR_SECTORS) )/NR_SECTORS;
X wn->wn_count = m_ptr->COUNT;
X wn->wn_address = (vir_bytes) m_ptr->ADDRESS;
X wn->wn_procnr = m_ptr->PROC_NR;
X
X /* This loop allows a failed operation to be repeated. */
X while (errors <= MAX_ERRORS) {
X errors++; /* increment count once per loop cycle */
X if (errors >= MAX_ERRORS)
X return(EIO);
X
X /* First check to see if a reset is needed. */
X if (w_need_reset) w_reset();
X
X /* Now set up the DMA chip. */
X w_dma_setup(wn);
X
X /* Perform the transfer. */
X r = w_transfer(wn);
X if (r == OK) break; /* if successful, exit loop */
X
X }
X
X return(r == OK ? BLOCK_SIZE : EIO);
X}
X
X
X/*===========================================================================*
X * w_dma_setup *
X *===========================================================================*/
XPRIVATE w_dma_setup(wn)
Xstruct wini *wn; /* pointer to the drive struct */
X{
X/* The IBM PC can perform DMA operations by using the DMA chip. To use it,
X * the DMA (Direct Memory Access) chip is loaded with the 20-bit memory address
X * to by read from or written to, the byte count minus 1, and a read or write
X * opcode. This routine sets up the DMA chip. Note that the chip is not
X * capable of doing a DMA across a 64K boundary (e.g., you can't read a
X * 512-byte block starting at physical address 65520).
X */
X
X int mode, low_addr, high_addr, top_addr, low_ct, high_ct, top_end;
X vir_bytes vir, ct;
X phys_bytes user_phys;
X extern phys_bytes umap();
X
X mode = (wn->wn_opcode == DISK_READ ? DMA_READ : DMA_WRITE);
X vir = (vir_bytes) wn->wn_address;
X ct = (vir_bytes) wn->wn_count;
X user_phys = umap(proc_addr(wn->wn_procnr), D, vir, ct);
X low_addr = (int) user_phys & BYTE;
X high_addr = (int) (user_phys >> 8) & BYTE;
X top_addr = (int) (user_phys >> 16) & BYTE;
X low_ct = (int) (ct - 1) & BYTE;
X high_ct = (int) ( (ct - 1) >> 8) & BYTE;
X
X /* Check to see if the transfer will require the DMA address counter to
X * go from one 64K segment to another. If so, do not even start it, since
X * the hardware does not carry from bit 15 to bit 16 of the DMA address.
X * Also check for bad buffer address. These errors mean FS contains a bug.
X */
X if (user_phys == 0) panic("FS gave winchester disk driver bad addr", (int) vir);
X top_end = (int) (((user_phys + ct - 1) >> 16) & BYTE);
X if (top_end != top_addr) panic("Trying to DMA across 64K boundary", top_addr);
X
X /* Now set up the DMA registers. */
X lock();
X port_out(DMA_M2, mode); /* set the DMA mode */
X port_out(DMA_M1, mode); /* set it again */
X port_out(DMA_ADDR, low_addr); /* output low-order 8 bits */
X port_out(DMA_ADDR, high_addr);/* output next 8 bits */
X port_out(DMA_TOP, top_addr); /* output highest 4 bits */
X port_out(DMA_COUNT, low_ct); /* output low 8 bits of count - 1 */
X port_out(DMA_COUNT, high_ct); /* output high 8 bits of count - 1 */
X unlock();
X}
X
X/*===========================================================================*
X * w_transfer *
X *===========================================================================*/
XPRIVATE int w_transfer(wn)
Xregister struct wini *wn; /* pointer to the drive struct */
X{
X/* The drive is now on the proper cylinder. Read or write 1 block. */
X
X /* The command is issued by outputing 6 bytes to the controller chip. */
X command[0] = (wn->wn_opcode == DISK_READ ? WIN_READ : WIN_WRITE);
X command[1] = (wn->wn_head | (wn->wn_drive << 5));
X command[2] = (((wn->wn_cylinder & 0x0300) >> 2) | wn->wn_sector);
X command[3] = (wn->wn_cylinder & 0xFF);
X command[4] = BLOCK_SIZE/SECTOR_SIZE;
X command[5] = CTRL_BYTE;
X if (com_out(DMA_INT) != OK)
X return(ERR);
X
X port_out(DMA_INIT, 3); /* initialize DMA */
X /* Block, waiting for disk interrupt. */
X receive(HARDWARE, &w_mess);
X
X /* Get controller status and check for errors. */
X if (win_results(wn) == OK)
X return(OK);
X if ((wn->wn_results[0] & 63) == 24)
X read_ecc();
X else
X w_need_reset = TRUE;
X return(ERR);
X}
X
X
X/*===========================================================================*
X * win_results *
X *===========================================================================*/
XPRIVATE int win_results(wn)
Xregister struct wini *wn; /* pointer to the drive struct */
X{
X/* Extract results from the controller after an operation. */
X
X register int i;
X int status;
X
X port_in(WIN_DATA, &status);
X port_out(WIN_DMA, 0);
X if (!(status & 2))
X return(OK);
X command[0] = WIN_SENSE;
X command[1] = (wn->wn_drive << 5);
X if (com_out(NO_DMA_INT) != OK)
X return(ERR);
X
X /* Loop, extracting bytes from WIN */
X for (i = 0; i < MAX_RESULTS; i++) {
X if (hd_wait(1) != OK)
X return(ERR);
X port_in(WIN_DATA, &status);
X wn->wn_results[i] = status & BYTE;
X }
X if (wn->wn_results[0] & 63)
X return(ERR);
X else
X return(OK);
X}
X
X
X/*===========================================================================*
X * win_out *
X *===========================================================================*/
XPRIVATE win_out(val)
Xint val; /* write this byte to winchester disk controller */
X{
X/* Output a byte to the controller. This is not entirely trivial, since you
X * can only write to it when it is listening, and it decides when to listen.
X * If the controller refuses to listen, the WIN chip is given a hard reset.
X */
X
X if (w_need_reset) return; /* if controller is not listening, return */
X if (hd_wait(1) == OK)
X port_out(WIN_DATA, val);
X}
X
X/*===========================================================================*
X * w_reset *
X *===========================================================================*/
XPRIVATE w_reset()
X{
X/* Issue a reset to the controller. This is done after any catastrophe,
X * like the controller refusing to respond.
X */
X
X int r = 1, i;
X
X /* Strobe reset bit low. */
X port_out(WIN_STATUS, r);
X for (i = 0; i < 10000; i++) {
X port_in(WIN_STATUS, &r);
X if ( (r&01) == 0)break;
X }
X if (r & 2) {
X printf("Hard disk won't reset\n");
X return(ERR);
X }
X
X /* Reset succeeded. Tell WIN drive parameters. */
X w_need_reset = FALSE;
X
X return(win_init());
X}
X
X/*===========================================================================*
X * win_init *
X *===========================================================================*/
XPRIVATE win_init()
X{
X/* Routine to initialize the drive parameters after boot or reset */
X
X register int i;
X
X command[0] = WIN_SPECIFY; /* Specify some parameters */
X command[1] = 0; /* Drive 0 */
X if (com_out(NO_DMA_INT) != OK) /* Output command block */
X return(ERR);
X
X lock();
X
X /* No. of cylinders (high byte) */
X win_out(param0.nr_cyl >> 8);
X
X /* No. of cylinders (low byte) */
X win_out(param0.nr_cyl & 0xFF);
X
X /* No. of heads */
X win_out(param0.nr_heads);
X
X /* Start reduced write (high byte) */
X win_out(param0.reduced_wr >> 8);
X
X /* Start reduced write (low byte) */
X win_out(param0.reduced_wr & 0xFF);
X
X /* Start write precompensation (high byte) */
X win_out(param0.wr_precomp >> 8);
X
X /* Start write precompensation (low byte) */
X win_out(param0.wr_precomp & 0xFF);
X
X /* Ecc burst length */
X win_out(param0.max_ecc);
X unlock();
X
X if (check_init() != OK) { /* See if controller accepted parameters */
X w_need_reset = TRUE;
X return(ERR);
X }
X
X if (nr_drives > 1) {
X command[1] = (1 << 5); /* Drive 1 */
X if (com_out(NO_DMA_INT) != OK) /* Output command block */
X return(ERR);
X lock();
X
X /* No. of cylinders (high byte) */
X win_out(param1.nr_cyl >> 8);
X
X /* No. of cylinders (low byte) */
X win_out(param1.nr_cyl & 0xFF);
X
X /* No. of heads */
X win_out(param1.nr_heads);
X
X /* Start reduced write (high byte) */
X win_out(param1.reduced_wr >> 8);
X
X /* Start reduced write (low byte) */
X win_out(param1.reduced_wr & 0xFF);
X
X /* Start write precompensation (high byte) */
X win_out(param1.wr_precomp >> 8);
X
X /* Start write precompensation (low byte) */
X win_out(param1.wr_precomp & 0xFF);
X
X /* Ecc burst length */
X win_out(param1.max_ecc);
X unlock();
X if (check_init() != OK) { /* See if controller accepted parameters */
X w_need_reset = TRUE;
X return(ERR);
X }
X }
X for (i=0; i<nr_drives; i++) {
X command[0] = WIN_RECALIBRATE;
X command[1] = i << 5;
X command[5] = CTRL_BYTE;
X if (com_out(INT) != OK)
X return(ERR);
X receive(HARDWARE, &w_mess);
X if (win_results() != OK) {
X w_need_reset = TRUE;
X return(ERR);
X }
X }
X return(OK);
X}
X
X/*============================================================================*
X * check_init *
X *============================================================================*/
XPRIVATE check_init()
X{
X/* Routine to check if controller accepted the parameters */
X int r;
X
X if (hd_wait(2) == OK) {
X port_in(WIN_DATA, &r);
X if (r & 2)
X return(ERR);
X else
X return(OK);
X }
X}
X
X/*============================================================================*
X * read_ecc *
X *============================================================================*/
XPRIVATE read_ecc()
X{
X/* Read the ecc burst-length and let the controller correct the data */
X
X int r;
X
X command[0] = WIN_ECC_READ;
X if (com_out(NO_DMA_INT) == OK && hd_wait(1) == OK) {
X port_in(WIN_DATA, &r);
X if (hd_wait(1) == OK) {
X port_in(WIN_DATA, &r);
X if (r & 1)
X w_need_reset = TRUE;
X }
X }
X return(ERR);
X}
X
X/*============================================================================*
X * hd_wait *
X *============================================================================*/
XPRIVATE hd_wait(bit)
Xregister int bit;
X{
X/* Wait until the controller is ready to receive a command or send status */
X
X register int i = 0;
X int r;
X
X do {
X port_in(WIN_STATUS, &r);
X r &= bit;
X } while ((i++ < MAX_WIN_RETRY) && !r);
X
X if (i >= MAX_WIN_RETRY) {
X w_need_reset = TRUE;
X return(ERR);
X } else
X return(OK);
X}
X
X/*============================================================================*
X * com_out *
X *============================================================================*/
XPRIVATE com_out(mode)
Xint mode;
X{
X/* Output the command block to the winchester controller and return status */
X
X register int i = 0;
X int r;
X
X port_out(WIN_SELECT, mode);
X port_out(WIN_DMA, mode);
X for (i=0; i<MAX_WIN_RETRY; i++) {
X port_in(WIN_STATUS, &r);
X if ((r & 0x0F) == 0x0D)
X break;
X }
X if (i == MAX_WIN_RETRY) {
X w_need_reset = TRUE;
X return(ERR);
X }
X lock();
X for (i=0; i<6; i++) {
X port_out(WIN_DATA, command[i]);
X r = hd_wait(1);
X if (r != OK) break;
X port_in(WIN_STATUS,&r);
X if ( (r&7) != 5) break;
X }
X unlock();
X return(OK);
X}
X
X/*============================================================================*
X * init_params *
X *============================================================================*/
XPRIVATE init_params()
X{
X/* This routine is called at startup to initialize the partition table,
X * the number of drives and the controller
X*/
X unsigned int i, segment, offset;
X int type_0, type_1;
X phys_bytes address;
X extern phys_bytes umap();
X extern int vec_table[];
X
X /* Read the switches from the controller */
X port_in(WIN_SELECT, &i);
X
X /* Calculate the drive types */
X type_0 = ((i >> 2) & 3) + ((i>>4) & 0xc);
X type_1 = (i & 3) + ((i>>2) & 0xc);
X
X /* Copy the parameter vector from the saved vector table */
X offset = vec_table[2 * 0x41];
X segment = vec_table[2 * 0x41 + 1];
X
X /* Calculate the address off the parameters and copy them to buf */
X address = ((long)segment << 4) + offset;
X phys_copy(address, umap(proc_addr(WINCHESTER), D, buf, 64), 64L);
X
X /* Copy the parameters to the structures */
X copy_param((&buf[type_0 * 16]), ¶m0);
X copy_param((&buf[type_1 * 16]), ¶m1);
X
X /* Get the nummer of drives from the bios */
X phys_copy(0x475L, umap(proc_addr(WINCHESTER), D, buf, 1), 1L);
X nr_drives = (int) *buf;
X
X /* Set the parameters in the drive structure */
X for (i=0; i<5; i++)
X wini[i].wn_heads = param0.nr_heads;
X wini[0].wn_low = wini[5].wn_low = 0L;
X wini[0].wn_size = (long)((long)param0.nr_cyl * (long)param0.nr_heads * (long)NR_SECTORS);
X for (i=5; i<10; i++)
X wini[i].wn_heads = param1.nr_heads;
X wini[5].wn_size = (long)((long)param1.nr_cyl * (long)param1.nr_heads * (long)NR_SECTORS);
X
X
X /* Initialize the controller */
X if ((nr_drives > 0) && (win_init() != OK))
X nr_drives = 0;
X
Xif (nr_drives == 0) {
X printf("No winchester drive ?????\n");
X wfc();
X}
X
X /* Read the partition table for each drive and save them */
X for (i = 0; i < nr_drives; i++) {
X w_mess.DEVICE = i * 5;
X w_mess.POSITION = 0L;
X w_mess.COUNT = BLOCK_SIZE;
X w_mess.ADDRESS = (char *) buf;
X w_mess.PROC_NR = WINCHESTER;
X w_mess.m_type = DISK_READ;
X if (w_do_rdwt(&w_mess) != BLOCK_SIZE)
X panic("Can't read partition table of winchester ", i);
X copy_prt(i * 5);
X }
X}
X
X/*============================================================================*
X * copy_params *
X *============================================================================*/
XPRIVATE copy_params(src, dest)
Xregister unsigned char *src;
Xregister struct param *dest;
X{
X/* This routine copies the parameters from src to dest
X * and sets the parameters for partition 0 and 5
X*/
X
X dest->nr_cyl = *(int *)src;
X dest->nr_heads = (int)src[2];
X dest->reduced_wr = *(int *)&src[3];
X dest->wr_precomp = *(int *)&src[5];
X dest->max_ecc = (int)src[7];
X}
X
X/*============================================================================*
X * copy_prt *
X *============================================================================*/
XPRIVATE copy_prt(drive)
Xint drive;
X{
X/* This routine copies the partition table for the selected drive to
X * the variables wn_low and wn_size
X */
X
X register int i, offset;
X struct wini *wn;
X long adjust;
X
X for (i=0; i<4; i++) {
X adjust = 0;
X wn = &wini[i + drive + 1];
X offset = PART_TABLE + i * 0x10;
X wn->wn_low = *(long *)&buf[offset];
X if ((wn->wn_low % (BLOCK_SIZE/SECTOR_SIZE)) != 0) {
X adjust = wn->wn_low;
X wn->wn_low = (wn->wn_low/(BLOCK_SIZE/SECTOR_SIZE)+1)*(BLOCK_SIZE/SECTOR_SIZE);
X adjust = wn->wn_low - adjust;
X }
X wn->wn_size = *(long *)&buf[offset + sizeof(long)] - adjust;
X }
X sort(&wini[drive + 1]);
X}
X
Xsort(wn)
Xregister struct wini *wn;
X{
X register int i,j;
X
X for (i=0; i<4; i++)
X for (j=0; j<3; j++)
X if ((wn[j].wn_low == 0) && (wn[j+1].wn_low != 0))
X swap(&wn[j], &wn[j+1]);
X else if (wn[j].wn_low > wn[j+1].wn_low && wn[j+1].wn_low != 0)
X swap(&wn[j], &wn[j+1]);
X}
X
Xswap(first, second)
Xregister struct wini *first, *second;
X{
X register struct wini tmp;
X
X tmp = *first;
X *first = *second;
X *second = tmp;
X}
*-*-END-of-k_wini.c-*-*
echo x - m_make.
sed 's/^X//' >m_make. <<'*-*-END-of-m_make.-*-*'
XCFLAGS = -Di8088 -w -F -T.
Xh=../h
Xl=/usr/lib
X
Xobj = main.s forkexit.s break.s exec.s signal.s getset.s \
X alloc.s utility.s table.s putc.s
X
Xmm: makefile $l/head.s $(obj) $l/libc.a $l/end.s
X# @echo "Start linking MM. /lib/cem will be removed to make space on RAM disk"
X# @rm -f /lib/cem /tmp/*
X# @asld -o mm $l/head.s $(obj) $l/libc.a $l/end.s
X# @echo "MM done. Please restore /lib/cem manually"
X @echo "Start linking MM.
X @asld -o mm -T. $l/head.s $(obj) $l/libc.a $l/end.s
X @echo "MM done.
X
X
Xalloc.s: const.h $h/const.h $h/type.h
X
Xbreak.s: const.h $h/const.h $h/type.h
Xbreak.s: $h/error.h
Xbreak.s: $h/signal.h
Xbreak.s: glo.h
Xbreak.s: mproc.h
Xbreak.s: param.h
X
Xexec.s: const.h $h/const.h $h/type.h
Xexec.s: $h/callnr.h
Xexec.s: $h/error.h
Xexec.s: $h/stat.h
Xexec.s: glo.h
Xexec.s: mproc.h
Xexec.s: param.h
X
Xforkexit.s: const.h $h/const.h $h/type.h
Xforkexit.s: $h/callnr.h
Xforkexit.s: $h/error.h
Xforkexit.s: glo.h
Xforkexit.s: mproc.h
Xforkexit.s: param.h
X
Xgetset.s: const.h $h/const.h $h/type.h
Xgetset.s: $h/callnr.h
Xgetset.s: $h/error.h
Xgetset.s: glo.h
Xgetset.s: mproc.h
Xgetset.s: param.h
X
Xmain.s: const.h $h/const.h $h/type.h
Xmain.s: $h/callnr.h
Xmain.s: $h/com.h
Xmain.s: $h/error.h
Xmain.s: glo.h
Xmain.s: mproc.h
Xmain.s: param.h
X
Xputc.s: $h/const.h $h/type.h
Xputc.s: $h/com.h
X
Xsignal.s: const.h $h/const.h $h/type.h
Xsignal.s: $h/callnr.h
Xsignal.s: $h/com.h
Xsignal.s: $h/error.h
Xsignal.s: $h/signal.h
Xsignal.s: $h/stat.h
Xsignal.s: glo.h
Xsignal.s: mproc.h
Xsignal.s: param.h
X
Xtable.s: const.h $h/const.h $h/type.h
Xtable.s: $h/callnr.h
Xtable.s: glo.h
Xtable.s: mproc.h
Xtable.s: param.h
X
Xutility.s: const.h $h/const.h $h/type.h
Xutility.s: $h/callnr.h
Xutility.s: $h/com.h
Xutility.s: $h/error.h
Xutility.s: $h/stat.h
Xutility.s: glo.h
Xutility.s: mproc.h
*-*-END-of-m_make.-*-*
echo x - readme.txt
sed 's/^X//' >readme.txt <<'*-*-END-of-readme.txt-*-*'
X
XThis directorry should contain the following files :
X
X file to be placed in decription
X ---- --------------- ----------
X
Xk_floppy.c kernel/floppy.c changed startup time for M24
X added timeout
X changes startup time if M24
X
Xk_wini.c kernel/wini.c changed com_out for M24
X
Xdiskpart.c tools/diskpart.c utility to partition harddisk
X
Xh_const.h h/const.h BOOT_DEV set to /dev/hd2
X
Xk_const.h kernel/const.h added hardware types
X
Xk_glo.h kernel/glo.h changed pc_at into hw_id
X
Xk_main.c kernel/main.c added m24 detection
X
Xk_proc.c kernel/proc.c changed test on pc_at
X
Xk_tty.c kernel/tty.c added wfc()
X
*-*-END-of-readme.txt-*-*
echo x - t_diskp.c
sed 's/^X//' >t_diskp.c <<'*-*-END-of-t_diskp.c-*-*'
X/*
X * Diskpart. Display and modify partition table
X * Written by Jakob Schripsema
X *
X * First run the DOS utilities FDISK and FORMAT. FDISK
X * puts the boot code in sector 0.
X * Then run diskpart
X *
X * diskpart /dev/hdx (MINIX)
X * diskpart x: (DOS)
X *
X * Compiling
X *
X * cc -o diskpart -DUNIX diskpart.c (MINIX)
X * cl -DDOS diskpart.c (DOS with MS C compiler)
X */
X
X#include <stdio.h>
X
X#ifdef DOS
X#include <dos.h>
X#endif
X
X/*
X * Constants
X */
X
X#define NHEAD 4 /* # heads */
X#define NSEC 17 /* sectors / track */
X#define SECSIZE 512 /* sector size */
X#define OK 0
X#define ERR 1
X#define TABLEOFFSET 0x1be /* offset in boot sector*/
X/*
X * Description of entry in partition table
X */
X
Xstruct part_entry {
X char bootind; /* boot indicator 0/0x80 */
X char start_head; /* head value for first sector */
X char start_sec; /* sector value for first sector*/
X char start_cyl; /* track value for first sector */
X char sysind; /* system indicator 00=?? 01=DOS*/
X char last_head; /* head value for last sector */
X char last_sec; /* sector value for last sector */
X char last_cyl; /* track value for last sector */
X long lowsec; /* logical first sector */
X long size; /* size of partion in sectors */
X};
X
X/*
X * Globals
X */
X
Xchar secbuf[SECSIZE];
Xchar *devname;
Xchar *dosstr = " DOS ";
Xchar *ndosstr = "Non-DOS";
X
X#ifdef DOS
Xunion REGS regs;
Xstruct SREGS sregs;
Xint drivenum;
X#endif
X
X#ifdef UNIX
Xint devfd;
X#endif
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X char ch;
X
X /* init */
X
X if (argc != 2) {
X printf("Usage: diskpart drive\n");
X exit(1);
X }
X
X devname = argv[1];
X getboot(secbuf); /* get boot sector */
X
X do {
X dpl_partitions();
X printf("\nchange write hexdump quit (c/w/x/q) ? ");
X ch = get_a_char();
X putchar('\n');
X switch (ch) {
X case 'c' :
X change_table();
X break;
X case 'w' :
X if (chk_table() == OK) {
X putboot(secbuf);
X exit(0);
X }
X break;
X case 'x' :
X dump_table();
X break;
X case 'q' :
X exit(0);
X default :
X printf(" %c ????\n",ch);
X }
X }
X while (1);
X}
X
X/*
X * Read boot sector
X */
X
X#ifdef DOS
X
Xgetboot(buffer)
Xchar *buffer;
X{
X segread(&sregs); /* get ds */
X
X if (devname[1] != ':') {
X printf("Invalid drive %s\n",devname);
X exit(1);
X }
X
X if (*devname >= 'a')
X *devname += 'A' - 'a';
X drivenum = (*devname - 'C') & 0xff;
X if (drivenum < 0 || drivenum > 7) {
X printf("Funny drive number %d\n",drivenum);
X exit(1);
X }
Xprintf("Drive number %d\n",drivenum);
X regs.x.ax = 0x201; /* read 1 sectors */
X regs.h.ch = 0; /* track */
X regs.h.cl = 1; /* first sector = 1 */
X regs.h.dh = 0; /* head = 0 */
X regs.h.dl = 0x80+drivenum;/* drive = 0 */
X sregs.es = sregs.ds; /* buffer address */
X regs.x.bx = (int)secbuf;
X
X int86x(0x13,®s,®s,&sregs);
X if (regs.x.cflag)
X {
X printf("Cannot read boot sector\n");
X exit(1);
X }
X}
X#endif
X
X#ifdef UNIX
X
Xgetboot(buffer)
Xchar *buffer;
X{
X devfd = open(devname,2);
X if (devfd < 0) {
X printf("Cannot open device %s\n",devname);
X exit(1);
X }
X if (read(devfd,buffer,SECSIZE) != SECSIZE) {
X printf("Cannot read boot sector\n");
X exit(2);
X }
X}
X#endif
X
X/*
X * Write boot sector
X */
X
X#ifdef DOS
X
Xputboot(buffer)
Xchar *buffer;
X{
X regs.x.ax = 0x301; /* read 1 sectors */
X regs.h.ch = 0; /* track */
X regs.h.cl = 1; /* first sector = 1 */
X regs.h.dh = 0; /* head = 0 */
X regs.h.dl = 0x80+drivenum;/* drive = 0 */
X sregs.es = sregs.ds; /* buffer address */
X regs.x.bx = (int)secbuf;
X
X int86x(0x13,®s,®s,&sregs);
X if (regs.x.cflag)
X {
X printf("Cannot write boot sector\n");
X exit(1);
X }
X}
X#endif
X
X#ifdef UNIX
X
Xputboot(buffer)
Xchar *buffer;
X{
X int r;
X
X if (lseek(devfd,0L,0) < 0) {
X printf("Seek error during write\n");
X exit(1);
X }
X if (write(devfd,buffer,SECSIZE) != SECSIZE) {
X printf("Write error\n");
X exit(1);
X }
X sync();
X}
X#endif
X
X/*
X * Dump partition table
X */
X
Xdump_table()
X{
X struct part_entry *pe;
X int i;
X
X pe = (struct part_entry *)&secbuf[TABLEOFFSET];
X printf("\n --first--- ---last---\n");
X printf("Prt ac hd sec cyl sys hd sec cyl low size\n");
X for (i = 1 ; i < 5 ; i++) {
X printf(" %x %2x %x %2x %2x %2x %x %2x %2x %6X%9X\n",
X i,
X pe->bootind & 0xff,
X pe->start_head & 0xff,
X pe->start_sec & 0xff,
X pe->start_cyl & 0xff,
X pe->sysind & 0xff,
X pe->last_head & 0xff,
X pe->last_sec & 0xff,
X pe->last_cyl & 0xff,
X pe->lowsec,
X pe->size);
X pe++;
X }
X}
X/*
X * Display partition table
X */
X
Xdpl_partitions()
X{
X struct part_entry *pe;
X int i;
X
X printf("\nPartition Type Begin End Active\n");
X pe = (struct part_entry *)&secbuf[TABLEOFFSET];
X for (i = 1 ; i <= 4 ; i++) {
X dpl_entry(i,pe);
X pe++;
X }
X}
X
X/*
X * Display an entry
X */
X
Xdpl_entry(number,entry)
Xint number;
Xstruct part_entry *entry;
X{
X int low_cyl,high_cyl,temp;
X char *typestring;
X char active;
X
X if (entry->sysind == 0x01)
X typestring = dosstr;
X else
X typestring = ndosstr;
X printf("%5d %s ",number,typestring);
X temp = entry->start_sec & 0xc0;
X low_cyl = (entry->start_cyl & 0xff) + (temp << 2);
X temp = entry->last_sec & 0xc0;
X high_cyl = (entry->last_cyl & 0xff) + (temp << 2);
X printf("%4d %4d",low_cyl,high_cyl);
X if ((entry->bootind & 0xff) == 0x80)
X active = 'A';
X else
X active = 'N';
X printf(" %c\n",active);
X}
X
X/*
X * Check partition table
X */
X
Xchk_table()
X{
X struct part_entry *pe;
X int i;
X int active;
X long limit;
X
X pe = (struct part_entry *)&secbuf[TABLEOFFSET];
X limit = 0L;
X active = 0;
X for (i = 1 ; i < 5 ; i++) {
X if (pe->size == 0L)
X return(OK);
X if (pe->lowsec <= limit) {
X printf("Overlap between part. %d and %d\n",i,i-1);
X return(ERR);
X }
X limit = pe->lowsec + pe->size - 1L;
X if (pe->bootind == 0x80)
X active++;
X pe++;
X }
X if (active > 1) {
X printf("%d active partitions\n",active);
X return(ERR);
X }
X return(OK);
X}
X/*
X * Check entry
X * head/sector/track info must match logical sector number
X * Used to check 'foreign' partition table during debugging
X */
X
Xchk_entry(entry)
Xstruct part_entry *entry;
X{
X char head;
X char sector;
X char track;
X
X sec_to_hst(entry->lowsec,&head,§or,&track);
X if ( (head != entry->start_head) ||
X (sector != entry->start_sec) ||
X (track != entry->start_cyl))
X return(ERR);
X sec_to_hst(entry->lowsec + entry->size - 1L,&head,§or,&track);
X if ( (head != entry->last_head) ||
X (sector != entry->last_sec) ||
X (track != entry->last_cyl))
X return(ERR);
X return(OK);
X}
X
X/*
X * Convert a logical sector number to
X * head / sector / track
X */
X
Xsec_to_hst(logsec,hd,sec,cyl)
Xlong logsec;
Xchar *hd,*sec,*cyl;
X{
X int bigcyl;
X
X bigcyl = logsec / (NHEAD * NSEC);
X *sec = (logsec % NSEC) + 1 + ((bigcyl >> 2) & 0xc0);
X *cyl = bigcyl & 0xff;
X *hd = (logsec % (NHEAD * NSEC)) / NSEC;
X}
X
X/*
X * change partition table
X */
X
Xchange_table()
X{
X struct part_entry *pe;
X int i,temp,low_cyl,high_cyl;
X char ch;
X
X pe = (struct part_entry *)&secbuf[TABLEOFFSET];
X for (i = 1 ; i <= 4 ; i++) {
X temp = pe->start_sec & 0xc0;
X low_cyl = (pe->start_cyl & 0xff) + (temp << 2);
X temp = pe->last_sec & 0xc0;
X high_cyl = (pe->last_cyl & 0xff) + (temp << 2);
X printf("Partition %d from %d to %d. Change ? ",
X i,low_cyl,high_cyl);
X ch = get_a_char();
X if (ch == 'y' || ch == 'Y')
X get_partition(pe);
X pe++;
X }
X putchar('\n');
X}
X
X/*
X * Get partition info : first & last cylinder
X */
X
Xget_partition(entry)
Xstruct part_entry *entry;
X{
X char buf[80];
X int first,last;
X long low,high;
X char ch;
X
X printf(" First cylinder ? ");
X gets(buf);
X sscanf(buf,"%d",&first);
X printf(" Last cylinder ? ");
X gets(buf);
X sscanf(buf,"%d",&last);;
X if (first == 0 && last == 0) {
X entry->bootind = 0;
X entry->start_head = 0;
X entry->start_sec = 0;
X entry->start_cyl = 0;
X entry->sysind = 0;
X entry->last_head = 0;
X entry->last_sec = 0;
X entry->last_cyl = 0;
X entry->lowsec = 0L;
X entry->size = 0L ;
X return;
X }
X low = first & 0xffff;
X low = low * NSEC * NHEAD;
X if (low == 0)
X low = 1; /* sec0 is master boot record */
X high = last & 0xffff;
X high = (high + 1)*NSEC*NHEAD - 1;
X entry->lowsec = low;
X entry->size = high - low + 1;
X sec_to_hst(low,
X &entry->start_head,
X &entry->start_sec,
X &entry->start_cyl);
X sec_to_hst(high,
X &entry->last_head,
X &entry->last_sec,
X &entry->last_cyl);
X printf(" DOS partition ? ");
X ch = get_a_char();
X if (ch == 'y' || ch == 'Y')
X entry->sysind = 1;
X else
X entry->sysind = 0;
X printf(" Active partition ? ");
X ch = get_a_char();
X if (ch == 'y' || ch == 'Y')
X entry->bootind = 0x80;
X else
X entry->bootind = 0;
X}
X
X/*
X * Read 1 character and discard rest of line
X */
X
Xget_a_char()
X{
X char ch;
X
X ch = getchar();
X if (ch != '\n')
X while (getchar() != '\n');
X return(ch);
X}
X
*-*-END-of-t_diskp.c-*-*
echo x - t_mkboot.
sed 's/^X//' >t_mkboot. <<'*-*-END-of-t_mkboot.-*-*'
Xbuild bootblok ../kernel/kernel ../mm/mm ../fs/fs init fsck /dev/fd0
*-*-END-of-t_mkboot.-*-*
exit