Path: utzoo!utgpu!jarvis.csri.toronto.edu!clyde.concordia.ca!uunet!tut.cis.ohio-state.edu!ucsd!helios.ee.lbl.gov!nosc!cod!hall From: hall@cod.NOSC.MIL (Robert R. Hall) Newsgroups: comp.os.minix Subject: Re: Suggestion for PC wini te Summary: DOS testing of wini.c Message-ID: <1738@cod.NOSC.MIL> Date: 2 Jan 90 22:48:41 GMT References: <89122504055886@masnet.uucp> Organization: Naval Ocean Systems Center, San Diego Lines: 339 In article <89122504055886@masnet.uucp>, peter_van_epp@cc.sfu.ca@canremote.uucp (Peter_Van_Epp@cc.sfu.ca) writes: > Subj: Suggestion for PC wini test program under DOS (long) > > Given the amount of troubles I and other people are having with > xt_/at_wini.c it seems to me that we should write a test program that > runs under DOS (sorry Andy!) that does the following: > Asks DOS what the drive under consideration looks like (int 13) by > reading the controller bios rom. Now the wini.c code would be . . . > project on the end of my (long!) list of things to do, unless someone > else is interested in making one (hint! hint!). > Peter_Van_Epp@cc.sfu.ca Here is a couple of MS-DOS programs I used to get Minix working with my hard drive. It doesn't have most of the feature Peter_Van_Epp suggested but is may be a starting place for someone. Robert R. Hall hall@nosc.mil echo x - rd_parms.c sed '/^X/s///' > rd_parms.c << '/' X/* rd_params.c X read hard dirve parameters */ X Xstruct param { X int nr_cyl; /* Number of cylinders */ X int nr_heads; /* Number of heads */ X int nr_sectors; /* Number of sectors per track */ X int nr_drives; /* Number of drives */ X int dr_type; /* drive type */ X} param0, param1; X Xint Ax, Bx, Cx, Dx; X X#include X#define BIOS_ASK 0x08 X#define DRIVE 0x80 X Xbios13() X{ X union REGS in_regs, out_regs; X X in_regs.x.ax = Ax; X in_regs.x.bx = Bx; X in_regs.x.cx = Cx; X in_regs.x.dx = Dx; X int86(0x13, &in_regs, &out_regs); X Ax = out_regs.x.ax; X Bx = out_regs.x.bx; X Cx = out_regs.x.cx; X Dx = out_regs.x.dx; X return; X} X Xget_params(dr, params) Xint dr; Xstruct param *params; X{ X Dx = dr + DRIVE; X Ax = (BIOS_ASK << 8); X bios13(); X params->nr_heads = ((Dx >> 8) & 0xff) + 1; X params->nr_sectors = (Cx & 0x3F); X params->nr_cyl = ((Cx & 0xC0) << 2) + ((Cx >> 8) & 0xFF); X params->nr_drives = (Dx & 0xFF); X params->dr_type = (Bx & 0x07); X} X Xmain() X{ X get_params(1, ¶m0); X printf("nr_heads is: %d\n", param0.nr_heads); X printf("nr_sectors is: %d\n", param0.nr_sectors); X printf("nr_cyl is: %d\n", param0.nr_cyl); X printf("nr_drives is: %d\n", param0.nr_drives); X printf("dr_type is: %d\n", param0.dr_type); X X printf("Ax is: %.4x Bx is: %.4x Cx is: %.4x Dx is: %.4x\n", X Ax, Bx, Cx, Dx); X} / echo x - rd_part.c sed '/^X/s///' > rd_part.c << '/' X/* This file contains a hard disk driver that uses the ROM BIOS. It makes X * a call and just waits for the transfer to happen. It is not interrupt X * driven and thus will have poor performance. The advantage is that it should X * work on virtually any PC, XT, 386, PS/2 or clone. The generic boot X * diskette uses this driver. It is suggested that all MINIX users try the X * other drivers, and use this one only as a last resort, if all else fails. 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 */ X X#include X X#include "minix/const.h" X#include "minix/type.h" X#include "minix/callnr.h" X#include "minix/com.h" X#include "minix/error.h" X#include "const.h" X#include "type.h" X#include "glo.h" X#include "proc.h" X X/* Error codes */ X#define ERR -1 /* general error */ X X/* Parameters for the disk drive. */ X#define MAX_DRIVES 2 /* this driver supports 2 drives (hd0 - hd9)*/ X#define DEV_PER_DRIVE 5 /* hd0 + hd1 + hd2 + hd3 + hd4 = 5 */ X#define NR_DEVICES (MAX_DRIVES * DEV_PER_DRIVE) X#define SECTOR_SIZE 512 /* physical sector size in bytes */ X#define BASE 1536 /* base address of kernel */ X X/* BIOS parameters */ X#define BIOS_ASK 0x08 /* opcode for asking BIOS for parameters */ X#define BIOS_RESET 0x00 /* opcode for resetting disk BIOS */ X#define BIOS_READ 0x02 /* opcode for BIOS read */ X#define BIOS_WRITE 0x03 /* opcode for BIOS write */ X#define DRIVE 0x80 /* BIOS code for drive 0 */ X#define PART_TABLE 0x1C6 /* IBM partition table starts here in sect 0 */ X XPRIVATE unsigned char buf[BLOCK_SIZE]; /* Buffer used by the startup routine */ XPRIVATE message w_mess; /* message buffer for in and out */ X 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_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 int wn_maxsec; /* maximum number of sectors per track */ X long wn_low; /* lowest cylinder of partition */ X long wn_size; /* size of partition in sectors */ X int wn_count; /* byte count */ X int wn_drive; /* 0x80 or 0x81 */ X vir_bytes wn_address; /* user virtual address */ X} wini[NR_DEVICES]; X XPRIVATE struct param { X int nr_cyl; /* Number of cylinders */ X int nr_heads; /* Number of heads */ X int nr_drives; /* Number of drives on this controler */ X int nr_sectors; /* Number of sectors per track */ X} param0, param1; X Xint nr_drives; X Xint Ax, Bx, Cx, Dx, Es; X X Xbios13() X{ X union REGS in_regs, out_regs; X struct SREGS seg_regs; X X in_regs.x.ax = Ax; X in_regs.x.bx = Bx; X in_regs.x.cx = Cx; X in_regs.x.dx = Dx; X seg_regs.es = Es; X int86x(0x13, &in_regs, &out_regs, &seg_regs); X Ax = out_regs.x.ax; X Bx = out_regs.x.bx; X Cx = out_regs.x.cx; X Dx = out_regs.x.dx; X return; 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 vir_bytes vir, ct; X unsigned locyl, hicyl, c1, c2, c3; X int r, device, errors = 0; X long sector; X phys_bytes user_phys; X extern phys_bytes umap(); X char far *pointer; X unsigned int segment; X X /* Decode the w_message parameters. */ X printf("Entered W_do_rdwt\n"); X device = m_ptr->DEVICE; /* minor device #. 1-4 are partitions */ X if (device < 0 || device >= NR_DEVICES) return(EIO); X if (m_ptr->COUNT != BLOCK_SIZE) return(EINVAL); X printf("Passed BLOCK_SIZE test\n"); X wn = &wini[device]; /* 'wn' points to entry for this drive */ X X /* Set opcode to BIOS_READ or BIOS_WRITE. Check for bad starting addr. */ X wn->wn_opcode = (m_ptr->m_type == DISK_WRITE ? BIOS_WRITE : BIOS_READ); X if (m_ptr->POSITION % BLOCK_SIZE != 0) return(EINVAL); X X /* Calculate the physical parameters */ X sector = m_ptr->POSITION/SECTOR_SIZE; /* relative sector within partition */ X printf("sector is %ld wn_size is: %ld\n", sector, wn->wn_size); X if ((sector+BLOCK_SIZE/SECTOR_SIZE) > wn->wn_size) return(EOF); X printf("Passed sector test\n"); X sector += wn->wn_low; /* absolute sector number */ X wn->wn_cylinder = sector / (wn->wn_heads * wn->wn_maxsec); X wn->wn_sector = (sector % wn->wn_maxsec); X wn->wn_head = (sector % (wn->wn_heads * wn->wn_maxsec) )/wn->wn_maxsec; 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 /* Do the transfer */ X vir = (vir_bytes) wn->wn_address; X ct = (vir_bytes) wn->wn_count; X pointer = buf; X segment = FP_SEG(pointer); X user_phys = ((unsigned long)segment << 4) + vir; X printf("pointer is 0x%.8lx\n", pointer); X printf("segment is 0x%.4x\n", segment); X printf("offset is 0x%.4x\n", vir); X Ax = (wn->wn_opcode << 8) | 2; /* read or write 2 sectors */ X Bx = (unsigned) (user_phys & 0xF); /* bx = low order 4 bits */ X Es = (unsigned) ((user_phys >> 4) & 0xFFFF); X hicyl = (wn->wn_cylinder >> 8) & 03; /* two high-order bits */ X locyl = (wn->wn_cylinder & 0xFF); /* 8 low-order bits */ X c1 = (locyl<<8); X c2 = (hicyl<<6); X c3 = ((unsigned) wn->wn_sector) + 1; X Cx = c1 | c2 | c3; X Dx = (wn->wn_head<<8) | wn->wn_drive; X printf("Starting call to BIOS\n"); X printf("Ax is: 0x%.4x\n", Ax); X printf("Bx is: 0x%.4x\n", Bx); X printf("Cx is: 0x%.4x\n", Cx); X printf("Dx is: 0x%.4x\n", Dx); X printf("Es is: 0x%.4x\n", Es); X bios13(); X r = (Ax >> 8) & 0xFF; X printf("bios13 status is: 0x%.2x\n", r); X return(r == 0 ? BLOCK_SIZE : EIO); X} X X X/*============================================================================* X * get_params * X *============================================================================*/ Xget_params(dr, params) Xint dr; Xstruct param *params; X{ X Dx = dr + DRIVE; X Ax = (BIOS_ASK << 8); X bios13(); X params->nr_heads = ((Dx >> 8) & 0xFF) + 1; X params->nr_sectors = (Cx & 0x3F); X params->nr_cyl = ((Cx & 0xC0) << 2) + ((Cx >> 8) & 0xFF); X params->nr_drives = (Dx & 0xFF); X} X X/*============================================================================* X * init_params * X *============================================================================*/ Xmain() X{ X unsigned int i, j; X X get_params(0, ¶m0); X get_params(1, ¶m0); X X /* Get the number of drives */ X nr_drives = param0.nr_drives; X X /* Set the parameters in the drive structure */ X for (i = 0; i < DEV_PER_DRIVE; i++) X { X wini[i].wn_heads = param0.nr_heads; X wini[i].wn_maxsec = param0.nr_sectors; X wini[i].wn_drive = DRIVE; X } X wini[0].wn_low = wini[DEV_PER_DRIVE].wn_low = 0L; X wini[0].wn_size = (long)((long)param0.nr_cyl X * (long)param0.nr_heads * (long)param0.nr_sectors); X for (i = DEV_PER_DRIVE; i < (2*DEV_PER_DRIVE); i++) X { X wini[i].wn_heads = param1.nr_heads; X wini[i].wn_maxsec = param1.nr_sectors; X wini[i].wn_drive = DRIVE + 1; X } X wini[DEV_PER_DRIVE].wn_size = (long)((long)param1.nr_cyl X * (long)param1.nr_heads * (long)param1.nr_sectors); X X printf("Starting read of partition table\n"); X /* Read the partition table for each drive and save them */ X for (i = 0; i < 1; 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 printf("Can't read partition table of winchester %d\n", i); X printf("Read partition table %d completed\n", i); X X X for(i = 0; i < 5 * 8; i += 8) X { X for(j = 0; j < 8; j++) X printf(" %.2x", buf[i + j] & 0xFF); X printf("\n"); X } X i = XT_WINI_VECTOR; X printf("XT_WINI_VECTOR is: %d 0x%.2x\n", i, i); X i = PRINTER_VECTOR; X printf("PRINTER_VECTOR is: %d 0x%.2x\n", i, i); X } X} X /