Atbios Kit Nov89

261
AT BIOS KIT The Comprehensive Guide to Creating an AT Bios in C " . .. _ A Complete Description of the Bios Including Source Code on Diskette John O. Foster & John P. ChQisser Annabooki I SBN 0-9 2 9392-02-7

Transcript of Atbios Kit Nov89

Page 1: Atbios Kit Nov89

AT BIOS KIT

The Comprehensive Guide to Creating an AT Bios in C

" .

,l{t~~~J~t~~}}~]::~.:: . . _

A Complete Description of the Bios Including Source Code on Diskette

John O. Foster & John P. ChQisser

Annabooki I SBN 0-9 29392-02-7

Page 2: Atbios Kit Nov89

AT BIOS KIT

The Comprehensive Guide

to Creating an AT Bios in C

John O. Foster & John P. Choisser

Page 3: Atbios Kit Nov89

AT BiosKit

by JohnO. Foster and John P. Choisser

PUBLISHED BY

Annabooks 12145 Alta Carmel Court, Suite 250-262 San Diego, CA. 92128

Copyright (C) Annabooks 1988, 1989

Copyright (C) FOSCO 1988, 1989

All Rights Reserved. No part of the contents of this book may be reproduced or transmitted in any form or by any means without the written permission of the publisher, except for the inclusion of brief quotations in a review.

Object Code produced from the Source Code mes may be reproduced only in accordance with the terms of the license agreement.

November 1989

Printed in the U oited States of America

ISBN 0-929392-02-7

This book is designed to provide information about a Basic Input Output System (BIOS) for an AT type computer. No warranty of suitability, purpose, or fitness is implied. The information contained within as supplied on an "as-is" basis. The authors and publishers shall have neither liability nor respon­sibility to any person or entity with respect to any loss or damage, real or claimed, in connection with or arising from any information contained in this book.

Page 4: Atbios Kit Nov89

Dedication

John O. Foster

This Book is dedicated especially to Patricia, and to the rest of the family for all their help and support.

John P. Choisser

This Book is dedicated to Coleen for her loving support during my career change.

Page 5: Atbios Kit Nov89

Preface

What started as a diversion has turned into a gratifying nuisance. Publishing the XT­AT Handbook and the XT Bioskit was an exercise in "Is anyone interested?" The Handbook proved there were some people out there, and the XT BiosKit indicated there were a lot of people out there. "Do you publish an AT Bios Book?" was often asked. When we at Annabooks tallied up the interest, the next move was obvious. More and more system designers are moving from 8088 based systems to 286 and 386 based systems. And the fascinating thing we heard was the variety of uses to which the PC architecture was being put. ..

We heard from those who are involved in automation, robotics, research, education, avionics, consumer and office products, energy management and control, and industries and applications too numerous to mention, both in the U.S. and around the world. Product volumes involved ranged from 5 and 10 per year, to thousands per month.

We even heard that because of the BiosKit, projects that were designed for 286 based systems could be changed to 8088 based systems. Being able to use the BiosKit was important enough to justify changing the product.

For all you who asked for an AT BiosKit, we are happy to present this latest volume in an exciting series which will cover a variety of topics, always in the form of a "working" book.

John O. Foster Hidden Meadows, California November 1988

Page 6: Atbios Kit Nov89

Table of Contents

SECTION A "ABOUT THE BIOS"

One Introduction

Two Audience

Three About the Programs

Four Tools Required

Five Ownership, License, and Warranty

Six Overview

SECTIONB 'THE C UTILITY PROGAMS"

One The Biossum File

Two The Biosdate File

Three The Biostype File

Four The Biosgen File

SECTIONC 'THE BUILD PROGRAMS"

One The Make ·File

Two The Link File

Three The Cut.inp File

SECTIOND 'THE ASM PROGRAMS"

One The Prfx.inc File

Two The Top File

Three The Pad File

Four The Fill File

Five The Data File

Six The Virt File

Page 7: Atbios Kit Nov89

SECTIONE 'THE CPROGRAMS"

One The Kit.h File

Two The Misc File

Three The Pod Module

Four The Equipment Driver

Five The Memory Size Driver

Six The Keyboard Driver

Seven The Video Driver

Eight The Floppy Disk Driver

Nine The Hard Disk Driver

Ten The Boot File

Eleven The Cassette Driver

Twelve The Parallel Printer Driver

Thirteen The Comm Driver

Fourteen The Timer Interrupt

Fifteen The Time of Day Function

Sixteen The Print Screen Function

Seventeen The Sys Vue File

Page 8: Atbios Kit Nov89

SECTIONF "ODDS AND ENDS"

One Loading Static Ram

Two The Indent Program

Three The Hilite Program

Four The Parens Program

Five The Bin2Hex Filter

Six The Splitbin Program

Seven The Mergebin Program

Eight The Patch.asm File

Page 9: Atbios Kit Nov89

NOTES

Page 10: Atbios Kit Nov89

SECTION A

About the Bios

This section introduces the Bios, lists some reasons for creating your own customized Bios, explains Ownership and License information, and provides an Overview of the structure of the Bios.

Page 11: Atbios Kit Nov89
Page 12: Atbios Kit Nov89

Introduction A·I·I

ONE

Introduction

Unseen and unnoticed, the Bios (Basic input/output system) of a personal computer takes control when power is switched on, setting up the hardware devices, running tests, and booting up the operating system from disk. Without a Bios the machine is an unusable, non-operating collection of hardware components. Yet the Bios is a mysterious component for the majority of users. The Bios is a collection of programs stored on a read-only memory chip and is usually considered to be part of the hardware set, but these routines are like any other software. They can -be analyzed, understood, modified and re-created as desired.

This Book

This book is a guide to analyzing and understanding what a Bios is, how it works, and how one goes about creating a Bios. The descriptions of the Bios functions are augmented with listings of the programs required to perform those functions. The auxiliary tools and utility programs which are used to create the Bios are also included with an explanation of their purpose and function.

What is the Bios?

Bios is an acronym for Basic input/output system. It is a set of programs that reside in non-volatile memory (often called firmware; programs that are implemented in hardware memory chip(s) and are not lost when power is turned ofO. The Bios includes the power-on diagnostics, a boot-up program, and device drivers for the keyboard, disk, display, serial ports, printer port, and miscellaneous functions. A Bios is usually written in assembly language, but the BiosKit is done in the C language wherever possible. Some low-level operations require assembly language for memory allocation reasons and some operations are done in assembly language for efficiency. But by providing the bulk of the BiosKit in C, it is much easier to understand, modify, and maintain the code.

Why do your own Bios?

You may want special features, such as special interface card support, Sys Vue capability, faster bootup, equipment status displays, and so forth. Some of these features are difficult to implement with a supplied Bios since you do not have the capability to modify it. Additionally, a standard Bios may not have the compatibility that you desire. You may also wish to upgrade your machine to newer capabilities that are included in later generations of compatible computers.

If you are a manufacturer or systems integrator, you may have found that your own Bios requires expensive long-term commitments to a Bios vendor that may not be able to respond to your needs in a timely manner. Once you have control of your Bios in your own hands, you will be able to modify and maintain your Bios at your own discretion.

If you are a manufacturer of systems for use in government or commercial applications which require delivery of source code for all software included in a system, BiosKit allows you to easily meet these requirements without cumbersome

Page 13: Atbios Kit Nov89

A·l·2 Introduction

escrow agreements or additional payment to a Bios Supplier to obtain source code. By including BiosKit Documentation as part of your product, you may satisfy your project requirements. If your project requires special verification or certification activities, Bioskit not only gives you access to source code, it also allows you to configure it as you desire.

A· Type BiosKit

Page 14: Atbios Kit Nov89

Audience A·2·1

TWO

Audience

This book is intended for various groups of people:

* Those who have an unsatisfied curiosity about the internal workings of their personal computer.

* Those who are involved in the hardware and system design details of PC's and need to understand the workings of a Bios.

* Those who are creating special applications of PC systems and find that the typical PC Bios may have some shortcomings or omissions.

* Those who just want to make their own Bios so they can enjoy the satisfaction of having done it.

* And especially for those people that are in more than one just one of the above groups.

Page 15: Atbios Kit Nov89

More Notes

Page 16: Atbios Kit Nov89

About The Programs A·3·1

THREE

About the Programs

This book and the magnetic media included with it provide you with the source code and explanations needed for you to customize your own Bios for an AT type compatible computer. The majority of the source code is in the C language with supporting routines in assembly language. C was chosen for a variety of reasons, including:

* It is well suited to systems level programs because it permits access to machine features.

* It is widely used, understood, and a de-facto standard among system level programmers.

* There are many publications available for reference, tutorials, as well as periodical publications for alternate information.

* It is supported by a variety of affordable compilers.

* Its architecture and structure encourage good programming practices which help to minimize the frustrating aspects of debugging and error-correction.

Because of some restrictive aspects of a Bios program, some of the programs are written in assembly language, as you might expect with systems-level C programs. This is required because:

* Certain locations in the completed program need to be fIXed at absolute memory locations (the reset jump).

* Constants need to reside in read-only memory and be allocated to the code segment in fIXed locations.

* Some operations such as block moves (used in CRT scrolling, for instance) are much faster than the C counterparts.

Page 17: Atbios Kit Nov89

Things To Do

Page 18: Atbios Kit Nov89

Tools Required A-4-1

FOUR

Tools Required

Building and customizing the Bios requires some tools. Knowledge is the basic tool. Then you will need the physical tools; the hardware and software described below.

Knowledge Tools

Readers should have or be prepared to acquire some degree of skill in the following areas to comprehend and become proficient in the creation and enhancement of a Bios:

* operation of DOS * operation of a text editor * assembly language understanding * understanding of the C language * understanding of the AT architecture

There are many excellent publications available on these subjects in addition to the manuals that are supplied with the software tools listed below. By visiting your library and book store, and by reading computer periodicals, and especially by talking to computer-interested acquaintances, you will find ways to augment your knowledge. For those who may be apprehensive about tackling a Bios project, remember that knowledge is acquired by bits and pieces. Curiosity, patience, and a positive attitude will be your best ally.

Software Tools

To build the Bios you will need the following tools: * C Compiler

Recommended - Microsoft V 5.1 or later Other Compilers may require some modification of the Source Code.

* Macro-Assembler - Microsoft V 5.1 or later * Linker - Microsoft (included with MASM or Compiler) * Debug program (included with MASM) * A Make Utility (included with MASM or Compiler) * An Archive or backup utility is also recommended.

You may chose alternate tools, but they may require some modification of the source code to build and execute successfully.

Hardware Tools

Your development computer should be an XT / AT compatible with 640K of ram, a hard disk, and a printer. Either a color or monochrome monitor is sufficient.

To program Eproms for your computer you will need a Prom programmer. The Sunshine (brand name) programmer (approximately $125.00) is suggested.

To erase Proms, a Walling Datarase UVProm Eraser is suggested ($35 to $55).

Page 19: Atbios Kit Nov89

A·4·2 Tools Required

Target Tools

The programs in this book were designed for use with an AT compatible hardware set. This means that the original AT or the truly compatible "clone/compatibles" will require little or no Bios modification to operate successfully. There are some areas of difference, however, that may affect your Bios details. Some of these are described below.

Prom/Rom chip types - Some high volume AT's use masked Rom chips for the Bios. These chips mayor may not have the same electrical characteristics and pinout as the Prom chips you would normally use for your Bios. You should verifY that the pinout of the original Bios chip you intend to replace is compatible with the chip you will be using. If it is not pin compatible, you may be able to replace it by using an appropriate adapter.

The next consideration is the addressing capability of the original Bios Socket(s) in your target system. Depending on the original design, the address mapping may be hard-wired or jumper (or decoding device) selectable to accommodate the Bios Proms you create. You should have the range of FOOOO-FFFFF available for your Bios. This will probably require two Proms, one for even bytes and one for odd bytes in your target system.

Turbo machines generally interpret a special combination of keystrokes to enter/leave the turbo mode. This decoding may be added to the keyboard handler (Bioskb.c ) in the scan code conversion section of the hardware interrupt service routine. Turbo-AT's may use one of the spare output pins of the 8042 keyboard controller chip to change the CPU clock speed. To determine if this method is used, you may manually toggle these bits using Sysvue (Port In and Out commands) to see if this scheme is used to control the Turbo switching. If you include a Turbo switching feature and subsequently have floppy disk failures, the DMA clock speed is to be suspected. Some Turbo motherboards switch the DMA clock to high speed along with the CPU clock. It may be necessary to include an "Unturbo" and "Returbo" sequence in the floppy disk module (Biosdisk.c) to insure that the DMA is operated at the slow clock speed during disk transfers. To do this, save the state of the signal used to implement the speed switch upon entry to the Disk_io handler, and restore it to its previous condition upon exit. A Turbo machine may have a

A-Type BiosKit

Page 20: Atbios Kit Nov89

Tools Required A ·4·3

"Turbo" mode display (typically an LED) to show when it is in turbo mode. This indicator is usually driven from the same speed switch signal that controls the clock.

One method of investigating compatibility is to attempt to run the standard version of DOS on a computer. If a given computer operates only with its customized version of DOS, some hardware incompatibility might be expected.

SysVue

Bonus - BiosKit includes the source code for Sys Vue, a Prom resident program that provides many of the features of disk resident Debug programs. Sys Vue is always available with a keystroke sequence. It is extremely handy for checking custom features of your Bios.

Once you have successfully built the standard version of the BiosKit, you will be ready to consider special versions for your particular application.

Section A: About the Bios

Page 21: Atbios Kit Nov89

Things I Should Do Soon

Page 22: Atbios Kit Nov89

Ownership, License, Warranty A·5·1

FIVE

Ownership, License, and Warranty

The following paragraphs explain the ownership (right of title) of the Source Code and of the Binary Code generated from it, the license granted to you to duplicate the object code, and the warranty of this published information. This information is important to you. Please read it carefully.

Ownership oj Source Code

The Source Code for BiosKit is an intellectual work covered under the copyright laws of the United States and other countries. Title to ownership is retained by FOSCO. Your purchase of the BiosKit includes a license to use the Source Code, but does not convey right of title of said Source Code to you. You may use the Source Code in accordance with the License Agreement as described in the following paragraph.

License to Duplicate

With the purchase of the BiosKit, FOSCO and Annabooks have waived the $4.00 per copy license fee for the first ten (10) copies of the BiosKit Binary code for your own use, or for sale in your product.

You are responsible for remitting to Annabooks the fee of $4.00 per copy for additional copies. This fee remittance should be made payable to Annabooks and annotated as "AT Bioskit License Fee". It should be made on not less than a quarter-year basis and must be payable in U.S. (US$) funds.

Payments should be sent to the following address: Annabooks 12145 Alta Carmel Court, Suite 250-262 San Diego, CA. 92128

Please abide by the license fee requirements to avoid the need for legal recourse on the part of Annabooks and FOSCO to insure compliance with these requirements.

During the build/ customization phases, you may program an unlimited number of Proms until you have completed the Bios. Once you place the Proms in a computer used to run programs, the Proms are included in the ten (10) quantity covered by this license to duplicate.

Any Bios built from the BiosKit must include the FOSCO copyright information included with the original source code. You may add additional information, but you may not delete any copyright information included in the standard BiosKit.

Page 23: Atbios Kit Nov89

A·5·2 Ownership, License, Warranty

DISCLAIMER AND LIMITED WARRANTY

The information contained in this book and on the diskette is believed to be factual and accurate; however, no claim of such, nor of fitness to purchaser's intended use, is implied. Although the programs described in this book (and contained on the diskette) are believed to be compatible in function and operation with the normal operation of an AT type computer, no warranty as to the completeness of compatibility to any other Bios is implied or expressed. Prudence dictates that the user must verify fitness, correctness, and applicability of the information contained in this publication. The diskette(s) are warranted to be readable when installed in a compatible computer. Warranty is limited to the replacement of unreadable diskette(s) within 90 days of purchase. The Diskette(s) are not copy-protected and should be used only to make working copies, and then archived for backup purposes. Liability under this warranty is limited to the replacement of the diskette(s) even if claims otherwise have been made by purchaser or any user of the information contained in this publication. This statement of warranty constitutes the full and complete agreement between seller and buyer. and may not be modified by oral representation or written instrument without the permission of FOSCO and Annabooks.

A· Type BiosKit

Page 24: Atbios Kit Nov89

Overview A·6·1

SIX

Overview

This chapter is intended to acquaint you with the major functions and parts of the Bios. To do this, we will follow the flow of the Bios from the power-on hardware reset point and summarize what happens as the computer is turned on. Descriptions of detailed operations will follow in later sections and be correlated with the Source Code Listings.

Power On -

The 80286 processors start operation at segment:offset address FFFFF:OOOO. This means that program execution begins at the last paragraph (16 bytes) at the top of address space. This location normally will have a far jump to a lower address where the Bios will start to initialize and check-out hardware features of the system.

Diagnostics -

This usually starts at a label called 'reset' and includes checking of the CPU chip registers, tests and initialization of the peripheral chips, and ends up by invoking a bootstrap routine.

Bootstrap -

The function of the bootstrap routine is to load DOS from a floppy disk. If you have a hard disk in the system, a failure to boot from a floppy is usually followed by an attempt to boot from the hard disk. If no disk is available, you may wish to default to Sys Vue or some other Prom resident program you may elect.

Drivers -

The Bios contains the low-level drivers for a variety of devices. DOS normally assumes these drivers are present in the Bios and makes calls to them to perform peripheral access. The drivers correspond to the Bios Interrupts documented in various publications about PC's and DOS. To fully support DOS, these drivers must be included, and their devices initialized by the Bios.

Bios Structure

This description of the Bios structure IS intended to clarify. some of the characteristics of the Bios.

The 80286 processor starts executing code (from a power-up reset) at the highest paragraph in the memory map. This is at Segment:Offset FFFFF:OOOO. To properly respond to the hardware reset, valid executable code must be stored at this location in the Bios Prom. To insure that the instruction intended for this location is assembled and linked correctly, the final module of the Bios is manipulated in such a way that the normal linker utilities (such as Microsoft's Linker which links programs in an ascending address sequence), can achieve this result. The top module of the Bios is written in Assembly language, so that programmer control is maintained over the location of certain instructions. Additionally, the top module

Page 25: Atbios Kit Nov89

A ·6· 2 Overview

provides a place to include various table structures and assembly language subroutines, which are C functions.

From the power-on reset, a jump is executed (at FFFFF:OOOO) to an assembly language initialization code sequence which initializes the DMA controller, the Ram Refresh, and the first 64 Kbytes of System Ram. Once this has been accomplished, the C language POD (Power On Diagnostic) module is executed. This module continues the power-up and diagnostic checks of the system, and also calls setup (initialization) routines in the various device driver modules. When the system has been completely initialized, the bootstrap function is called.

The POD process includes: loading the interrupt vector locations, initializing the display adapter, determining the size of the system Ram, testing the system Ram, reading the equipment configuration CMOS Ram, performing a checksum test on the Bios prom, identifying and initializing COM and LPT ports, calling any executable Rom option modules, initializing the floppy disk drive(s), and finally calling the bootstrap procedure.

Why Link is Done Twice

During the linking process when buildin~ the Bios, a trial link is performed. This trial link determines how far short the BIOS falls of filling a complete segment (64 Kbytes). This shortfall in length is calculated, and a filler module is built which will compensate for the shortfall. The Bios is then linked again with the filler module to produce a Bios in whic~ the required locations are fIXed at the correct addresses. This file is then converted from an .EXE format file to a .BIN binary image file suitable for transfer to a Prom programmer.

How to develop and test a Bios

The simplest way, of course, is to build a Bios, program a Prom, install the Prom in the system, and see how the system runs. This method is time consuming and debugging can be difficult, particularly if the system doesn't run at all. The preferred method is to install a Static Ram Adapter Card residing above the video ram area, and away from any rom-scan devices such as EGA Video and Hard Disk Adapters that might be installed in your target system. Recommended location is segment DOOO. The Test Bios is then loaded into the Ram area and a Jump instruction is executed to start executing the Test Bios. The Load-and-Jump can be performed using a Debug Batch file as shown in Section F. To effectively integrate the Bios, you should have (or should add) a pushbutton reset switch to your target system. This allows you to easily reset and restart your system with its prom-based Bios if your Test Bios should lock up or run away due to modifications which you are testing.

An additional aid to testing is to add debug mode display statements to track the activity of the Bios. These may be included in your C modules by using the write_string("text") statement. Hexadecimal byte and word values may be dumped

A-Type BiosKit

Page 26: Atbios Kit Nov89

Overview A ·6·3

using the lbyte(value) and lword(value) statements. By referring to the BiosVue.c module, you may examine examples of the usage of these statements.

When you have verified the operation of your modified Bios, the debug-mode statements may be removed, and the Bios rebuilt.

Driver Structure

By examining the structure of the Driver modules, you will see that they are essentially self-contained. They may call common assembly language functions in BiosTop.asm and common C functions in BiosMisc.c, but they seldom will call other modules except through the Interrupt structure. This helps to isolate interaction and serves to make testing easier.

Drivers have the general structure of a Setup routine followed by the Driver itself. Some drivers may also have a service routine for its associated hardware interrupt. The Setup routines are called from BiosPod to initialize the drivers during the Power-On-Diagnostics.

Programming Style

As you work with the source code, you will begin to apply your particular style of programmin~ to re-writes, additions, and changes. This is normal and it is a sign of your increasIng understandin~ of the programs. Don't be afraid to analyze the program structure and expenment. There are at least as many ways to code a function as there are programmers! Since this book deals with each topic only once, we had to present each example in a particular manner. You have a different perspective and style, and you will probably see it in a slightly different manner. Remember there are many right ways to code a function. It is sometimes difficult to find one of those right ways; it is usually easier to find one of the wrong ways!

Section A: About the Bios

Page 27: Atbios Kit Nov89

Things I Should Avoid Doing

Page 28: Atbios Kit Nov89

SECTIONB.

The C Utility Programs

These programs are used during the building process to add the date-stamp, calculate the checksum, install the CPU type identification, and to fix some locations at absolute addresses.

Page 29: Atbios Kit Nov89
Page 30: Atbios Kit Nov89

The Biossum File B-l-1

ONE

The Biossum File

The Biossum.c file is used during the Bios Build process to calculate the additive checksum of the Bios and to insert the checksum value into the last byte of the Bios. It looks for the first non-FF location and treats it as the start of the block. If the Bios is padded with FF's at the front of the file, the program will scan forward every 2K bytes to look for the start. This allows you to reserve space in 2 Kbyte blocks at the front for your own special programs. The Rom-Scan routine will determine where the Bios starts and scan up to that point.

/************************************************************************************~**************

* * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * * Module Name: Bios checksum calculator * * Version: 1.00 * * Author: FOSCO * * Date: 1-5-89 * * * Functional Description: * : This program calculates a checksum and inserts it into the last byte location of the Bios.

* Argunents: * Filename * * Return: * None * : Version History:

* ***************************************************************************************************/

/* INC L U D E F I L E S */

#include <stdio.h>

/* FUN C T ION PRO TOT Y PES */

/* G LOB A L V A R I A B L E S */

uns i gned numread i' char sum,buffer[~2t68]; FILE *stream;

/* G LOB A L CON S TAN T S */

/* L 0 CAL D E FIN I T ION S */

/* L 0 CAL CON S TAN T S */

/* PRO G RAM */

main(argc,argv) int argc; char *argv[]; { if (argc <2) (

}

printf("Not enough parameters on COlllll8nd line\n"); exit(O);

if «stream = fopen(argv[1] ,"r+b"» == NULL) printf(IICould not open fi le for reading\nll);

else (

sum=O' numread = fread«char *)buffer,sizeof(char),32768,stream);

Page 31: Atbios Kit Nov89

}

B·l·2 The Biossum File

/* ** Scan for the first non -ff- cell at 2k boundaries to mark the start of the bios code. ** Reserve the prior cells for rom module integration later when customizing the bios prom ** with extensions. */

for (i=O;(i < numread) && (buffer[i] == Oxff); i += 2048);

/* i is advanced to beginning of actual bios code */ for (;i<numread;i++) sum += buffer[i];

numread = fread«char *)buffer,sizeof(char),32767,stream); for (i=O;i<numread;i++) sum += buffer[i]; sum = O.-sum; buffer[l] = sum; fseek(stream l -1L,SEEK END); fwrite(&sum,1,1,stream);

fclose(stream); }

A· Type BiosKit

Page 32: Atbios Kit Nov89

The Biosdate File B-2-1

TWO

The Biosdate File

The Biosdate.c file is the program which inserts the current date value as the date­stamp in the Bios module. This date is determined from the current date in your development machine. It will obviously affect the overall checksum of the Bios module, if you re-build on different days.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * * Module Name: bios date routine * * Version: 1.00 * * Author: FOSCO * * Date: 1-05-89 * * Filename: Biosdate.c * * Functional Description: * * Insert date string into bios binary file. This program inserts the current date information * into the date field in the Bios at location FFF5 * * * Ar~unents: * Fllename * * Return: * Writes date field in bios.bin file * * Version History: * 1-5-89 font revision * ***************************************************************************************************/

/* INC L U 0 E F I L E S */

#include <stdio.h>

/* FUN C T ION PRO TOT Y PES */

/* G LOB A L V A R I A B L E S */

FILE *stream; char date_buffer[9];

/* G LOB A L CON S TAN T S */

/* L 0 CAL 0 E FIN I T ION S */

/* PRO G RAM */

main(argc,argv) int argc; char *argv [] ; {

}

if (argc <2) (

}

printf("Not enough parameters on conmand l ine\n"); exiteO);

if «stream = fopen(argv[1],lIr+b"» == NULL) printf("Could not open file for reading\n"); else ( fseek(stream,-11,SEEK END); /* find date field */ strdate(date buffer);

Twrite«char -)date buffer,sizeof(char),8,stream); } -fclose(stream) ;

Page 33: Atbios Kit Nov89

Things Someone Else Should Do

Page 34: Atbios Kit Nov89

The Biostype File B-3-1

THREE

The Biostype File

The Biostype.c file is used to insert a byte identifying the type of system in which the Bios is installed. The type identification may be used by some applications (or the Bios if so desired) to determine operational characteristics of the system hardware and/ or software. This byte is located at the next- to-last location of the Bios. In an AT Bios, there is also another identification function; Interrupt 15, Function code CO, which returns system configuration parameters. This parameter block provides additional type information. /************************************************************************************************** * : Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

: Module Name: Bios type

* Version: 1.00 * * Author: FOSCO * * Date: 5-5-88 * * Filename: biostype.c * : Functional Description:

* Insert CPU Type byte into bios binary file. This program inserts a machine identification byte * at location FFFE 1n the Bios. Because of an Assembler quirk, if we try to define this in the * Source file, the assembler increments the offset counter and believes that the segment becomes : larger than 64K bytes, which it considers an error condition.

* * Ar~unents: * b10stype filespec [typel * where type is pc,xt,at,jr,xt640 * if type is omitted, then default is xt * * Return: : Writes type byte in bios.bin file 'filespec'

* Version History: * * ***************************************************************************************************/

/* INC L U 0 E F I L E S */

#include <stdio.h> #include <string.h>

/* FUN C T ION PRO TOT Y PES */

/* G LOB A L V A R I A B L E S */

FILE *stream: char type_buffer[2l;

/* G LOB ALe a N S TAN T S */

/* LaC A L 0 E FIN I T ION S */

#define at Oxfc /* these are the standard defined types */ #def i ne xt Oxfe #define pc Oxff #def i ne j r Oxfd #define xt640 Oxfb

/* PRO G RAM */

main(argc,argv) /* bios.bin */ int argci char *argv [] ; { char cpu_type = xt; /* default to XT type byte */

Page 35: Atbios Kit Nov89

B·3·2 The Biostype File

if (argc <2) {

}

printf("Not enough parameters on conmand line\nll);

exi teO);

if (argc > 2) { if (strc~i(argv[2],"at") == 0) cpu_type = at; i f (strc~i(argv[2], IIxtlf) == 0) cpu_type = xt; if (strc~i(argv[2],IIJXIf) == 0) cpu_type = f?C; if (strc~i(argv[2] ,lfjrlf) == 0) cpu_type = Jr; if (strc~i(argv[2] ,lIxt640") == 0) cpu_type = xt640;

} if «stream = fopen(argv[1] ,"r+bll » == NULL) printf("Could not open file for reading\n"); else . { fseek(stream

6-2,SEEK END); /* find type field */

type buffer[ ] = cpu-type; . fwrite«char *)type_6uffer,sizeof(char),1,stream);

} fclose(stream);

}

A· Type BiosKit

Page 36: Atbios Kit Nov89

The Biosgen File B-4-1

FOUR

The Biosgen File

The Biosgen.c file is used during the build process to sense the size of the Bios code and calculate a value which will be used to upward justify the Biostop module so that it resides in the highest portion of the Bios segment. This is required to insure that when a power-on hardware reset occurs there is an instruction present to be executed. /*************************************************************************************************** * : Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

* Module Name: Bios filler generator * * Version: 2.00 * * Author: FOSCO * * Date: 12-01-88 * * Filename: biosgen.c * : Functional Description:

* This program reads the map file (bios.map) and calculates how far short it falls from ending at * the top of the segment. Then it builds a biosfill.inc file that pads out enough to complete the * segment (64k bytes). The .inc file is used in a second linking of the .obj files. This produces : a full 64k byte file with the power-on reset jumps fixed at offset FFFO in the binary image file.

* Ar!iJl.II1ents: : bl0sgen bios.map biosfill.inc

* Return: * Creates a biosfill. inc file * * Version History: 2.00 9/12/88 * The method of determining the file length was changed to operate with 5.1 tools. This program * now looks at the .MAP and searches for the ORG EOOO label. If it finds the label, it looks at * the offset value associated with it, and calcuTates the fill value from that. If it does not * find the label, it prints an Abort Message. If the .ma~ file shows that the Bios is too large, * it prints a message indicating that the Bios will not fit into the segment. * * Notes: * This file normally compiles with two Warning Messages. They may·be disabled by changing the * message level switch in the make file. The program will execute OK even with the warnings. * ***************************************************************************************************/

/* INC L U 0 E F I L E S */

#include <stdio.h> #include <string.h>

/* FUN C T ION PRO TOT Y PES */

unsigned int hval(unsigned char);

/* G LOB A L V A R I A B L E S */

FILE *stream· int radix = ~O; char first[20],second[20],third[20]; char *p;

unsigned int it unsigned int dlff; unsigned int find; /* find/no find flag */ unsigned int find string; unsigned long int-numread; unsigned char line[255], *result;

/* G LOB A L CON S TAN T S */

/* L 0 CAL 0 E FIN I T ION S *1

/* PRO G RAM */

Page 37: Atbios Kit Nov89

B·4·2 The Biosgen File

main(argc,argv) 1* sourcefile.map,destfile.inc *1 int argc; char *argv[]; {

/* this is the label we will search for */ char *estring = "_ORG_EOOOII;

/* this is where we move the offset value of the label*1

char *vstring = 110000";

if (argc <3) (

}

printf("Not enough parameters on comnand l ine\n"); exi t(O);

if «stream = fopen(argv[ll ,"r+b"» == NULL) printf("Could not open file for reading\n"); else { find = 0; /* check each line of the .map file for the wanted label*1 do ( if«result = fgets(line,255,stream» != NULL); ( /* check for the label */ if (strstr(result,estring) 1= NULL) ( find string = OxeOoo; strnepy(vstring,&line[6],4); diff = O( for(i=O;1<4;i++) { diff = (diff « 4) + hval(vstring[i]);

} find = 1;

} }

} while «result != NULL) && (find == 0»;

fclose(stream);

if (find == 0) 1* no find */ ( printf("Could not find ORG FOOO label in .MAP file\n\r"); printf("Aborting operation7\n\r")i printf(" 1. Check comnand line argunent speci fies .MAP file\n\r"); printf(1I 2. Check .MAP file for proper labels.\n\r")i

} else ( printf(1I File size = XSu\n\r tl ,diff+(Ox10000-find string»; if (diff >= find_string) -{ printf(".EXE file is to large to process - aborting fill generation\n\r")i

} else (

}

numread = find_string - diffi /* num to write */

printf(1I Free Space = XSu\n\r",numread);

/* now build the text line for the biosfill.inc file */ strcpy(first II cI:) II). strcpy(second,ultoa(numread,sec~,radix»; strcpy(third," dup(Offh)")i strcat(first,second)i strcat(first,third)i

if «stream = fopen(argv[2] ,"Wlt» == NULL) printf("Could not open file for wdting\n")i else ( fwrite«char *)first,sizeof(char),strlen(first),stream);

}

fclose(stream); }

} }

/* convert hex ascii to val */

unsigned hval(unsigned char cval) {

A· Type BiosKit

Page 38: Atbios Kit Nov89

unsigned val; cval -: '0'· if (cval > ~) cval -: 7; val: cval; return(val);

} .

The Biosgen File B-4-3

Section B: The C Utility Proauams

Page 39: Atbios Kit Nov89

Things I keep Forgetting

Page 40: Atbios Kit Nov89

SECTION·C

The Build Programs

These programs are used to assemble, compile and link the Bios modules. The process is automated to permit a complete build with just a few keystrokes.

Page 41: Atbios Kit Nov89
Page 42: Atbios Kit Nov89

The Make File C·l·l

ONE

The Make File

The Make File is the top level file used in building a Bios. It includes all the operations needed to compile and assemble the source files, to link them into a code module, and to convert the code module into a binary image file for Prom programming. This file will also build the utility programs needed for the build process. Using the MAKE utility simplifies the operation and allows the building of the Bios with just a few keystrokes.

#***********************************************************************************-*************** # # Copyright (c) 1988, 1989 FOSCO - All Rights Reserved' # # Module Name: atbios.make # # Version: 1.00 # # Author: FOSCO # # Date: 1-5-89 # # Filename: at # # Functional Description: # #" This is the Make file to build the AT Bios # To Build the Bios, type 'make bios' <enter> # # Version History: # # #***************************************************************************************************

#--- inference rules - see description of MAKE utility --­

.asm.obi: atprfx.inc masm $ IW1/Z1/z;

.obj.exe: link $*;

.c.obj: atkit.h cl IZp1 IJ IWO IG2 Ic IZl IZi lAS lOx S*.c

#-------------- list of files to build ------------------­

#--- These are utility routines used to build the Bios ----

# routine to fi II up to top module

biosgen.exe: S*.c cl IWO lOx IZi S*.c Ilink ICo

# routine to place date in binary file

biosdate.exe: S*.e cl IWO lOx IZi S*.c Ilink ICo

# routine to place type byte in binary file

biostype.exe: S*.e cl IWO lOx IZi S*.e Ilink ICo

# routine to checksum binary file

biossum.exe: S*.c cl IWD lOx IZi S*.c Ilink ICo

# routine to display parenthesized text

parens.exe: $*.c

Page 43: Atbios Kit Nov89

C·l·2 The Make File

cl IWO lOx Ili S*.c Ilink ICo

# routine to indent according to {}

indent.exe: S*.c cl IWO lOx Ili S*.c Ilink ICo

, routine to display comments

hilite.exe: $*.c cl IWO lOx Ili $*.c Ilink ICo

, routine to split out even/odd bytes

splitbin.exe: $*.c cl IWO lOx Ili $*.c Ilink ICo

, routine to merge in evenlodd bytes (for test purposes)

mergebin.exe: $*.c cl IWO lOx Ili $*.c Ilink ICo

bin2hex.exe: $*.asm masm $*. link $*;

# binary image to Intel hexadecimal filter

,---------- These are the Bios Modules -------------­

, routine to pad the front of the Bios

atpad.asm:

atpad.obj:

atdata.asm:

atdata.obj:

atprsc.obj:

atmem.obj:

atmisc.obj:

atboot.obj:

atvue.obj:

atcomn.obj:

atlcb.obj:

atdisk.obj:

athard.obj:

atlpt.obj:

, the data declaration module for biosvue

, print screen driver

, memory size driver

, misc drivers in 'c'

# bootstrap routine

, sys vue

# COllIn driver

, keyboard driver

# floppy disk driver

, hard disk driver

# lpt ddver

, crt driver

A· Type BiosKit

Page 44: Atbios Kit Nov89

atcrt.obj:

attmr.obj:

attod.obj:

atequi.obj:

atcass.obj:

atpod.obj:

atvirt.asm:

atvirt.obj:

attop.asm:

attop.obj:

'II timer driver

'II time of day driver

'II equipment driver

'II cassette driver

'II power on diagnostics

'II virtual mode driver

'II absolutized high location module

'11---------- This is the linking process ----------­'II make binary file of bios

at.bin: \ atdisk.obi atlink atkb.Obj atvue.Obj \ atcomm.ObJ atlpt.Obj atcrt.Obj atcut.inp \ atPOd.obj atpad.Obj atdata.Obj atvirt.Obj \ atboot.obj atcass.Obj atequi.ObJ attmr.Obj \ atmisc.obJ attop.Obj at \ attod.obj atprsc.Obj atmem.Obj athard.Obj \ biostype.exe biosdate.exe biossurn.exe biosgen.exe

copy atblank.inc atfill.inc masm atf ill· link Cilatlink biosgen at.map atfill.inc masm atf ill; link ICo Cilatl ink debug <atcut.inp biosdate at.bin biostype at.bin at biossurn at.bin spl itbin at

The Make File C·l·3

Section C: The Build Pro&rams

Page 45: Atbios Kit Nov89

Things I Forgot

Page 46: Atbios Kit Nov89

The Link File C-2-1

TWO

The Link File

The Link File is an indirect file used by the linker to convert the group of bios---.obj files into an executable (.EXE) file module. The EXE module will then be converted to a binary image file for loading a prom programmer. atpad+ atdata+ atpod+ atboot+ atconm+ atkb+ atdisk+ athard+ atlpt+ atcrt+ atequi+ atmem+ attmr+ attod+ atprsc+ atcass+ atmisc+ atvue+ atvirt+ atfill+ attop, at, at/m;

Page 47: Atbios Kit Nov89

Things I Remember

Page 48: Atbios Kit Nov89

The Cut.inp File C·3·1

THREE

The Cut.inp File

The Cut.inp is used after the second link to transform the .EXE file, which is output by the linker, to a .BIN (binary image file). This type of operation is usually done by using the DOS Utility "EXE2BIN", but "EXE2BIN" cannot handle a full segment .exe file.

**************************************************************************************************** * * Copyright ec) FOSCO 1988, 1989 - All Rights Reserved * : Module Name: Cut of bios after second linking

* Version: 2.00 * * Author: FOSCO * * Date: 1-5-89 * : Filename: atcut.inp

: Functional Description:

* * * * *

This input file is used to perfonm an exe -> bin load of the bios.exe file. Because it is a 64K file, the traditional exe2bin program overflows. This file directs that a 64 Kbyte output file (bios.bin) be written. This output file will be the binary image used for prom programming.

* Argll1lents: * * Return: * * Version History: * ***************************************************************************************************

nat.exe l rbx 1 rex o nat.bin w cs:O q

Page 49: Atbios Kit Nov89

Things Someone Should Tell Me

Page 50: Atbios Kit Nov89

SECTION:D

The ASM Programs

These programs are used to include assembly language functions, tables, virtual memory support, and initial start-up code for the Bios.

Page 51: Atbios Kit Nov89
Page 52: Atbios Kit Nov89

The Prfx.inc File D·l·l

ONE

The Prfx.inc File

The Prfx.inc is the include file used for the assembly (.ASM) modules. It specifies the memory model, macro definitions, segment loading order for the linker, and required absolute offset locations for various data and code.

page 55,132

.*************************************************************************************************** , Copyright (c) FOSCO 1988 - All Rights Reserved

Module Name: AT Bios assembly module prefix

Version: 2.01

Author: FOSCO

Date: 01-01-89

Filename: biosprfx.inc

Functional Description:

This include file is used for the standard definitions for assembly language modules of the bios.

It is used to define the segment names, the segment loading sequence, assorted macros, and location assignments.

Version History: 2.01 - Font revision

, .************************************************************************************************** ,

.286p • seq

-text segment word public 'code' text ends -data segment word public 'data'

:data ends

const segment word public 'const' const ends

bss segment word public 'bss' :bss ends

fill segment word public 'fill' :fill ends

-stack segment word stack 'stack' stack ends -atext segment word publ i c 'acode'

:atext ends

.model small,e

dgroup group _text,_data,const, bss,_fill,_atext assume cs:dgroup,di:dgroup

ok error

delay

.xl ist

equ equ

o -1

macros for Bios generation

macro Jq) J~ enan

$+2 $+2

Page 53: Atbios Kit Nov89

D·1·2 The Prfx.inc File

write cmos

macro push mov out delay out

r~

- push push call add enan

read cmos macro - push

call add enan

true false

equ equ

ax al,20h 20n,al

OaOh,al ax

macro address, value value address out cmos sp,4

address address incmos sp,2

-1 o

;---- stack swappers for interrupt routines ------

int header - p'ush

Jf11) enan

macro dest offset dest interrupt_shell

( this 8088 version emulates the push 1 nt header 88 macro dest

inmediate opcode ; this is the 8088 version

- Push ax push bp mov bp,sp

; this saves ax on the stack ; save bp while we access the stack ; use bp for a pointer

mov ax, offset dest xchg ax, [bp+21 pop bx jmp interrupt shell

i ax = dest restore ax and put the dest on the stack

; restore bp, leaving the dest

enan -

;-------- required by MS C Compiler ---------; This definition is r~ired by the C Compiler. ; The value was determined by looking the standard C libraries. _acrtused equ 9876h

Bios Equates

ana equ 00

pit~rt 0 equ 040h pit~rt-1 equ 041h pit~rt-2 equ 042h pi t~rt:cmnd equ 043h

pio~rt a equ 060h p!o~rt:b equ 061h plo.J>Ort c equ 062h pio~rt:cmnd equ 063h

segment 00 segment:OO

segment at 0 ends

icomment /* rom bios data area */

segment 40 conm l iit dw 4 dup(?) lpt_Tist dw 3 duP(?)

org 67h voffset dw vsegment dw ? vflag db

org 078h lpt timeout list db 4 dup(?) corrm timeout list db 4 dup(?) segment_40 inds

segment at 40h

?

?

;--------- macros used to indicate org conflicts

free=O slop=O

A· Type BiosKit

cina chamel 0 addr reg port addr

8255 port a addr 8255 port b addr 8255 port c addr

Page 54: Atbios Kit Nov89

The Prfx.inc File D·l·3

macro arg ifdef teql

romorg

tetJ1)=$ i f1 if ($ le (arg-OeOOOh) @out «- »,(arg-OeOOOh)-S,« bytes free» free=free+arg-$

else @out «- »,S-(arg-OeOOOh),« bytes TOO LONG I!!!!»~

%out slo~slop+$-(arg-OeOOOh)

endif endif

else t~$

endif if1 @OUt «»,arg,« ORIGIN OF &arg»

endif org arg-OeOOOh endn

@out macro arg1,arg2,arg3 .radix 16

@Qout

@Qout arg1,%(arg2),arg3 .radix 10 endn

macro %out endn

arg1,arg2,arg3 arg1 arg2 arg3

i------------------------------------------------------Rom entry points

Unfortunately, these entry points need to be enforced since many users assl.llle these to be fixed. Even though lt violates the PC rules, we have to live with it.

_copyright reset

-nmi Coot -conm table -conm-io ~ -keybOard io -keyboaraisr -disk io -equ -disk-isr equ -diskj)arms :printer io

video io equ :videojlarms _mem_slZe equ equlpment

-cassette io -video font -time of day -timer int -vector - dll1lny i ret :J>rinCscreen nard reset -date-st8ll1;) ~arc:rware_id

.list

.data

• code

equ OeOOOh equ OeOSbh equ Oe2c3h equ 0e6f2h

~~9h Oe729h

equ Oe82eh equ Oe987h OecS9h OefS7h equ Oefc7h

~~Sh Oefd2h

~1h OfOa4h

equ Of84dh equ Of8S9h equ Ofa6eh equ Ofe6eh equ OfeaSh equ Ofef3h equ OffS3h equ OffS4h equ OfffOh power on start equ OfffSh date stamp of bios equ Offfeh hardware 10 byte

Section D: The ASM ProlUams

Page 55: Atbios Kit Nov89

Things I Should Tell Someone

Page 56: Atbios Kit Nov89

The Top File D·2·1

TWO

The Top File

The Top.asm File is an assembly language file which is linked so as to reside in the top portion of the Bios segment. It is the module which responds to the power-on hardware reset of the system. This module is where the execution of code starts, and is used to reset critical peripheral functions and start Ram Refresh. A minimum block of Ram is assigned to allow the use of a stack and then control is transferred to the POD (Power On Diagnostics) routine. This module also contains the assembly language support functions used by the Bios. The Bios ID and Copyright ASCII text information, the CPU type byte, the Bios date-stamp, and the Bios checksum byte are also in this module .

• *************************************************************************************************** , ; Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

; Module Name: AT Bios top of the'segment assembly module

; Version: 1.02

; Author: FOSCO ; ; Date: 10-18-89

Filename: attop.asm

Language MS MASM 5.1

Functional Description:

This module serves these purposes; 1. It provides the power-on jump at location FFFFO. 2. It starts the Ram refresh. 3. It allocates a stack. 4. It transfers flow to the power-on diagnostic module. 5. It holds assembly language functions

This module is linked as the final module in order for power-on jump.

Version History: 1.01

it to respond to the hardware reset

In the sense program for test bios' at 0000 or EOOO, changed the lines (2 places) from: cmp byte ptr ds:[DI+2],SOh

to the following: c~ byte ~tr ds:[2],SOh

because the inclusion of the DI index was lnI8nted. DI mayor may not be = 0000 1.02 Deleted the test for a Bios at Segment EOOO Added interrupt disable around the insw/outsw for the hard disk

rep in and rep out f'-WICt ions. Added staCK swap option for function call interrupts to minimize use of callers stack space (for DOS 4.xx c~tiblity) Updated various modules (see modules for descriptions)

!*************************************************************************************************** , include atprfx.inc

extrn biospod:near

extrn boot:near extrn comm io:near extrn keybOard io:near extrn keyboardrisr:near extrn disk io:near extrn disk-isr:near extrn printer io:near extrn video io:near extrn mem sTze:near extrn equTpment:near extrn cassette_io:near

pod module is a destination

Page 57: Atbios Kit Nov89

D·2·2 The Top File

extrn extrn extrn extrn extrn

extrn extrn extrn extrn

time of day:near timer int:near print-screen:near watch:flag:word syserror:far

restart2:near restart5:near restart9:near restart10:near

;------- public labels --------------publ ic publ ic publ ic public

publ ic ~lic public

publ ic public ~lic public public public publ ic public public public publ ic

ver id bios id name-id owner_id

reset type byte date:stanp

conm list lpt Tist corriii timeout list lpt timeout fist config table video font colUlii table videoj)arms mode table hdisK table _acrtused

public org EOOO i a correct lTnk may be confirmed by checking this label's location in the file Bios.map

;========== This is Bios Identification =================== segment assume cs:dgroup

org_EOOO label byte

i There may be some programs sensitive to what bit pattern resides in this area. If so, this text ; area may be encoded as needed.

bios cOlJ1)8t field label byte - dO 12 dup(Offh)

db 8ah db '1BMC' db 14 dup(Offh)

i========= This is part of the power up sequence ========= remorg reset

reset proc -_j~ reseta

align 16

ver_id label byte db 'Version 1.02 ',0

bios id label byte name:id label bYte

db 'Annabooks AT BiosKit ',0 owner id label byte

- db 'Copyright (c) FOSCO 1988,1989 - All Rights Reserved ',0

This ASCII field is intended to show the Copyright and even/odd identification when you are using 2 Proms to hold the Bios. If you examlne (~) the indiv;c:iual Proms, you wi II see a clear message, and will be able to discern whether lt is the even or odd prom.

align db db db align db al ign

Programmers Note:

16 'CCooppyyrriigghhtt «cc» 11998888

ff 11998899'

, FFOOSSCCOO -- AATT--BBIIOOSSKK TT ' ,-- AAllll RRiigghhttss RReesseerrvveedd ',00 16 'eovdedn ffiieelldd ',00 16

A-Type BiosKit

Page 58: Atbios Kit Nov89

The Top File D·2·3

We have noticed some reset problems with some CPU boards. If the power-on voltage does not come up cleanly and strongly, the 286 may not get a good reset. It seems that this sometimes happens on loaded systems with marginal power supplies.

The reset. signal to the CPU may not delay long enough before it rises through the threshold voltage to allow the CPU to start. It also may pass through the indeterminate area (can't decide whether it is a logic "0" or a logic "1") too slowly and break into oscillation.

Another problem area we have also seen is that the crystal or oscillator may not get started consistently. If these problems are caused by hardware problems, there is lIttle that the software can do except try to execute some delay loops until thIngs are stable.

If you experience problems in this area, a scope is handy for checking the sequencing of the "power 90od" signal from the power supply, the oscillator cirCUits, and the waveform of the reset SIgnal. After that, an emulator may be required to help to pInpoint the problem.

From a software standpoint, inserting delay loops may be about the only thing you can attempt.

If you encounter, and especially if you solve a problem in this area, sharing your information would be a generous gesture. .

reseta: cli cld mov out

al,80h 70h,al

disable interrupts

disable nmi's

.----------- check for bios' patched in ----------; This patch checking sequence is a powerful development tool. You may link to a "test" Bios at segment 0000. It allows you to modify and test Bios', ; while still retaining an operating Bios at segment FOOO. For more information, see the Chapter ; on liThe Patch.asm file".

If we find a Bios patch (by checking its signature), then we go to it.

check1:

check2:

mov aX,OdOOOh ; check seg dOOO first mov ds,ax cmp word ptr ds:[0],OSb1h jne check2 ; no bios here, continue cmp byte ptr ds:[2],SOh jne check2 ; no bios here, continue mov ax,cs are we checkIng ourselves? cmp ax, OdOOOh je check2 yes, skip it xor cx,cx set 64k count xor al,al clear checksum xor si,si clear index

add inc loop or jne

db dw dw

; do a checksum on the test bios al ,ds: [5 i] si check1 al,al check2

Oeah 00003h OdOOOh

jump to bios at dOOO

First, we need to check to see if this was a power-on start or a restart from virtual mode.

If it is a power-up start, then we will go through this startup and then go to BiosPod.

If it is a restart we will go to a particular restart routine.

in al,64h look at the 8742 status port test al,04h test the power on condition flag jnz CilF jump if not a power on start

put valid restart code in cmos Ofh

mov al~8fh prepare to clear cmos cell Of out 70 ,al select the address delay

al al xor out 71h,al mark as val id power-up code

xor aX,ax mov ds,ax mov word ptr ds:[472h],0 reset warm boot flag

jlJ1) power_en_start

CilCil: ; determine type of restart

Section D: The ASM Pro&rams

Page 59: Atbios Kit Nov89

Q)Q):

Q)Q):

Q)Q):

Q)Q):

D· 2·4 The Top File

mov out delay in or Jnz J~

c~ jne

mov out delay xor out j~

c~ jne

mov out delay xor out j~

c~ jne

mov out delay xor out jlJ1)

c~ jne

mov out delay xor out j~

al/8th 70n,al

al,71h al,al

prepare to read cmos cell Of select the address

get the cmos contents

GlF power_on_start

al,02 GlF

al/8th 70n,al

al,al 71h,al restart2

al,OS GlF

al/8th 70n,al

al al 71~,al restartS

al,09 GlF

al/8fh 70n,al

al al 71tal restart9

al,10 iF

al,8th 70h,al

al al 71~,al restart10

reset the restart code to itO"

memory test return

reset the restart code to "0"

j~ dword with interrupt

reset the restart code to "0"

block move return

reset the restart code to .. a ..

j~ dword without interrupt

; unsupported restart code

i-- save the restart code in case we want to display an invalid code

power_on_start:

;- .......... start the refresh timer .•...........•. -

mov out mov out mov out

al,74h pit-POrt_cmnd,al al, f8 pit-port_' ,al al,o­pit.J)Ort_1,al

; start the ram refresh timer

save the wanm boot flag while we clear the lower 64k

xor ax,ax mov es,ax mov bp,es:[472h]

make sure all repeats are in forward direction

cld

cycle the ram memory to pre-charge the rams

xor ax, ax mov di ,0 mov cx,32768 rep stosw

mov ax -1 mov di :0 mov cx,32768 rep stosw

A-Type BiosKit

store zeroes

store ones

Page 60: Atbios Kit Nov89

xor ax,ax rnov di,O rnov cx,32768 rep stosw

rnov ax -1 rnov di ;0 rnov cx,32768 rep stosw

do a quick ram test on the lower 64k copy the bios to low ram

rnov si,OOOOh rnov di,OOOOh

store zeroes

store ones

rnov cx, 32768 rep movs word ptr es:[di],word ptr cs:[si]

comp bios to low ram

rnov si,OOOOh rnov di,OOOOh rnov cx, 32768

The Top File D· 2·5

repz c. rnov sp,cx

word ptr es: [di],word ptr es:[si] ; save cx - cx = 0 = ok, else ram compare error

now do a ram clear on 64k - then proceed

xor ax,ax mov cx, 32768 xor di ,di rep stosw

mov es:[472h],bp ; restore the warm boot flag in its place mov es:[415h],sp; save the low ram test indicator

;-- now we can use 'e' because we can have a stack IIII

;--- set up the local stack - now we can use real calls

xor ax,ax cli mov ss,ax mov sp,ax ; top of the sys_seg

;/* from here on we can use 'e' because we have a stack */

;- . - - - - - - - - - - - - -push cs P.OP ds ; 'e' wants ds = cs

~ biospod

reset

;=-=-=-:-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-; The NMI routine may be expanded as desired. It resets the parity toggles and returns to ; the interrupted program.

romorg label push xor out in or out and out P.OP Het

nmi 6yte ax al al Oa6h 1al al,61h al,30h 61h al al/bcfh 61n,al ax

disable nmi interrupts reset the nmi toggles

This is where the hard disk table can reside. There is room for 60-70 entries as needed. You may modify these entries to support the disk types you desire.

hd tbl struc struc hdTive-cyls dw ? hdrive-heads db ?

- dw 0 hdrive-precomp dw ?

db 0 hdrive contrl db ?

- db 0 db 0

Section D: The ASM ProlUams

Page 61: Atbios Kit Nov89

D·2·6 The Top File

db ° hdrive lndng dw ? hdrive-sectors db ?

- db ° hd_tbl_struc ends

drive type macro a1,a2,83 a4 a5,86,a7 - hd tbl struc <a~,8j,0,a4,0,a5,0,0,0,86,a7,0> era.. -

al ign 16

hdisk_table label byte

drive type 1, 306, 4,128,0, 305,17 drive-type 2, 615, 4,300,0, 615,17 drive-type 3, 615, 6,300,0, 615,17 drive-type 4, 940, 8,512,0, 940,17 drive-type 5, 940, 6,512,0, 940,17 drive-type 6, 615, 4, -1,0, 615,17 drive-type 7, 462, 8,256,0, 511,17 dr!ve:type 8, 733, 5, -1,0, 733,17 drlve type 9L 900,15, -1,8, 901,17 dr!ve:type 1u,820, 3, -1,0, 820,17 dr!ve_type 11,855, 5, -1,0, 855,17 drlve type 12,855, 7, -1,0, 855,17 drive-type 13,306,8,128,0,319,17 drive-type 14,733, 7, -1,0, 733,17 drive-type 15, 0, 0, 0,0, 0, ° drive-type 16,612, 4, 0,0, 663,17 drive-type 17,977, 5,300,0, 977,17 drive-type 18,977, 7, -1,0, 977,17 drive-type 19,102~,7,512,0,1023,17 drive-type 20,733, 5,300,0, 732,17 drive-type 21,733, 7,300,0, 733,17 drive-type 22,733, 5,300,0, 733,17 drive-type 23,306, 4, 0,0, 336,17 dr!ve:type 24,612, 4,305,0, 663,17 drlve type 25,306, 4, -1,0, 340,17 drive-type 26,612, 4, -1,0, 670,17 drive-type 27,698, 7,300,0, 732,17 drive-type 28,976, 5,488,0, 977,17 drive-type 29,306, 4, 0,0, 340,17 drive-type 30,611, 4,306,0, 663,17 dr!ve:type 31,732 7,300,0, 732,17 dr!ve_type 32,10~,5, -1,0,1023,17 drlve_type 33,306, 2, -1,0, 305,17

The SysVue "TYPES" Conmand looks for this following entry to sense the end of the hard drive parameter table.

drive_type -1,-1,-1,-1,-1,-1,-1 ; end of table

; this function is used to reset the parity logic

reset~rity enables proc uses ax in- al,61h ; reset the nmi toggles or aL l 30h out 61n aL and al l 6cfh out 61n,aL ret

reset~rity_enabLes endp

romorg j~

boot Soot

; This is the table referenced by the Int 15, Function CO ; get system configuration parameters caLL.

config tabLe LabeL - dw

db db db db db

~te Ofch 01h

° 70h 4 dup(O);

Length of tabLe in bytes model byte sub modeL byte bios leveL

; DNA 3,cascede 8259, rtc clock spares

romorg comm tabLe comn table label byte -'- dw 1047,768,384,192,96,48,24,12

romorg j~

romorg

comm io comm_To

_keyboard_fo

A-Type BiosKit

Page 62: Atbios Kit Nov89

jmp keyboard_io

romorg keyboard isr jmp Keyboard_Tsr

romorg disk io int_header- - disk_io

romorg jmp

disk isr aisk_Tsr

The Top File D· 2· 7

disk uses own stack

This is the default disk parameter table. The Biosdisk.c Module actually uses its own set of enhanced parameters to support the additional drive types available.

romorg _disk-P8nms fdisk table label byte

- db Odfh,2,2Sh,2,Ofh,1bh,Offh,54h,Of6h,Ofh,8

romorg jmp

-p~inter_io prlnter_l0

video uses own stack

romorg video~rms label

db db db db

video~rms byte

38h,40,2dh,10,1fh,6,19h,1ch,2,7,6,7,0,0,0,0 71h,80,Sah,10,1fh,6,19h,1ch,2,7,6,7,0,0,0,0 38h,40,2dh,10,7fh,6,64h,70h,2,14617,0~0606° 61h,80,S2h,1S,19h,6,19h,19h,2,1~,11,1~, , ,0,0

The length tabel is not used by biosert.c we include it in case some user thinks it exists.

length table label byte - dw 2048,4096,16384,16384

coll.l1n table label byte - db 40,40,80,80,40,40,80,80

mode table label byte - db 2ch,28h,2dh,29h,2ah,2eh,1eh,29h

;==== this large area is used for the asm routines ====== ; This is used by the hard disk driver for data-in xfers

proc mov mov mov mov pushf cl i cld rep popf ret endp

uses es di cx dx,tseg:word,toff:word,port:word,count:word dx,port es,tseg di,toff cx,count

save flags while disabling

insw

; This is used by the hard disk driver for data-out xfers

rep_out proc mov mov mov mov pushf cli cld rep popf ret

uses ds S1 ex dx,tseg:word,toff:word,port:word,count:word dx,port ds,tseg si,toff cx,count

save flags while disabling

outsw

rep_out endp

; --------- this is the ram test called by 'e' -----­; This test is used in real-mode only.

;unsigned int ram_test(unsigned base,unsigned length)

returns ok = 1 returns error = 0

Section D: The ASM Pro&rams

Page 63: Atbios Kit Nov89

D-2-8 The Top File

ram_test proc uses mov mov push

~ mov xor rep

mov xor mov repe

jcxz mov jo., short

ram test10: - mov

ram test20: - xor

mov xor rep mov ret

ram_test endp

; write and read bios pattern into 64k cx ds si es di,test_base:word,test_length:word cx,test lengtn es, testE>ase cs -ds

si ,OOOOh di ,di movsw

si,OOOOh di ,di cx,test_length cn.,sw

ram test10 si ,error ram_test20

si ,ok

di ,di cx,test length ax,ax -stosw ax,si

set di = 0

set di = 0

set di = 0

clear the block return the condition in ax

; This routine is used to re-locate the Bios-system-segment from the top of the 1st 64k segment ; (at power-on time) to the top of the System Ram at run-time.

move system segment proc uses ax cx dx ds si es di c to seg:word,seg size:word - cTi ; disable lnterrupts because

( of moving the stack moves, to_seg ; destinatlon segment

mov cx, seg size ; ca l c the base segment address shr cx,4-mov aX,1000h sub ax,cx

mov ds,ax mov cx,seg size ; move I'YVY1 bytes xor si,si -xor di,di • set di = 0 rep movs byte ptr es:[di],byte ptr ds:[si]

mov mov and mov

mov mov xor mov xor rep

mov mov mov sti ret

ax,es dx,ax aX,OfOOOh ss,ax

ax,ds es,ax di ,di cx,seg_size ax,ax stosb

ax,40h ds,ax ds: [Oeh] , dx

move_system_segment endp

; reset the stack segment ; save dest segment for 40:e

stack is top ·of 641c segment

now clear the old segment

set di = 0

clear the old block

set new sys seg ptr ; re-enable interrupts

;------- this is the rom scan checksum called by 'e' ----­; unsigned int checlcsum(unsigned segment,unsigned length)

checksum proc uses bx cx ds,segptr:word,length arg:word mov ds,segptr ; get Sase address mov cx,length_arg ; get count xor ax,ax xor bx,bx

QlGl: add al ,ds: [bx] inc bx point to next byte loop Q8 ret

checksum endp

A-Type BiosKit

Page 64: Atbios Kit Nov89

;-- this is the far call routine called by 'C' rom scan --­

i void far _call (l.I'\signed int segment,lW'Isigned int address)

far call proc segptr:word,addr:word LOCXL t~ segment:word,t~ offset:word -...... j5ushf _ ...... -

push a push ds push es push segptr get segment pop teRJ) segment push addr- get offset pop temp offset call dwora ptr [temp_offset] pop es pop ds

= ret far_call endp

;-- this jump to boot passes the drive' in dl -­

i boot_jump(seg,off,drive);

boot jump proc segptr:word, addr:word,drive: word locaT temp_segment:word,temp_offset:word

push

=h pop mov jfl1)

boot_jump endp

segptr get segment teRJ) segment addr - i get offset temp offset dx,drive dwOrd ptr [temp_offset]

i------------ beep routine ----------------i void beep(void);

beep proc uses ax bx cx dx mov bx,128 mov dx,pio-POrt b in al,dx -mov ah,al

and al,Ofch out dx,al mov cx,64 loop alB or al,2 out dx,al mov cx,64

beep 1 0:

GlGl:

@Gl:

128 cycles last about 1/12 sec.

save the 8255 port byte

turn the beeper off

make the duty cycle 50X

i turn the beeper on

leave it on = to the off time

The Top File D-2-9

loop Q8 dec bx jnz ~10 mov al,ah out dx,al

; COU"lt the major cycles down

get the original port byte restore the 8255 to previous

ret beep encIp

i----------·_·---------------------------·_·--------seg_40_constant dw 40h

i void setds_system_segment(void)i

setds system segment proc - mov dS,cs:seg 40 constant

mov ds, ds: [Oen] -ret

setds_system_segment endp

i-- this is used to set the DS to a specified value -­i void setds(unsigned ptr);

setds proc seg-ptr:word push seg-ptr pop ds ret

setds endp

i-- get the current stack segment value -­i unsigned get_ss(void)i

Section D: The ASM Pro&rams

Page 65: Atbios Kit Nov89

D·2·10 The Top File

proc mov ret encfp

ax,ss

;-- test the specified watch flag bits ; return true if set, false if not

; unsigned watch(unsigned)i watch proc uses ds,bits:word

call setds system segment mov ax, bits -test ds:watch flag,ax mov ax, false-jz iF mov ax, true

iilGI: ret watch encfp

;-- this can be used to force a break while debugging --

trap proc ; this can be used for hard breakpointing int 18h ; goes to SysYue ret

trap endp

; check to see if any key p'r~sent at console device --i returns true if a key waltlng ,

kbhit proc mov int mov jz mov

; returns true if any key hit

ret

aX,0100h 16h ax, false iF ax, true

kbhi t encfp

;=========== Console In Routine ===============

ci

ci

char ci (void); proc mov int ret endp

;*========- block checksum routine ==============*/ ; unsigned checksum bios block(void)

extrn bios_start:near

checksum bios block proc uses bx ds,seg addr:word,off addr:word - pusn cs - -pop ds ; set ds = cs to el iminate need for CS: overide xor ax,ax ; clear accumulator mov bx,offset bios start

iilGI: add al,[bx] -inc bx exit at end of segment jnz CilB ret

checksum_bios_block endp

i*=========== Console OUt Routine =============*/ ; console out routine ; co(char);

co proc uses ax bx1char:byte mov ah,Oen mov al,char mov bx,O int 10h ret

co endp

;--- calc the hdisk size - this uses some long unsigneds

unsigned calc_hd!sk_si~e(cyls,heads,sectors); returns a va l ue 1 n ax 1 n megabytes By doing this in ASH, the C Lib ft.n:tion is not needed.

proc uses dx'si,cyls:word,heads:word,sectors:word

A· Type BiosKit

Page 66: Atbios Kit Nov89

xor mov mov nul mov nul mov div ret

calcJ,disk_size

dx,dx ax,cyls si ,heads si si,sec:tors si si,2000 si

endp

i---.-.-----------------------------------------; this is used by the timer interrupt to chain to a user

timer chain - push

P.OP 1nt ret

timer_chain

proc uses ds 40h ds 1ch

endp

; this chains the hard -> floppy disk without extra ; stack usage

fdisk chain - mov

pop pop pope 1nt retf 2

fdisk_chain

proc sp,bp es ds

40h

endp

discard the callers return address

The Top File D·2·11

~-~;;~~~-;h;-hi;h-~~d;~-~~d-~f-;~-~;i;~ long integer as an unsigned in ax ; unsigned hi_regs(unsigned long)

~i_regs proc low arg:word,high arg:word mov aX,nigh_arg -ret

hi_regs endp

;--------long multiply for setting tod clock

; unsigned long lnul(unsigned long,unsigned)

lnul proc mov mov mov nul ret enctp

uses bx,ax_arg:word,dx_arg:word,bx_arg:word dx,dx_arg

convert binary - mov

mov shr and aad xor ret

convert_binary

ax,ax arg bX,bx-arg bx -

proc ax,arg ah,al ah,4 al,Ofh

ah,ah

endp

arg:word

; void bin2dec:(value,return array[S]); ; the output array is in os:

ax di si dx,value:word,array-ptr:word di,array..p.tr

bin2dec proc uses mov mov mov mov mov mov mov

byte ptr as: [di+O],' , byte ptr ds:[di+1],' , byte ptr ds:[di+2],' byte ptr ds:[di+3],' byte ptr ds:[di+4),'0' byte ptr ds:[di+S),O string tenminator char

add di ,4 mov si,10 mov ax, value

iilQ): mov ~,O div Sl add dl,'O~ mov ds: [d1] ,dl dec di or aX,ax

Section D: The ASM Pro&rams

Page 67: Atbios Kit Nov89

D·2·12 The Top File

jnz ret

bin2dec endp

i-----------------------.-.-------------------; unsigned dec2bin(unsigned decval): ; the arg is max of 9999 decimal - ok for up to 8192k of extended memory ; the binary value is returned in ax

dec2bin proc uses dx di cx,decval:word mov dx,O ; clear accumulator

@Q):

mov ax,O mov di,10 mov cx,4 I1IJl di rol decval,4 mov bx, decva l and bx,OOOfh add ax,bx loop iil8 ret

dec2bin endp

load I1IJltiplier i load loop count ; I1IJl by ten

get next digit load to bx save only wanted digit add to accumulated nuJi)er

; do for all four digits

;------ move string routine for alpha mode crt scrolling

; void move_row(unsigned segment,unsigned from_offset,unsigned to_offset, unsigned count)

move_row proc uses mov mov mov mov mov cld jcxz rep

@Q): ret move_row endp

cx si di es ds,segptr:word,from:word,to:word,count ds,segptr ; segment es,segptr si,from di, to cx,count

GilF movsw

from to count

;------ clear row routine for alpha mode crt scrolling

i void clear_row(unsigned segment, unsigned address,unsigned count, unsigned fill)

clear_row proc uses ax cx di es,segptr:word,addr:word,count:word,filler:word !nOv es, segpt r ; segment . !nOv d i , addr ; address !nOv cx , count ; CO\.l\t mov ax,filler ; fill cld jcxz QF rep stosw

QGl: ret clear_rowendp

;-- move string routine for graphics mode crt scrolling

move graph i cs row proc uses cx dx s i - mov- dx,O

move_graphics_r0w5: mov

GlG1:

@Q):

mov mov mov mov cld add add jcxz rep mov mov add add mov cld add add jcxz rep add

i~

ds,segptr es,segptr si,from di,to cx,count

si,dx di ,dx QF

movsw si,[~] di, [bI)+8] si,2000h di ,2000h cx, [bp+10]

si,dx di ,dx QF

A-Type BiosKit

from_offset, to_offset, count)

di es ds,segptr:word, from:wordf. to:word,count:word : use dX to move Tour lines each

segment

from to count

from to add for odd row add for odd row count

Page 68: Atbios Kit Nov89

ret move_graphics_row endp

;------ clear row routine for alpha mode crt scrolling

; void clear_graphics_row(segment, address, count, fill)

The Top File D-2-13

clear graphics row proc uses ax ex dx di - mov - dx,O

es,segptr:word,addr:word,count:word,filler:word ; use dx to clear four lines each

clear_graphics_rowS: mov es,segptr

Q)Q):

mov di,addr mov cx,count mov ax,filler cld add jcxz

di ,dx CilF

segment address count fill

address rep mov add mov mov add cld

stosw di, [bp+61 di ,2000h cx, [~81 ax, [bp+101 di ,dx

add for odd row cOU"St fill

jcxz iF rep stosw add dx,80 c"1l dx, 320 jb clear_graphics_rowS ret

clear_graphics_row endp

; ---- low level routines for 'e' ---------.======================================================== ; this version assumes the regs are in the system segment. note that it also requires a ; slightly different regs structure than int86 or int86x because it always passes es and ds.

axoff equ 4 cxoff equ 6 dxoff equ 8 sioff equ 10 dioff equ 12 bpoff equ 14 bxoff equ 16 dsoff 18 esoff equequ 20 floff equ 22 Jmp_off equ 24 J mp seg equ 26 coCe_string_location equ 28

; void sys_int(char number, reg_block);

code string proc far - lds bX,cs:[bx+bxoff]

int 0 number offset = $-code string-1

- ret -code string length = $-code string code:string- endp-

sys_int proc uses si di ax bx cx dx es ds, number:word,regs_block:word

mov bx,regs_block

move the code string image ; get cOU"St of bytes to move

mov cx,code string length ; point-to org-of code string

mov si offset code string -; ~ild ptr to-destination

mov di ,bx add di,offset code string location

; set segment Tor destination push ds pop es

; now do the copy rep movs byte ptr es:[dil, byte ptr cs:[sil

; load the correct interrupt number mov ax, number mov [bx+code_string_location+number_offsetl,al

Section D: The ASM Pro&rams

Page 69: Atbios Kit Nov89

D·2·14 The Top File

mov add mov

; load the j~ vector word ptr [bx+jmp off],code string location [bx+Jmp off],bx - --

mov mov mov mov mov mov

[bx+ JII1(seg] ,ds

; load the registers ax, [bx+axoff] cx, [bx+cxof f] dx, [bx+dxoff] si,[bx+sioff] di, [bx+dioff] es, [bx+esoff]

push mov push push call

~save the real bp for the implied LEAVE instruction

bP, [bx+bpoff] ds bx dword ptr ds:[bx+jmp_off]

now we have to swap out ds:bx with the stack-saved ones

push push push mov lds

bx save returned ds:bx ds bp save bp - will be used as ptr bP,sp bx, [bp+6] re-load myblock ds:bx

pop pop pop

ds:[bx+bpoff] ; restore returned bp ds: [bx+dsoff] ds: [bx+bxoffl

pop pop :; ; discard old ds:bx slots

i without affecting flags

pop

mov mov mov mov mov mov pushf pop

ret sys_int endp

~ bp is now pre-interrupt value

; store the registers

[bx+esoff] , es [bx+axoff],ax [bx+cxoff],cx [bx+dxoff],dx [bx+s i off] , s i [bx+di off] ,di ; save flags [bx+floff]

; SysErr routine ~ts an error code in ax, then goes to sysvue -- This is an expansion feature ; you may wish to implement.

sys_err proc mov pushf call ret

sys_err endp

uses ax,error_code:word ax, error_code

syserror

;---------------------------------------------------get vector returns the selected vector in OX:AX. This routine is done in assenClr language because a 'e' routine would need the library eng shift function to build the seg:off into DX:AX.

unsigned long get_vector(char number);

get vector proc uses bx es,number:word - xor bx,bx

mov es,bx mov bx,number xor bh,bh shl bx,1 shl bx,1 cl i mov dX,es:[bx]+2 mov aX,es:[bx] sti ret

get_vector endp

getds proc

A· Type BiosKit

int #I

rul by 4

Page 70: Atbios Kit Nov89

getds

mov ret endp

The Top File D· 2·15

ax,ds

return the bios code segment value in AX. This function is coded this way so the Bios may be operated at segments other than FOOO.

unsigned bios_cs(void);

bios_cs proc mov ret

bios_cs endp

ax,cs

Disable interrupts

void disable(void);

disable proc cU ret

disable endp

Enable interrupts

void enable(void);

enable proc sti ret

enable endp

void delay(unsigned res,unsigned count);

res == 0 - delay in useconcfs res 1= 0 - use as milliseconds resolution count = count

delay_call proc uses ax cx dx ds,res:word,count:word cmp res 0 jnz mil[i_delay

micro delay: - mov

iiIi:

xor mov div add mov

in and cmp je mov loop ret

milli delay: - mov

milli major: - push

mov iiIi: call

loop

~ ret

delay_call

read timer ccx.nt - xor

out Jmp

iiIi: Jmp iiIi: ~mp iiIi: 1n

mov Jmp

iiIi: ~mp iiIi: Jmp GlQl: 1n

xchg

ax, count dX,dx cx,15 cx ax,2 cx,ax

al,61h al,10h ah,al Q8 ah,al Q)8

CX,COU'lt

cx

micro seconds delay this has 15 usec resolution each toggle of the refresh bit is 15 usecs now cx = count/15 make sure we have at least 15-30 usecs min. cx will be a loop count

get port b refresh bit save only the bit we want

now use current state wait n times

th1'S' ; ~es argument = # of millis resolution

1S major loop

cx res delay a milli Q)8 --

this is minor loop

wait for resolution counts cx mill i_major

endp

proc al,al 43h,al GlF QF QF al,40h ah,el CilF GlF CilF al,40h ah,al

repeat major loop for total counts

each COU'lt = .8 usecs latch timer 0 count into storage register

: delay for 8253 response

delay for 8253 response

Section D: The ASM Proauams

Page 71: Atbios Kit Nov89

D·2·16 The Top File

ret read_timer_count endp

; return count in ax

; Note: Remember that the counters in the 8253/8254 are down counters, ; so that we have to subtract the desi red count from the current count.

delay a mi II i - - call

call mov sub

j~ mov not

@GI: call cq) jae ret

delay_a_milli

proc uses cx read timer count reaa-timer-count cx,ax -cx,1250 cx,ax GlF cx,ax cx read timer count ax,cx -Gl8

endp

delay 1 milli second do a double read

since count rate is 1.19 Mhz, about 1250 timer counts = 1 millisecond

delay count> current count, no rollover use delay based from zero if rollover

delay until current count >= calced count

get offset - pop

push ret

get_offset

proc ax ax

this function is used to retrun the callers offset it pops the callers address into ax puts it back so it can be used for the ret instruct i on

endp

;--- These are additional peek and poke functions

; unsigned peek40(unsigned offset);

peek40 proc uses bx eS,offptr:word mov bx,40h mov es,bx mov bx,offptr mov aX,es:[bx] ret

peek40 endp

; char peekb40(unsigned offset);

peekb40 proc uses bx esfoffptr:word mov bX,ltOh mov es,bx mov bx,offptr mov al,es:[bx] xor ah,ah ret

peekb40 endp

; char peekbcs(unsigned offset);

peekbcs proc uses bx/off~tr:word mov Dx,offptr mov al,cs:[bx] xor ah,ah ret

peekbcs endp

; unsigned peekcs(unsigned offset);

peekcs proc uses bx,offptr:word mov bx,offptr mov ax,cs:[bx] ret

peekcs endp

peeks in segment 40h

; void pokeb40(unsigned offset, char value);

pokeb40 proc uses ax bx eS,offptr:word,value:word mov bX,40h mov es,bx moV bx,offptr mov ax, value mov es:[bx],al ret

pokeb40 endp

; void poke40(unsigned offset, unsigned value);

poke40 proc uses ax bx esloffptr:word,value:word mov bx,40n mov es,bx mov bX,offptr mov ax, value

A-Type BiosKit

Page 72: Atbios Kit Nov89

mov ret

poke40 endp

es:[bx],ax

; void andb40(unsigned offset, char value);

andb40 proc uses mov mov mov mov and ret

ax bxes,offptr:word,value:word bX,40h es,bx bx,offptr ax, value es:[bx],al

andb40 endp

; void and40(unsigned offset, unsigned value);

and40

and40

proc mov mov mov mov and ret endp

uses ax bx es,offptr:word,value;word bX,40h es,bx bx,offptr ax, value es:[bx],ax

; void orb40(unsigned offset, char value);

orb40

orb40

proc mov mov mov mov or ret endp

uses ax bx es,offptr:word,value:word bX,40h es,bx bx,offptr ax, value es:[bx],al

; void xorb40(unsigned offset, char value);

xorb40 proc uses ax bx es,offptr:word,value:word mov bx,40n mov es,bx mov bx,offptr mov ax, value xor es:[bx],al ret

xorb40 endp

;--- These are the standard peeks, pokes, ins, and outs

; unsigned peek(unsigned segment, unsigned offset)

peek proc uses bx es,segptr:word,offptr:word mov es,segptr mov bX,offptr mov aX,es:[bx] ret

peek endp

; void poke(segment, offset, value);

poke proc uses ax bx es,segptr:word,offptr:word,value:word mov es,segptr mov bx,offptr mov ax, value mov es:[bx],ax ret

poke endp

; char peekb(unsigned segment,unsigned offset);

peekb proc uses bx es,segptr:word,offptr:word mov es,segptr mov bx,offptr mov al ,es: [bx] xor ah,ah ret

peekb endp

; void pokeb(unsigned segment, unsigned offset, char value);

pokeb proc uses ax bx es,segptr:word,offptr:word,value:word mov es, segpt r mov bx,offptr mov ax, value mov es:[bx],al

The Top File D·2·17

Section D: The ASM Pro&rams

Page 73: Atbios Kit Nov89

D·2·18 The Top File

ret pokeb endp

; unsigned inport(unsigned port);

inport proc uses dx,port:word mov dx,port in ax,dx ret

inport endp

; void outport(unsigned port, unsigned value);

outport proc uses dx ax,port:word,value:word mov dx,port mov ax, value out dx,ax ret

outport endp

; char inportb(unsigned port);

inportb proc uses dx,port:word mov dx,port in al,dx xor ah,ah ret

inportb endp

; void outportb(unsigned port, char value);

outportb proc uses ax dx,port:word,value:word mov dx,port mov ax, value out dx,al ret

outportb endp

cstods

cstods

proc push pop ret endp

SdLIIIIIY i sr proc - send eoi

iret­Sdllll11Y _ i sr endp

Siret proc lret

Siret endp

; set ds = to cs cs ds

Stack swapper for interrupt routines - (see int_header macro) --­

Typically code written in C may use more stack space then tweaked assembly language code. Intennediate varlables created br using "for" and "while" loops mar be assigned to the stack. A so the use of the "Interrupt" dec aration for Interrupt service routines causes all the registers to be pushed on the stack. Normally this does not cause problems, beCause user or appl ication declared stacks are usually large encxJ¥h to be safe. However, there are some instances where a program 1 gnores the user declared stack (PC-DOS 3.xx VDISK) or system software (PC/MS 4.xx IO.SYS) sets a very tight stack, which will run with most (but not all) BIOS' written in assembr.' (The more curious among us may have already discovered the rase "may run on some PC and XT machines", in the DOS 4.xx manuals •

Starting with DOS 3.xx, the IIstacks=n,yt' conmand has been included for CONFIG.SYS use to set up a stack ~l for swapping stacks on the hardware (caused through the 8259 interrupt controller(s» interrupts. This alleviated some stack overflow problems encountered when running true IBM PC-DOS on true IBM hardware. So it wasn't an error committed either by the 3rd party clone or BIOS creators. It simply was a result of the programmlng style used in writing the DOS. Microsoft is currently the most prominent "bender" of the rules (previously IBM possessed the leverage) and we (as well as Intel) are forced to conform. The code below implements a stack swapping mechanism for use by Function Call Interrupts by creating a stack in the system segment ram area for the des ired funct i on ca Lt. The swap occurs before the Interrupt Service Routine is called, allowing all the user registers to be pushed onto the new staCK. This limits user stack usage and seems to solve the problems.

A-Type BiosKit

Page 74: Atbios Kit Nov89

The Top File D·2·19

Example of usage:

A non-swapped interrupt -Vector ---------> cdecl far interrupt sample(interrupt_registers)

<-----------. A swapped interrupt -Vector ---------> push dest

jmp interrupt_shell

• (swap to system stack)

· ----> cdecl far interrupt sample(interrupt_registers)

. . <----------. • (restore to callers stack)

<-----------.

The code below is entered with destination address on the stack push dest jmp interrupt_shell

extrn bx save:word,ds save:word,dest save:word extrn ss:save:word,sp:save:word,length mark:word extrn current_open: word, end_block:wordr

size_requested equ 256 default standard size

interrupt_shell proc

push push mov mov mov pop pop pop mov pushf add

j~ popf

rJSh ds

ret QlQ:

mov add popf

mov mov mov mov mov mov

pushf push push rJ:h

ret

continue: push push mov mov mov pop pop pushf sub popf

ds bx

entered with interrupts disabled as a result of the previous Int xx opcode.

bx,O ds,bx ds,ds: [040ehl bx save ds-save deit save bx, cur rent _open

bx,size requested bx,end Slock ilF -

dest save

get system segment sys:xx

; sys:xx+2 sys:xx+4

; save callers flag state check for space available

j~ if enough space use current stack, jump to isr service

bx,dWord ptr ds:[bx_savel restore ds:bx·to callers values

bx,current oper:\ current_open,size_requested

get base address of block

• mark the block "in use" ds:[bx+length markl,size requested ds:[bx+ss savil,ss ; save the caller stack pointers ds:[bx+sp:savel,sp in the allocated stack block sp,ds ss,sp sp,dS: [current_open] set sp at top of new block

cs offset continue ; set up ~ony interrupt call dest save ; set destination address bx,dWord ptr ds:[bx_savel ; restore ds:bx to callers values

go to dest with phnoy call

bx ds bx,O ds,bx ds,ds: [40ehl ds save bx:save

ds:[current_openl,size_requested

Section D: The ASM ProlD"ams

Page 75: Atbios Kit Nov89

D·2·20 The Top File

mov bx,current open mov ss,ds:[bx+ss save] ; get the callers stack description mov sp,ds:[bx+sp-save] mov ds:[bx+length mark],O mark the block as free lds bx,dword ptr as: [bx_save]

retf interrupt_shell

2 endp

return with cuurent flags

;============== end of the asm routines =================== romorg jnp

romorg jnp

mem size iiie"Lsize

equipment iquipment

romorg cassette io int_header- -cassette_io

romorg vi deo font

cassette uses own stack

video font label byte -; - These are the bit-mapped characters for the graphics mode. They must be here ; because some user software uses these for generating characters in graphics mode.

db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db db

OOOh,OOOh,OOOh,OOOh,OOOh,OOOh,OOOh,OOOh 07eh,081h,Oash,081h,Obdh,099h,081h,07eh 07eh,Offh,Odbh,Offh,Oc3h,Oe7h,Offh,07eh 06ch,Ofeh,Ofeh,Ofeh,07ch,038h,010h,OOOh 010h,038h,07ch,Ofeh,07ch,038h,010h,OOOh 038h,07ch,03Bh,Ofeh,Ofeh,07ch,038h,07ch 010h,010h,03Bh,07ch,Ofeh,07ch,038h,07ch 000h,000h,01Bh,03ch,03ch,01Bh,OOOh,000h Offh,Offh,Oe7h,Oc3h,0c3h,Oe7h,Offh,Offh 000h,03ch,066h,042h,042h,066h,03ch,000h Offh,Oc3h,099h,Obdh,Obdh,099h,Oc3h,Offh OOfh,007h,00fh,07dh,Occh,Occh,Occh,078h 03ch,066h 066h 066h 03ch 01Bh 07eh 01Bh 03fh,033h:03fh:030h:030h:070h:OfOh:OeOh 07fh,063h,07fh,063h,06eh,067h,0e6h,OcOh 099h,05ah,03ch,Oe7h,Oe7h,03ch,05ah,099h 080h,OeOh,OfBh,Ofeh,OfBh,OeOh,08Oh,OOOh 002h,00eh,03eh,Ofeh,03eh,OOeh,002h,OOOh 018h,03ch,07eh,018h,018h,07eh,03ch,01Bh 066h,066h,066h,066h,066h,000h,066h,OOOh 07fh,Odbh,Odbh,07bh,01bh,01bh,01bh,OOOh 03eh,063h,038h,06ch,06ch,038h,Occh,078h 000h,000h,000h,000h,07eh,07eh,07eh,000h 018h,03ch,07eh,018h,07eh,03ch,01Bh,Offh 01Bh,03ch,07eh,01Bh,01Bh,01Bh,01Bh,000h 01Bh,01Bh,01Bh,01Bh,07eh,03ch,01Bh,000h 000h,01Bh,00ch,Ofeh,00ch,01Bh,000h,OOOh 000h,030h,06Oh,Ofeh,06Oh,030h,000h,000h OOOh,OOOh,OcOh,OcOh,OcOh,Ofeh,OOOh,OOOh 000h,024h,066h,Offh,066h,024h,000h,000h 000h,01Bh,03ch,07eh,Offh,Offh,000h,OOOh OOOh,Offh Offh 07eh 03ch 01Bh OOOh OOOh OOOh,OOOh:OOOh:OOOh:OOOh:OOOh:OOOh:OOOh 030h,078h,078h,030h,030h,OOOh,030h,OOOh 06ch,06ch,06ch,OOOh,OOOh,OOOh,OOOh,OOOh 06ch,06ch,Ofeh,06ch,Ofeh,06ch,06ch,000h 030h,07ch,OcOh,078h,00ch,OfBh,030h,000h 000h,Oc6h,Occh,01Bh,030h,066h,Oc6h,000h 038h,06ch,038h,076h,Odch,Occh,076h,000h O6Oh,06Oh,OcOh,OOOh,OOOh,OOOh,OOOh,OOOh 018h,030h,06Oh,06Oh,06Oh,030h,01Bh,000h O6Oh,030h,01Bh,01Bh,018h,030h,06Oh,000h 000h,066h,03ch,Offh,03ch,066h,000h,000h OOOh, 030h, 030h,Ofch, 030h ,030h ,000h,000h 000h,000h,00Oh,000h,000h,030h,030h,060h OOOh,OOOh,OOOh,Ofch,OOOh,OOOh,OOOh,OOOh 000h,000h,OOOh,000h,OOOh,030h,030h,000h 006h,00ch,01Bh, 030h, O6Oh , OcOh ,000h,000h 07ch,Oc6h,Oceh,0deh,Of6h,0e6h,07ch,000h 030h,070h,030h,030h,030h,030h,Ofch,000h 078h,Occh,00ch,038h,06Oh,Occh,Ofch,000h 07Bh,Occh,00ch,038h,00ch,Occh,078h,000h 01ch,03ch,06ch,Occh,Ofeh,00ch,01eh,000h Ofch,OcOh,OfBh,OOch,OOch,Occh,078h,OOOh 03Bh,06Oh,OcOh,OfBh,Occh,Occh,078h,OOOh Ofch,Occh,00ch,01Bh,030h,030h,030h,000h 078h,Occh,Occh,07Bh,Occh,Occh,078h,OOOh 078h,Occh,Occh,07ch,00ch,01Bh,070h,OOOh 000h,030h,03Oh,000h,000h,030h,030h,000h 000h,030h,030h,000h,000h,030h,030h,06Oh 01Bh,030h,06Oh,OcOh,06Oh,030h,01Bh,000h

A-Type BiosKit

00 - nul 01 - "A 02 - "B 03 - "C 04 - "0 05 - "E 06 - "F 07 - "G 08 - "H 09-- "I OA - "J 08 - "I( OC - "L 00 - "M OE - "N OF - "0 10 _ "p 11 - "Q 12 - "R 13 - "s 14 - "T 1S - "U 16 - "V 17 - "y 18 - "X 19 - "y 1A - "Z 18 - "r 1C - "\ 1D - "] 1E - "6 1F - "-20 - spc 21 - I 22 - " 23 - 1# 24 - S 25 - X 26 - & 27 - I

28 - ( 29 - ) 2A - * 28 - + 2C - , 2D - -2E - • 2F - I 30 - 0 31 - 1 32 - 2 33 - 3 34 - 4 35 - 5 36 - 6 37 - 7 38 - 8 39 - 9 3A -38 - ; 3C - <

Page 76: Atbios Kit Nov89

The Top File D·2·21

db OOOh,OOOh,Ofch,OOOh,OOOh,Ofch,OOOh,OOOh 30- = db 060h,030h,01Sh,OOch,01Sh,030h,06Oh,OOOh 3E - > db 078h,Occh,OOch,01Sh,030h,OOOh,030h,OOOh 3F - ? db 07ch,Oc6h,0deh,Odeh,Odeh,OcOh,07Sh,OOOh 40 - Q db 030h,07Sh,Occh,Occh,Ofch,Occh,Occh,000h 41 - A db Ofch,066h,066h,07ch,066h,066h,Ofch,OOOh 42 - B db 03ch,066h,OcOh,OcOh,OcOh,066h,03ch,OOOh 43 - C db OfSh,06ch,066h,066h,066h,06ch,OfSh,OOOh 44 - 0 db Ofeh,062h,068h,07Sh,068h,062h,Ofeh,000h 45 - E db Ofeh,062h,068h,07Sh,068h,06Oh,OfOh,OOOh 46 - F db 03ch,066h,OcOh,OcOh,Oceh,066h,03eh,OOOh 47 - G db Occh,Occh,Occh,Ofch,Occh,Occh,Occh,OOOh 48 - H db 078h,030h,030h,030h,030h,030h,078h,OOOh 49 - I db 01eh,OOch,OOch,OOch,Occh,Occh,078h,OOOh 4A - J db Oe6h,066h,06ch,078h,06ch,066h,Oe6h,OOOh 48 - K db OfOh,06Oh,06Oh,06Oh,062h,066h,Ofeh,000h 4C - L db Oc6h,Oeeh,Ofeh,Ofeh,Od6h,Oc6h,Oc6h,OOOh 40 - M db Oc6h,Oe6h,Of6h,Odeh,Oceh,Oc6h,Oc6h,OOOh 4E - N db 038h,06ch,Oc6h,Oc6h,Oc6h,06ch,038h,OOOh 4F - 0 db Ofch,066h,066h,07ch,06Oh,06Oh,OfOh,OOOh 50 - p db 07Sh,Occh,Occh,Occh,Odch,078h,01ch,OOOh 51 - Q db Ofch,066h,066h,07ch,06ch,066h,0e6h,OOOh 52 - R db 078h,Occh,OeOh,070h,01ch,Occh,078h,OOOh 53 - S db Ofch,Ob4h,030h,030h,030h,030h,078h,OOOh 54 - T db Occh,Occh,Occh,Occh,Occh,Occh,Ofch,OOOh 55 - U db Occh,Occh,Occh,Occh,Occh,078h,030h,OOOh 56 - V db Oc6h,Oc6h,Oc6h,Od6h,Ofeh,Oeeh,Oc6h,OOOh 57 - W db Oc6h,Oc6h,06ch,038h,038h,06ch,Oc6h,OOOh 58 - X db Occh,Occh,Occh,078h,030h,030h,078h,OOOh 59 - Y db Ofeh,Oc6h,08ch,018h,032h,066h,Ofeh,OOOh SA - Z db 078h,060h,06Oh,06Oh,06Oh,06Oh,078h,000h 58 - [ db OcOh,06Oh,030h,018h,00ch,006h,002h,OOOh 5C - \ db 07Sh,01Sh,01Sh,018h,01Sh,01Sh,078h,000h 50 - ] db 010h 038h 06ch Oc6h OOOh OOOh OOOh,OOOh 5E - A

db OOOh:OOOh:OOOh:OOOh:OOOh:OOOh:OOOh,Offh SF -db 030h,030h,01Sh,000h,OOOh,OOOh,OOOh,OOOh 60

_ T

db OOOh,000h,078h,00ch,07ch,Occh,076h,000h 61 - a db OeOh,06Oh,06Oh,07ch,066h,066h,Odch,000h 62 - b db OOOh,00Oh,07Sh,Occh,OcOh,Occh,078h,OOOh 63 - c db 01ch,OOch,00ch,07ch,Occh,Occh,076h,000h 64 - d db OOOh,OOOh,078h,Occh,Ofch,OcOh,078h,OOOh 65 - e db 038h,06ch,06Oh,OfOh,06Oh,06Oh,OfOh,000h 66 - f db 000h,OOOh,076h,Occh,Occh,07ch,OOch,OfSh 67 - 9 db OeOh 060h 06ch 076h 066h 066h 0e6h OOOh 68 - h db 030h:OOOh:070h:030h:030h:030h:07Sh:000h 69 - i db 00ch,OOOh,00ch,00ch,00ch,Occh,Occh,07Sh 6A • db OeOh,06Oh,066h,06ch,078h,06ch,Oe6h,OOOh 68 : ~ db 070h,030h,030h,030h,030h,030h,078h,OOOh 6C - l db OOOh,OOOh,Occh,Ofeh,Ofeh,Od6h,Oc6h,OOOh 60 - m db OOOh,OOOh,OfSh,Occh,Occh,Occh,Occh,OOOh 6E - n db OOOh,OOOh,078h,Occh,Occh,Occh,078h,OOOh 6F - 0 db 00Oh,OOOh,Odch,066h,066h,07ch,06Oh,OfOh 70 - P db 000h,000h,076h,Occh,Occh,07ch,00ch,01eh 71 - q db OOOh,00Oh,Odch,076h,066h,06Oh,OfOh,00Oh n- r db 00Oh,000h,07ch,OcOh,078h,00ch,OfSh,OOOh 73 - s db 010h,030h,07ch,030h,030h,034h,01Sh,000h 74 - t db 000h,OOOh,Occh,Occh,Occh,Occh,076h,000h 75- u db 00Oh,000h,Occh,Occh,Occh,078h,030h,OOOh 76 - v db OOOh,OOOh,Oc6h,Od6h,Ofeh,Ofeh,06ch,OOOh n- w db OOOh,OOOh,Oc6h,06ch,038h,06ch,Oc6h,OOOh 78 - x db OOOh,000h,Occh,Occh,Occh,07ch,00ch,OfSh 79- y db OOOh,00Oh,Ofch,098h,030h,064h,Ofch,000h 7A - z db 01ch,030h,030h,OeOh,030h,030h,01ch,000h 78- { db 01Sh,01Sh,01Sh,000h,01Sh,01Sh,01Sh,000h 7C - ! db OeOh,030h,03Oh,01ch,030h,030h,OeOh,000h 70-db 076h,Odch,000h,OOOh,000h,OOOh,000h,000h 7E db 000h,01Oh,038h,06ch,Oc6h,Oc6h,Ofeh,000h 7F -

~omorg time of day J..., time_of_may

~omorg timer int J..., timer_Tnt

romorg dumIy iret iret - -romorg -print screen int_header print:screen

print screen uses own stack

abort string label byte - db 13,10,'WARNING - This program cannot be executed under 00S.',13,10,'$'

abort: push pop

; if this program is started by dos, we display a message and abort cs ds

Section D: The ASM Pro&rams

Page 77: Atbios Kit Nov89

D·2·22 The Top File

mov mov int mov int

dx,offset abort string ax 0900h -21h print string ax,4cOOh 21" exit to DOS

i=== This is the hardware entry point after a reset === romorg

starting~int: db dw dw

Oeah OeOSbh OfOOOh

i=== This is the standard location for the date-stamp === romorg date stamp

date_stamp label byte -db '--1--1--',0

i These locations are loaded with the current date by bfosdate during the buHd process.

i======== This is the CPU type byte =========== type byte label byte

- db 0

i This location is loaded with the type byte value by biostype during the bui ld process.

i=== This is where the Bios checksum value is stored ===== db 0

i This location is loaded with the calculated checksum by biossum during the build process.

_atext ends

end abort

A-T~ BiosKit

Page 78: Atbios Kit Nov89

The Pad File D·3·1

THREE

The Pad File

The Pad.asm File is an assembly language file used to assign the starting offset of the Bios to a location greater than 0000 in the segment. If it is desired to reserve space at the beginning of the Bios segment for optional rom-scan modules, or to reduce the size of the Bios to less than 64 Kbytes in order to use a smaller-size prom, the hiospad module is used to declare the Bios starting offset. A signature is placed at the beginning of this module to facilitate the detection of secondary and test Bios'. The signature is a representation of the word "bios" expressed by the hexadecimal characters "bI05" . . *************************************************************************************************** I

; Copyright (c) FOSCO 1988 - All Rights Reserved

Module Name: AT Bios pad out the front of the bios

Version: 1.00

Author: FOSCO

Date: 12-01-88

Filename: atpad.asm

Functional Description:

This module is used to fill out the front of the bios prom when a less than 64k bios is desired. The linker always generates a 64k binary image module. The unused locations are preset to all ones (FF) so that prom pr09rammers may skip over these locations. This leaves them unused and avai lable for merging 1n optional rom-scan modules for an extended custom Bios.

Version History:

!************************************************************************************************** I

include atprfx.inc • code extrn reset:near

bios start proc - dw

db j~

bios_start endp

end

OSb1h BOh reset

this is a Bios signature

Page 79: Atbios Kit Nov89

Things I Should Forget

Page 80: Atbios Kit Nov89

The Fill File D·4·1

FOUR

The Fill File

The Fill.asm File is an assembly language file used during the linking process to upwardly justify the biostop module so that it resides at the end of the Bios segment.

.*************************************************************************************************** , Copyright (c) FOSCO 1988 - All Rights Reserved

Module Name: Bios fill at link time

Version: 1.00

Author: FOSCO

Date: 5-12-88

Filename: atfill.asm

Functional Description:

Uses biosfill.inc (generated by BIOSGEN) to fill out area so the biostop module will be positioned correctly at the top of the bios.

Version History:

;**************************************************************************************************/

include atprfx. inc

-fi II segment

include atfill.inc

fill ends -end

Page 81: Atbios Kit Nov89

Meetings I Should Go To

Page 82: Atbios Kit Nov89

The Data File D·5·1

FIVE

The Data File

The Data.asm File is an assembly language file used to declare the variables assigned to the system scratch Ram segment and those used by the Sys Vue program. These variables will be assigned to the top 2 Kbytes of space in the system Ram Memory map by the power-up (POD) routine.

The memory block pool definitions also reside in this file. The acquire_block and release_block operations (in Biosmisc.c) are used to assign memory for use as variables to limit use of the stack by Bios function call routines .

• ************************************************************************************************** , Copyright (c) FOSCO 1988 - All Rights Reserved

Module Name: AT Bios system data definition

Version: 1.00

Author: FOSCO

Date: 12-01-88

Fi lename: atdata.asm

Language: MS MASH 5.1

Functional Description:

This module is used to declare the variables in the system ram segment. Most of these variables are used by biosvue. A stack is assigned at the top of the module for use by the POD routines.

Version History:

;**************************************************************************************************/

include atprfx.inc

the data section to declare the system ram for biosvue

publ ic publ ic ~lic Public publ ic public public publ ic public public publ ic public public public publ ic public public publ ic public public public public public public public publ i c publ ic publ ic public publ ic public Public publ ic

mode size mode-type sysvUe busy inchar­buffer exit flag buffer index reg saves inreg saves out reg saves token index token-value cc -token buffer conmafid index flag ir&x token fUlt)er list index last-del im breai flag last ~ start seg ~ast:dumP:start:off lnt seg int-off reg-index break chain trace-chain trap_Chain present sl.l1l enter_seg, enter_off char count record_type

Page 83: Atbios Kit Nov89

D·5· 2 The Data File

~lic ~lic public ~lic public publ ic publ ic

trace COll1t watch-flag watch-selection u found jJ redirect flag dec_array

;=== definition of system scratch object === scratch segment at 0

aid dw

; sysvue variables

sysvue busy dw 1 mode sTze dw mode-type dw inchir dw 1

?

? ?

buffer dw 80 dup(1) exit flag dw ? buf fir index dw 1

- align 16 reg saves label word

- dw 16 dup (1) inreg saves label word

- dw 16 dup(1) out reg saves label word

- dw 16 dup(1) token index dw 1 token-value dw 8 dup(1) cc - dw 1 token buffer dw 16 dup(1) conrnaiid index dw ? flag inC!ex dw token number dw 1 lis t T ndex dw 1 last-delim dw 1 breaK flag dw 1 last a~ start seg dw 1 last-dump-start-off dw 1 int seg Ow - 1 int-off dw 1 reg-index dw ? break chain dd 1 trace-chain dd 1 trap_Chain dd ? present dw trace count sum - dw enter seg dw enter-off dw char count dw record type dw ? watch flag watch-selection u found dw H. dw redlrect flag dec_array ci)

? dw ? 1 ? 1

dw dw ? 1 dw 6 dup(1)

?

?

? ?

?

Object Structure Definitions

optional id field = 5aa5 to be valid load this field if you need to locate this object in an expanded system.

line input buffer ; -1 = exit from sysvue

ptr for DUffer

i these are normal saves

these are used for INT command

these are used for I NT command

ptr for token string

token string gotten from _token_index

nr. of match i ng i tern

i last delimiter found

;============== variables for functions ============ :------ reserved space for protected mode tables ------­

;----- pointer to parent bios

parent

org publ ic dw

48h parent 1

;------ reserved space for protected mode tables

al ign 16 pUblic GOT block

GOT_block label byte -dq 7 dup(1)

publ ic lOT_block dq

al ign publ ic

lOT block o -16 psuedo _LI OT

A· Type BiosKit

Page 84: Atbios Kit Nov89

psuedo_LIDT

align PUblic

psuedo_LGO'r

align publ i c

virtual block - db

df 0

8 ~uedo LGDT df - 0

16 virtual block label byte 256 dup(7)

block space for allocating public start block public current open Publi c end blOCk public blOCk beg public block:end

The Data File D-5-3

The following area is a block-pool, from which blocks can be allocated by the functions: acquire_block release block

These allow dynamic allocation for recursive functions while minimizing stack space used. public ds save,bx save,dest save, length mark public sp:save,ss:save - -

align 16

start block dw 7 current ~ dw ? end_blOCk dw 7

bx save dw 7 ds-save dw 7 deit_save dw 7

align 16

block beg label word - dw 1024 dup(7)

block_end label word

;===================================================

scratch ends

; This structure is used to save the old stack pointer in the new ; stack block, It is used to switch back to the callers stack ; after a swapping interrupt.

swap_seg segment at 0 length_mark dw

dw dw dw

sp_save ss save swap_seg ends

end

7 7 7 7

also user 10 field save of callers ss:sp

Section D: The ASM Pro&rams

Page 85: Atbios Kit Nov89

Meetings I Should Avoid

Page 86: Atbios Kit Nov89

The Virt File D-6-1

SIX

The Virt File

. The Virt.asm File contains the virtual mode routines.

Three major items are handled by the virtual routines: 1. Sizing and testing any extended ram 2. Block move routine which supports Virtual Ram Disks. 3. Switching machine operation to virtual mode.

Default descriptor tables are built for ram test and for the block move. The user needs to build the tables when switching to virtual mode. The test and the move routines have their own restart sequences, so that the CPU may be restarted back in real mode, and continue operation.

A restart consists of saving a restart code in the CMOS RAM at location OF. An error code may be returned in DMA page register port 80. The values are used to determine what action to take. An optional argument may be saved in port 88. A signal is then sent to the 8042 keyboard controller which pulses the reset line to the CPU. The CPU then restarts in the default real-mode and the restart-code value is checked to see if it is other than a power-up or a normal reset switch sequence. If a valid restart code value is found in port 80, the Biostop.asm module code diverts to the specific restart sequence. This restart sequence then restores the machine state (registers) and returns control to the program which caused the CPU to go to virtual mode.

The 286 CPU normally starts operation in the real-mode upon power-up. It may be switched to virtual mode by setting the protection enable (PE) bit in the machine status word (MSW). Because of a quirk in the original design of the 286 CPU, the only way to switch back to the real-mode, (which is the normal mode for DOS), is by actually causing a hardware reset of the CPU chip. To permit this, the 8042 output port has an output line which connects to the 286' s reset input line. A command may be sent to the 8042 to pulse this reset line.

The 386 has provision for switching to and from the virtual mode internally by modifying the machine status register (MSW) by a 386-specific instruction (MOV to Control Register). This enhancement of the 386 negates the need for the complicated restart handling of the 286.

One item about the 286 which is of interest is that there is a Interrupt Descriptor Table Register (IDTR) which provides the base address of the interrupt vectors. Upon a hardware reset, this register is set to a value of 0000, so that the base address of the interrupt vector segment is at zero. When switching to virtual mode, this register is changed to point to an Interrupt Descriptor Table (IDT). This permits the interrupt vector segment to be re-Iocated without changing the contents of the vector locations. This basing register is also active in the real-mode (since it defaults to 0000, we are not aware of its existence in real-mode) and can be used to relocate or substitute multiple sets of interrupt vectors. In standard DOS practice, however, this option is not exercised.

Page 87: Atbios Kit Nov89

D·6· 2 The Virt File

Why the DMA page register is used to save parameters - During the restart sequence, there are usually some values that need to be passed from the virtual­mode program back to the real-mode program. These could be saved in the CMOS RAM, or somewhere in system memory. A very convenient spot that was originally used on the AT type machines, is the DMA page register chip. In the earlier PC and XT type of machines, the re~ister was a write only device, which handled the four standard DMA channels. ThIs chip held the high four bits of the memory address during a DMA transfer, as the 8237 DMA chip only has 16-bit internal repsters. The AT type of machines have an additional 8237 DMA controller for 16-bJt wide data transfers. Now there was a need for 8 page registers (one for each of the 8 DMA channels). Instead of using two of the XT type chips (74670), a newer chip was selected. This is the 74612 type of chip. This contains 16 8-bit registers, 8 of which are used for the DMA channels. These registers are both read/write, so two of these are used for passing parameters by the AT BiosKit. The basic restart-type code is passed in location OF of the CMOS-RAM, but an error-descriptive value is passed in the page register port at 80, and a second argument may be passed in register port 88.

Notes for potential 386/376 users - The 386, as mentioned previously, has an enhanced mechanism for switching between real and virtual modes, while the 376 assumes the virtual mode of operation from reset, since it does not have the real­mode capability. .

.*************************************************************************************************** , ; Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

~ Module Name: AT BiosKit Virtual memory support

~ Version: 1.02

; Author: FOSCO

; Date: 10-20-89

: Filename: atvirt.asm

; Language MS MASM 5.1

; Functional Description:

; Version History: ; 1.01 ; Deleted some extraneous code (GOT structures) ; 1.02 ; Corrected block move errors ; Changed restart from 8042 s~e to double fault shutdown sequence ; Added sucoort for restart 5 and 10 ; Changed ")/11) myself" loop after shutdown to a HLT to keep busses quiet

!*************************************************************************************************** , include atprfx.inc

extrn extrn extrn . extrn extrn

extrn extrn ~lic publ ic public

err'-port equ arg-.POrt equ port a porto i ntalJO inta01

out cmos : near GOT block!near IDTolock:near psuido LGOT: near psuedo:LIDT:near

co:near lword:near restartS restart9 restart10

080h 088h equ equ equ equ

; save stuff in page register chip 66~te for saving aux. data on restarts

061h 020h 021h

A-Type BiosKit

Page 88: Atbios Kit Nov89

intbOO equ intb01 equ status-POrt equ input DUffer full equ restart cell- equ restart-command equ Ofeh

OaOh Oa1h 064h 02h 08fh

cmos-POrt equ 070h disa~e-P8rity equ OOch ena~le-P8rity equ Of3h parlty_error equ OcOh

build 24bit address macro arg1,arg2 - PUsh arg2

push ar~1 call bulld 24 add sp,4 -enan

build_descriptor macro arg1,arg2 push arg2 push ar~1 call bulld descriptor routine add sp,4 - -enan

These are macros to enable or disable A20, added 5-12-89 <BG>

active inactive equ

Odfh

change_number = 0 Number of change_a20 call

empty_8042 macro local empty_loop empty_number = empty _nc.Jlt)er + xor cx,cx

empty_loop; 1n and loopnz mov encin

al,64h al,02h ~ty loop al, ~tyj'uar

Inc number of empty call

change a20 macro arg ;; Odfh = enable, Oddh = disable - local error check,exit change

empty_number = 0-; Start ofT with empty number = 0 change number = change number + 10h

- ~ty 8042 -jnz - error check mov a l ,Od'lh out 64h,al ~ty 8042 jnz - error check mov al,arg out 60h,al efI1)ty 8042

error check: -- clc

jz exit_change stc add al,change_number

exit change: - enan i End of new macros <BG>

i==== definitions for virtual modes ===== i==== (test_ram and move_block) ==== i------ Code/Data Descriptor definitions ----------------

desc struc lim 15 0 dw bas-15-0 dw bas-23-16 db access-

limit (15-0) base (15-0) base (23-16)

The Virt File D-6-3

irsv desc ends

o o o db dw

o o

; access rights ; intel 386 reserved next 2 bytes

trap/interrupt gate definition

tigdesc struc code offset code:select

dw dw db

? ? o

offset to routine selector to routine always zero

Section D: The ASM Pro&rams

Page 89: Atbios Kit Nov89

D-6-4 The Virt File

hb_arb

tigdesc ends

db dw

len_desc equ 8

?

o high base and access rights reserved for 386

;========== Global Descriptor Table structures ========== 0 _______ the GOT for the block move organization ------; This structure order is determined by the function call format. ; Do not alter it I ; We also use this structure for the extended memory testing move struc move any dq 0 move :gdt c:Jq 0 move ds move-es move-cs move-ss move-idt dq 0 move-ends

fdt fdt ide

struc

ends dqO

i 00 ; 08

10 18 20

• 28 30 - this exists for both move and mem-test

; 00

i---------- the GOT for virtual mode function call --------i This structure order fs determined by the function call format. ; Do not alter it I mode struc mode_any dq mode sdt dq mode -1 dt c:Jq mode-ds dq mode:es dq mode ss dq mode - cs c:Jq modecios dq mode-ends

o o o o o o o o

00 - unusable 08 - GOT 10 - lOT 18 - data 20 - extra 28 - stack 30 - code 38 - bios

i----------------------------------------------------- ----;----------- the gdt segment for the POD and the move ---­

gdt segment segment at 0 gdt:start label byte

desc <> desc <> desc <> desc <> desc <> desc <> desc <>

gdt end label byte gdt-len = gdt end-gdt start gdt:segment ends -

idt segment segment at 0 idt:start label byte

desc <> idt_segment ends

virtual_enable equ 1

null_idt: desc<>

table 0 not usable 08 - GOT 10 - temp for ds 18 - temp for es 20 - temp for ss 28 - temp for cs 30 - lOT - created for move

ram idt descriptor

;========== end of definitions ============

i this module includes all the code for accesssing the virtual memory and running in protected mode

i----------------------------------------------------- -----• code

;-------- move virtual block - function code 15h ----------

virtual move proc uses ds,word count:word,global segment:word,global offset:word - cli - - ; disable interrupts/execeptions

cld xor al,al out err-POrt,al change a20 acllve jnc - iF change a20 inactive mov - aX,0300h ret

A-Type BiosKit

; clear the error bucket

enable full range addressing <8G> i no carry says A20 ok

disable 1t again <8G> mark A20 error, return to caller

; quiCK return when A20 error

Page 90: Atbios Kit Nov89

ii)Q: pusha push push push pop assune

mov mov mov mov

ds es 40h ds ds:segment_40

ax,ss vsegment,ax ax,sp voffset,ax

write_cmos restart_cell,9

build_descriptor es,si

mov

mov mov

cx,word_count

ax,40h

The Virt File D-6-S

save return pointers in low ram

save stack description in low ram

set restart type 9

get and save the move count

es,ax es, word ptr es:[Oeh] mov get system seg

19dt fword ptr es:psuedo_LGOT; point the gdt-reg to the block

Udt fword ptr es:psuedo_LIOT ; lOT's are built

mov lmsw delay db

aX,virtual enable ax -

Oeah

go into protected mode this jump to clear queue

dw

jmp far ptr into cs: selector to ; set access rights

cont i nue execut i ng 2 lines be l ow

continue:

ii)Q:

ii)Q:

dw

nap mov mov mov mov mov mov sub sub ~ep 1n test jz xchg xchg mov out in delay or out delay and out

aX,move_ss sS,ax aX,move ds ds,ax -aX,move_es eS,ax di ,di si ,si movsw al,port b al,parity error GlF -ds: [di] ,ax ds: [di] ,ax al,1 err,J)Ort,al al,port_D

al,disable-psrity port_b,al

al,enable-psrity port_b,al

change a20 inactive jnc - GlF in al,err,J)Ort or al,al jnz GlF mov al,3 out err,J)Ort,al

set up selectors

; word count is already in ex ; this does the actual move

see if a parity error on move

jump if no error re-write the bad word

set parity error code in bucket

reset parity

were there any previous errors? test for non-zero

no - set A20 error code

i fndef SLOW RESET Shutdown may not work on some ch i ps~ts <BG> ; try causing i shutdown

else <BG>

endif

lidt fword ptr cs:null idt int 3 -

mov out

hlt

al,restart command status,J)Ort,al

Use keyboard controller to reset if shutdown won't work

this causes restart

End of alternate reset code <BG> stop cpu to quiet the busses

i- This is where the restart from the block moves comes in -

restart9: ; proc mov mov assune

ax,40h ds,ax ds:segment_40

Section D: The ASM ProlUams

Page 91: Atbios Kit Nov89

D·6·6 The Virt File

cli mov mov mov mov pop pop pope 1n mov xor ret

ax,vsegment ss,ax ax,voffset sp,ax es ds

al,errJ)Ort ah,al al,al

restore the original real stack

; get.returning error code

return with error code in AH virtual_move endp

••.•..•.•. switch to virtual mode .•••...•...•••.•• ; Int 15 c function 89

void vlrtual mode(bhbltseV,off) called with 5h = 8259 .1 lndex called with bl = 8259 #2 index called with es = segment of ~inter to global desc. table called with si = offset of pointer to globel desc. table returns with ax = 0 = ok, else not zero = error all other registers destroyed IIII

vi rtua l mode proc bhbl : word,desc_seg: word, desc_off: word - cl i

@G):

lOT

change a20 active jnc - iF mov ax,-1 ; set error, quick return to caller ret

mov mov 19dt

l idt

es,desc seg si,desc-off fword pfr es:[si].mode_gdt

fword ptr es:[sil.mode_idt

reload the 8259 interrupt controllers because we have changed the base address of the

( the interrupt vectors).

mov out delay mov xchg out delay mov out delay mov out delay mov out

al,11h intaOO,al

ax,bhbl ah,al inta01,al

al,04h inta01,al

al,01h inta01,al

al,Offh inta01,al

al,11h intbOO,al

ax,bhbl intb01,al al,2

intb01,al

al,1 intb01,al

this is penn from caller

this is penn from caller

mov out delay mov out mov delay out delay IIIOV out delay IIIOV al,Offh out intb01,al

build our own CS: as the bas 23 16 value for the descriptor table, This way we can execute from a secondary or a test bios, it other than segment FOOO.

IIIOV shr

IIIOV mov IIIOY IIIOY IIIOY moY lmsw

ax,cs ax,12

A-Type BiosKit

; now looks as 32-16 value

Page 92: Atbios Kit Nov89

delay mov mov mov mov mov mov

The Virt File D·6· 7

this jump to clear queue

~

ax,mode_ds ds,ax ax,mode_es es,ax ax,mode ss ss,ax -bx sp,4

get the return address off the stack need to adjust this II!! we may have to back up through the call into the Int 15 function to return

push push retf

virtual_mode endp

mode cs bx -

to the real caller. 7111 push cs selector on stack push return on stack return to user

These are the "continue" points for returning from virtual mode to real mode, when using the switch to virtual mode function above The User MUST disable both interrupts and NMl

f and load V OFFSET and

V SEGMENT with a valid continuation address. hen the user must load the restart code (5d or 10d (OSh or Oah» in CMOS location xx, then cause a double fault exception to force a CPU reset. Not many users get involved in this. Programmers Opinion: If you really want to operate in virtual mode, get a 386 mach i ne.

restart5:

restart10:

in mov out

mov mov j"l)

al,60h al / 20h 20n,al

ax,40h ds,ax dword ptr voffset

i=============================

idt descriptor label byte - dw rom idt len

purge the keyboard buffer send an EOI to the interrupt controller to purge pending timer interrupts

voffset is in segment 40:

dw offset rom_idt db Ofh,O resident idt table is in bios_cs

idt descriptor length = S-idt_descriptor' rom-idt: -

- tigdesc <exc OO,move cs,,81h> tigdesc <exc-01,move-cs,,81h> tigdesc <exc-02,move-cs,,81h> tigdesc <exc-03,move-cs,,81h> tigdesc <exc-04,move-cs,,81h> tigdesc <exc-OS,move-cs,,81h> tigdesc <exc-06,move-cs,,81h> tigdesc <exc-07,move-cs,,87h> tigdesc <exc-08,move-cs,,87h> tigdesc <exc-09,move-cs,,87h> tigdesc <exc-10,move-cs,,87h> tigdesc <exc-11,move-cs,,87h> tigdesc <exc-12,move-cs,,81h> tigdesc <exc-13,move-cs,,81h> tigdesc <exc-14,move-cs,,87h> tigdesc <exc-15,move-cs,,81h> tigdesc <exc-16,move-cs,,87h> tigdesc <exc-17,move-cs,,81h> tigdesc <exc-18,move-cs,,81h> tigdesc <exc-19,move-cs,,81h> tigdesc <exc-20,move-cs,,87h> tigdesc <exc-21,move-cs,,81h> tigdesc <exc-22,move-cs,,87h> tigdesc <exc-23,move-cs,,87h> tigdesc <exc-24,move-cs,,87h> tigdesc <exc-2S,move-cs,,81h> tigdesc <exc-26,move-cs,,81h> tigdesc <exc-27,move-cs,,81h> tigdesc <exc-28,move-cs,,87h> tigdesc <exc-29,move-cs,,87h> tigdesc <exc~0,move-cs,,87h> tigdesc <exc~1,move-cs,,87h>

rom_idt_len equ S-rom_Tdt -

;--------------------------------ex_int:

Q)Q):

mov out mov out hlt

al,2 err~rt,al al,restart command status~rt,al

exception interrupts for move error code = 2 = excep. into error

Section D: The ASM ProlUams

Page 93: Atbios Kit Nov89

D·6·8 The Virt File

restore idt label fword - dw 3ffh

dw 0 dw 0

i ret addr label word - i ret

lim 15 0 basi -

; this sets up an all inclusive exception table. if we get an exception while we are in virtual mode, we want to process and report it.

sys idt offsets - - dw

dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw

label word offset exc 00 offset exc-01 offset exc-02 offset exc-03 offset exc-04 offset exc -05 offset exc-06 offset exc-07 offset exc-08 offset exc-09 offset exc-10 offset exc-11 offset exc-12 offset exc-13 offset exc-14 offset exc-15 offset exc-16 offset exc-17 offset exc-18 offset exc-19 offset exc-20 offset exc-21 offset exc-22 offset exc-23 offset exc-24 offset exc-25 offset exc-26 offset exc-27 offset exc -28 offset exc-29 offset exc'""30 offset exc::J1

00 = divide error 01 = si~le step 02 = l'1IIi 03 = trap 04 = into detect 05 = bounds check 06 = inval id opcode 07 = NPX not available 08 = double fault 09 = NPX segment error 10 = invalid tss 11 = cs, ds, es not present 12 = SS: not present 13 = general prot error 14 = 15 = 16 = NPX error 17 = 18 = 19 = 20 = 21 = 22 = 23 = 24 = 25 = 26 = 27 = 28 = 29= 30 = 31 =

;----- this is the canned gdt for the pod routines ---------

gdt data start - - desc

label word <0,0,0,0> ; 00·

08 - the GOT desc desc desc desc desc desc

<gdt len(,offset GOT olock,0,93h> <-1,0000 ,Ofh,93h> -; 10 - temp for ds <-1,0000h,10h,93h> ; 18 - temp for es <-1,0000h,00h,93h> ; 20 - temp for cs <-1,0000h 00h,93h> ; 28 - temp for ss <rom idt (en,rom idt,0,93h> ; 30 - the IDT

word - - -gdt_data_end label

---------------.------------------_._--.-._--------exc_OO: mov al,O ; load al with exception ruar jmp test exc

exc_01: mov al,1-jmp test exc

exc_02: mov al,2-jmp test exc

exc_03: mov al,3-jmp test exc

exc_04: mov al,4-jmp test_exc

exc_05: push mov mov sub mov mov pop mov jnp

exc_06: mov jnp

exc_07: mov

es this is a bounds check ax,move es es,ax -di ,di word ptr es:[di] 0 word ptr es:[di+~],07fffh es al,5 test_exc

al,6 test exc al,r

A· Type BiosKit

Page 94: Atbios Kit Nov89

j~ test exe exc_08: mov al,8-

j~ test exc exc_09: mov al,9-

jlJ1) test exe exc_10: mov al,10

jlJ1) test exe exc_11: mov al,1T

jlJ1) test exc exc_12: mov al,12

jlJ1) test exe exc_13: mov al,13

jlJ1) test exc exc_14: mov a l, 17;

jlJ1) test exc exc_15: mov al,1)

jlJ1) test exe exc_16: mov a l , 11)

jlJ1) test exe exc_17: mov al,17

j~ test exc exc_18: mov al,18

j~ test exc exc_19: mov al,19

j~ test exc exc_20: mov al,20

j~ test exe exc_21: mov al,2T

jlJ1) test exc exc_22: mov al,22

jlJ1) test exe exc_23: mov al,23

j~ test exe exc_24: mov al,27;

jlJ1) test exe exc_25: mov al,2)

jlJ1) test exe exc_26: mov al,21)

j~ test exc exc_27: mov al,27

jlJ1) test exc exc_28: mov al,28

jlJ1) test exc exc_29: mov al,29

jlJ1) test exe exc_30: mov al,30

jlJ1) test exc exc_31 : mov al,3T

jlJ1) test_exe

; if we got an exception, process it so we can return an ; exception code.

test_exc: add out iret

al,80h errJ)Ort,al

add SOh to these exceptions

;------- build a descriptor table in the system ram segment

we do this for both the block move and the mem-test t seV:t off ~ints to the template to build wi wlll-fill in some dynamic values it will be buil t in system:segment:GDT_block

;------- build the global descriptor tables ---------------

; These are built with current CS: in case we are in test mode

build_deseriptor_routfne proc t_seg:word,t_off:word

i-- ds:si ~ seg:off of the template

mov mov

ds,t seg si,t:off

i-- es:di = location in system segment to build the descriptor

mov di,offset GOT_block mov ax,40h mov es,ax moves, word ptr es:[Oeh]

i-- cx = length of the template

The Virt File D·6·9

mov cx,24 template is 48 bytes long

Section D: The ASM Prolfams

Page 95: Atbios Kit Nov89

D·6·10 The Virt File

push rep pop

di movsw di

i-- build a dynamic GOT descriptor

build 24bit address es,<offset GOT block> mov - es:[dil.move gdt.lim 15 O,38h mov es:[dil.move-gdt.bas-15-0Jax mov es:[dil.move-gdt.bas-23-10 dl mov es:[dil.move-gdt.access;93h mov es:[dil.move:gdt.irsv,O

i-- build a dynamic CS: descriptor

build 24bit address cs,O moy - es:[dil.move cs.lim 15 0,-1 mov es:[dil.move-cs.bas-15-0 ax moy es:[dil.move-cs.bas-23-1A,dl moy es:[dil.move-cs.access;9bh moy es:[dil.move:cs.irsv,O

i-- build a dynamic SS: descriptor

build 24bit address ss,O moy - es:[dil.move ss.lim 15 0,-1 moy es:[dil.move-ss.bas-15-0,ax moy es:[dil.move-ss.bas-23-16 dl mov es:[dil.move-ss.access;93h mov es:[dil.move:ss.irsv,O

i-- build a dynamic lOT descriptor

build 24bit address es,<offset lOT block> mov - es:[dil.move idt.lim 15 U,6 mov es:[dil.moye-idt.bas-15-0 Jax mov es:[dil.move-idt.bas-23-10 dl mov es:[dil.move-idt.access;93h mov es:[dil.move:idt.irsv,O

i-- now build the lOT descriptor

build 24bit address cs,<offset rom idt> mov - dT,offset lOT block -mov es:[dil.idt.Tim 15 0,6 mov es:[dil.idt-.bas-15-0 Jax mov es:[dil.idt-.bas-23-10 dl mov es:[dil.idt-.access;93h mov es:[dil.idt:.irsv,O

;-- now build the psuedo GOT- qescriptor

build 24bit address es,<offset GOT block> mov - dT,offset psUedo LGOT -mov word ptr es:[di+U01,56 mov es:[di+02],ax mov es: [di+04],dx

i-- now bui ld the psuedo lOT descriptor

build 24bit address es,<offset lOT block> mov - dT,offset psUedO LIOT -mov word ptr es:[di+UO],256 mov es:[di+02],ax mov es: [di+04],dx ret

build_descriptor_routine endp

save base address of GOT table

;---------------------------------------------------_.--; returns a 24 bit address in OX:AX

bui ld_24 proc xor mov mov shr shl add adc ret

bui ld_24 endp

xseg:word, xoff:word dx,dx ax,xseg build 24-bit address from seg:off dl,ah dl,4 ax,4 ax,xoff dl,O

Test Ram - size, test, and clear

A· Type BiosKit

Page 96: Atbios Kit Nov89

returns ok/error code in AX - size in cmos(30 and 31) note: this are all near procs, since they can be called from the Bios CS: only. After we do a restart, we are also in the Bios CS:, so we automatically connect with the right return address. The ram test is a combination of a block-move (Bios -> test area) followed by a block compare.

CJIlSg: db 13,10,"A20 error on entry",O

test ext mem proc - - cl i

cld al,Offh 21n,al

mov out pusha push ds push es write cmos 30h,0 ; write:cmos 31h(0 ; xor al,a out err-POrt,al

disable interrupts/execeptions

mask the 8259 save all the reggies

clear the re~rting cells for ext mem size

; clear the error reporting cell

The Virt File D·6·11

Note: Interesting point: It takes the 8042 a discrete amount of time to actually enable the A20 address line after this command is given. It is given in some publications as > 20 useconds. If the extended mem tests cuase a system crash 'it may be because A20 has not switched yet, and < 1Mb ram is getting trashed. See the delay routines in the wrap enable/disable functions.

@GI:

change_a20 active ; enable full range addressing <BG> ; Error numbers 516,52,53 <BG> ; no carry says A2 OK jnc .F

mov ah,al change_a20 inactive ; mov al,ah out err-POrt,al pop es pop ds popa mov sti ret

aX,0300h

40h

save nuar of "efI1)tyl that failed <8G> <8G>

retrieve nuar of "8q)tyl that failed <8G>

mark A20 error, return to caller ; re-enable interrupts ; quick return when A20 error

push pop assl.me

ds ds:segment_40

save return pointers in low ram

mov mov mov mov

ax,ss vsegment,ax ax sp voJfset,ax

save stack description in low ram

write_cmos restart_cell,2 ; set restart type 2

build a complete GOT table set Once we do this, we can't do any interrupts, because the LIOT changes the interrput vector table base. Since we set it up for exceptions, we won't be able to do video interrupts.

next:

build_descriptor cs,<offset GOT_data_start>

mov mov mov

19dt

lidt

mov lmsw

delay

db

dw dw

delay

mov mov

ax,40h eS,ax es, word ptr es:[Oeh] get system seg

fword ptr es:psuedo_LGDT; point the gdt-reg to the block

fword ptr es:psuedo_LIOT lOT's are built

ax,virtual_enable ax

Oeah

ax, offset move_ss ss,ax

goto virtual mode

this jump to clear queue

jmp far ptr into cs: selector to set access rights

Section D: The ASM ProlUams

Page 97: Atbios Kit Nov89

D·6·12 The Virt File

mov mov assune

start loc equ end loc

ax, offset move gdt ds,ax -ds:gdt segment OOfh -equ Ofeh

- mov mov

mem check:

dl,start loe • start at 1 Mb - 64K ds:move_es.bas_15_0,6 ; set es: segment = xxOOOO

- inc c~ jae mov

dl dl,end loe ; > 15 Mb bou1dary ? mem exit ds:move_es.bas_23_16,dl ; set es: segment

cld mov mov sub sub mov

; make sure direct is forward

~~ sub mov

ax,move_es es,ax di ,di s i ,si cX,8000h ; move 64k

• this preloads the block movs word ptr es:[dii,word ptr cs:[si] di ,di si,si

repe jcxz j~

cX,8000h ; compare 64k • this does the actual test

crops word ptr cs:[sii,word ptr es:[di] mem ok ; it's OK

mem_ok:

mem_exit:

sub mov xor rep j~

mem:exit exit

di ,di cX,BOOOh ax,ax stosw mem_check

. ; now clear the block clea.r 64K

check the next block

xor cI1,cfI dec dl ; ~ dl down to last good segment sub dx,start loc ; rejustify to "0000" shl dx,6 - ; eX8q)le Z56K = 100h ; just return tested OK size - pod can display findings wr1te_cmos 30h(dx ; write the cmos

GlGl:

xchg dh d write_cmos 3ih,dx

change a20 inactive; jnc - QF mov ah,al in al,err-POrt or al,al jnz GlF mov al,ah

out errJlOrt,al

ifndef NO SHUTDOWN

~ty numbers 71,72,73 <BG>

save number of tlemptY" that fai led <8G> were there any previous errors ? test for non-zero

no - set A20 exit error code to number of fai led "emptY" <8G>

Shutdown may not work on some chipsets <8G> ; try causing a shutdown

lidt fword ptr cs:null idt int 3 -

else <BG>

endif

mov out

hlt test_ext_mem endp

al,restart command status-POrt,al

; Use keyboard controller to reset if shutdown won't work

End of alternate reset code <8G> stop the CPU to qui et the busses

; This is the real return from the ext mem test

restart2 proc mov mov assune mov mov mov mov pop pop

GlGl:

f?OP8 1n or jnz mov sti ret

aX,40h ds,ax ds: segment 40 ax,vsegment ss,ax ax,voffset sp,ax es ds

al, err -port al,al QlF ax,ok

A· Type BiosKit

restore the original real stack

now pop the registers

iet returning error code 1f non-zero, return "error"

return(ok);

Page 98: Atbios Kit Nov89

mov sti ret

restart2 endp

ax, error

; return(error);

; ________________________________________________________ e.

end

The Virt File D·6·13

Section D: The ASM Pro&rams

Page 99: Atbios Kit Nov89

Meetings I Should Call

Page 100: Atbios Kit Nov89

The C Programs

These are the modules of the Bios which are in C. They include the Function Calls and the Interrupt Service Routines.

Page 101: Atbios Kit Nov89
Page 102: Atbios Kit Nov89

The Kit.h File E·l·l

ONE

The Kit.h File

The Kit.h file is the 'c' header file used for all the Bios modules. The 'c' language utilities used in the build process use normal .h files since they run from normal Ram. Because the Bios is a prom-resident pro~ram, it has its own special requirements in the use of the CPU's segment regIsters. Declarations to provide interrupt routine support are also in this file. A special simplified interrupt sequence is provided in order to save and restore registers when either calling interrupt routines, or in defining a function to act as an interrupt routine. Because of these features included in the bioskit.h file, interrupt service routines are written as regular functions, with the machine register state being declared as unsigned integer parameters on the stack.

/*************************************************************************************************** * : Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

* Module Name: AT Bios h file of standard definitons * * Version: 1.02 * * Author: FOSCO * * Date: 11-01-89 * * Filename: atkit.h * * Language MSC 5.1 * : Functional Description:

* This file is used for the standard header for bios 'C' programs. It is the only header file : that should be #defined in the Bios modules. Other headers may contain conflicting definitions.

* * * * *

The Bios does not use any standard library for two main reasons: 1. The linker attempts to place library routines at the top of the segment,

which Rl.lSt contain some fixed code.

2. The standard libraries assume that the program is running under DOS (which is not the case for Bios), and may make DOS references. *

* * *

The file Biostop.asm contains the assembly-language functions required for the Bios.

* Version History: * 1.01 : Font revi s i on - content t.n:hanged

* 1.02 * Defined casts for low ram variables * ***************************************************************************************************/

unsigned peek(unsigned,unsigned); unsigned peek40(unsigned)i unsigned peekcs(unsigned)i void poke(unsigned,unsigned,unsigned)i void poke40(unsigned,unsigned);

unsigned char peekb(unsigned,unsigned)i unsigned char peekb40(unsigned)i unsigned char peekbcs(unsigned)i unsigned peekcs(unsigned);

void pokeb(unsigned,unsigned,unsigned char); void pokeb40(unsigned,unsigned char); void beep(void);

void and40(unsi~ned,unsi~ned); void andb40(unslgned,unslgned char)i void or40(unsi~ned,unsi~ned)i void orb40(unslgned,unslgned char); void xor40(unsigned,unsigned)i

Page 103: Atbios Kit Nov89

E·l· 2 The Kit.h File

void xorb40(unsigned,unsigned char);

unsigned inport(unsigned)i unsigned char inportb(unslgned); void outport(unslqned,unsi~ned); void outportb(unslgned,unslgned char);

unsigned bios cs(void): void set vector(unsigned,unsigned,unsigned *): void lbyfe(unsigned char): void lword(unsigned): void write string(unsiqned *): void bios_Unsigned(unSlgned,unsigned *,unsigned *);

void outcmos(unsigned,unsigned char); unsigned char incmos(unsigned); unsigned acquire scratch block(unsigned,unsigned,unsigned,struct callers far *); void release bloek(unsigned): unsigned loni set timeout count(unsigned); void snapshot in(Unsiqnedr, struct callers far *): void snapshot:out(unslgned, struct callers far *):

#define true 1 #define false 0

#define yes true #define no false

#define ok 0 #define error -1

#define at Oxfc #define xt Oxfe

1* error codes may be 0001-ffff *1

1/ type byte definition 1/ type bYte definition

#define cr 13 #define If 10 #def i ne bspace 8

#define sys_seg_size 4096

#define BIT15 Ox8000 #define BIT14 Ox4000 #define BIT13 Ox2000 #define BIT12 Ox1000 #define BIT11 Ox0800 #define BIT10 Ox0400 #define BIT9 Ox0200 #define BIT8 Ox0100 #define BIT7 Ox0080 #define BIT6 Ox0040 #define BITS Ox0020 #define BIT4 Ox0010 #def i ne B I T3 Ox0008 #def i ne B I T2 Ox0004 #define BIT1 Ox0002 #define BITO Ox0001

II Define the watch bits

II size of the system segment

II These bits are also used by the block acquire/release II function as the owners 10 codes. This is for future enhancements.

#define VIDEO BITO #define VUE BIT1 #define CASSETTE BIT2 #def i ne EQU I PMENT B I T3 #define MEMORY BIT4 #define LPT BITS #define COM BIT6 #define FLOPPY BIT7 #define HARD BIT8 #define TOO BIT9 #define BOOT BIT10 #define TIMER BIT11 #define KEYBOARD BIT12 #define PRSC BIT13 #define POO BIT14

1/ define the devices subject to watching - exclude some I #define WATCH MASK CASSETTEIEOUIPMENTIMEMORYICOMIFLOPPYIHARDITOOIBOOT #define carry-bit Ox0001 #define zero_Sit Ox0040

#define interrupt registers \ uns i gMa es, uns i gned ds, uns i gned d i, uns i gned s i , uns i gned l?P, uns i gned sp, \ uns i gned bx, uns i gned dx, uns i gned cx, uns i gned ax, uns i gned i p, uns i gned cs, uns i gned flags

A· Type BiosKit

Page 104: Atbios Kit Nov89

The Kit.h File E·l·3

II This definition is the same as above except for the semi-colons in place of the commas. II It is used for snapshots.

#define snap registers \ lI"'Isigned eS;lI"'ISigned ds; unsigned di; lI"'Isigned si;lI"'Isigned t?P; unsigned sPi \ lI"'Isigned bX;lI"'Isigned dx; lI"'Isigned cx; lI"'ISigned aX;lI"'Isigned ip; lI'lsigned cs; lI'lsigned

flags;

II This is the structure of the callers save registers on the stack /1 after an into function entry

struct callers {

uns i gned es; uns i gned ds; unsigned di; unsigned si; unsigned bpi unsigned sp: uns i gned bx: uns i gned dx: uns i gned cx: uns i gned ax; uns i gned i P: uns i gned cs; unsigned flags: } ;

II This definition provides a siq)llfied means to set the interrupt vector to the service routine.

#define link_interrupt(level,name) set_vector(level,bios_cs(),name)

//--------------------------------------------------------------------------------------------------#define variables typedef struct {\ lI"'Isigned length tag: \ unsigned user ia:\ unsigned ax:\-lI"'IS i gned cx; \ unsigned dx:\ lI"'Isigned si;\ lI"'ISigned di:\ lI"'Isigned bp:\ unsigned bx: /* this is so we can do LDS ax *1 \ unsigned ds:\ unsigned es:\ unsigned flags;\ uns!gned Jq)_off;\ unslgned J~ seg:\ unsigned coOe_string[18]i 1* reserved for code string *1 \

#define end_variables lI"'ISigned char size; }

II This definition sizes the block acquire to include the variables specified II in the variable declaration

#define acquire block(id) acquire scratch block(id, \ (&myblock->size-- &myblock->lengtn tag) +-\ (16-«&myblock->size - &myblock->lingth_tag) X 16»)

11---------------------------------------------------- --II definitions of variables in data segment segment 40h

#clef ne VECTOR(nr) (*«lI"'ISigned long far *) #def ne VECTOR 00 (*«lI"'ISigned long far *) #def ne VECTOR-OO OFFSET (*«lI"'ISigned far *) #def ne VECTOR:OO:SEGMENT (*«lI"'Isigned far *)

#clef ne VECTOR 00 (*«lI"'ISigned long far *) #clef ne VECTOR-OO OFFSET (*«lI"'ISigned far *) #clef ne VECTOR:OO:SEGMENT (*«lI"'ISigned far *)

#def ne VECTOR 00 (*«l6Isigned long far *) #def ne VECTOR-OO OFFSET (*«lI"'ISigned far *) #def ne VECTOR:OO:SEGMENT (*«lI"'ISigned far *)

#clef ne VECTOR 13 (*«l6Isigned long far *) #clef ne VECTOR-13 OFFSET (*«lI"'ISigned far *) #clef ne VECTOR:13:SEGMENT (*«lI"'ISigned far *)

#def ne VECTOR 40 (*«unsigned long far *) #def ne VECTOR-40 OFFSET (*«l6Isigned far *) #def ne VECTOR:40:SEGMENT (*«unsigned far *)

4 * nr» OxOOOO»

OxOOOO»

OxOOOO»

Ox004c»

Ox0100»

OxOOOO» Ox0002»

OxOOOO» Ox0002»

OxOOOO» Ox0002»

Ox004c» Ox004e»

Ox0100» Ox0102»

Section E: The C Pro&rams

Page 105: Atbios Kit Nov89

E·l·4 The Kit.h File

#define SYSTEM SEGMENT PTR (*«unsigned far *) Ox40e» #define SWITCH-BYTE (*t(unsigned char far *) Ox410» #define EQUIP 1LAG (*«unsi9ned far *) Ox410» #define MEMORY SIZE (*«unslgned far *) Ox413» #define KB FLAn (*«unsigned char far *) Ox417» #define KB-FLAG 1 (*«unsigned char far *) Ox418» #define ALT INPUT (*«unsigned char far *) Ox419» #define BUF'ER HEAD (*«unsigned far *) Ox41a» #define BUFFER-TAIL (*«unsigned far *) Ox41c» #define KB BUF1ER (*«unsigned far *) Ox41e» #define SE£K STATUS (*«unsi9ned char far *) Ox43e» #define MOTel STATUS (*«unSlgned char far *) Ox43f» #define MOTOR-COUNT (*«unsigned char far *) Ox440» #define DISK !TATUS (*«unsigned char far *) Ox441» #define CRT RODE (*«unsigned char far *) Ox449» #define CRT-COLS (*«unsigned far *) Ox44a» #define CRT-LENGTH (*«unsigned far *) Ox44c» #define CRT-START (*«unsigned far *) Ox44e» #define CUR!OR POSN (*«unsigned far *) Ox450» #define CURSOR-NOOE (*«unsigned far *) Ox460» #define ACTIVE-PAGE (*«unsigned char far *) Ox462» #define ADOR 6845 (*«unsigned far *) Ox463» #define CRT AooE SET (*«unsigned char far *) Ox465» #define CRT-PALL!TTE (*«unsigned char far *) Ox466» #define V 01FSET (*«unsi~ned far *) Ox467» #define V-SEGMENT (*«unSlgned far *) Ox469» #define V-FLAG (*«unsigned char far *) Ox46b» #define TTMER LOW (*«unsi~ned far *) Ox46c» #define TIMER-HIGH (*«unSlgned far *). Ox46e» #define TIMER-LONG (*«unsigned long far *) Ox46c» #define TIMER-LONG MAX Ox1800bO f* 24 hour count *f #define TIMER-OFL t*«unsi~ned char far *) Ox470» #define BIOS IREAK (*«unstgned char far *) Ox471» #define RESET FLAG (*«unsigned far *) Ox472» #define HO ST~TUS1 (*«unsigned char far *) Ox474» #define HO-NUN (*«unsigned char far *) Ox475» #define HO-CONTROL (*(Cunsigned char far *) Ox476» #define LPT TIMEOUT LIST (*«unsi~ned char far *) Ox478» #define cOMR TIMEOUT LIST (*«unstgned char far *) Ox47c» #define BUFF!R START-(*(Cunsigned far *) Ox480» #define BUFFER-eNO (*«unsigned far *) Ox482» #define ROWS C-«unsigned char far *) Ox484» #define POINTS (*«unsigned far *) Ox485» #define INFO (*«unsigned char far *) Ox487» #define INFO 3 (*(Cunsigned char far *) Ox488» #define HO STATUS (*«unsigned char far *) Ox48c» #define HO-ERROR C*CCunsigned char far *) Ox48d» #define HO-INT FLAG (*«unsigned char far *) Ox48e» #define HF-CNTIL (*«unsigned char far *) Ox48f» /* 490-493-are floppy disk drive and media type bytes */ /* 494-497 are floppy disk drive current track positions */ /* kb flags 2 and 3 must be re-located if using more than 2 floppy drives */ #define KB FLAG 3 (*«unsigned char far *) Ox496» . #define KB-FLAG-2 (*C(unsigned char far *) Ox497» #define US£R FL~G (*C(unsigned far *) Ox498» #define USER-FLAG SEG (*(Cunsigned far *) Ox49a» #define RTC (OW (-(Cunsi~ned far *) Ox49c» #define RTe-HIGH (*«unstgned far *) Ox4ge» #define RTC-WAIT FLAG (*«unsigned char far *) Ox4AO» #define PRS~ BUSY (*«unsigned char far *) Ox500» #define aooT:AREA (*C(unsigned char far *) Ox7cOO»

f*=====================.== end of bfoskft.h ==================================*/

A-Type BiosKit

Page 106: Atbios Kit Nov89

The Mise File E·2·1

TWO

The Mise File

The Misc.c file contains functions which are used by various modules. Many of the functions used by the Setup and Watch commands in Sysvue reside in this file. The register snapshot routines are in here, as well as most of the support functions for the 8042 keyboard controller chip.

1*************************************************************************************************** * : Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

* Module Name: AT Bios misc. functions * * Version: 1.02 * * Author: FOSCO * * Date: 10-20-89 * * Filename: atmisc.c * * Language: MS C 5.1 * * Functional Description: * This module includes miscellaneous functions used by vadous modules. * * Arguments: * * Return: * * Version History: * 1.01 * Changed the IIcurrent video" peekb40 from Ox13 (mem size) to Ox10 (switch byte) * 1.02 : Added 8253 timer-based timeout support

***************************************************************************************************1

1* INC L U D E F I L E S *1

#include lIatkit.h"

1* FUN C T ION PRO TOT Y PES */

void eoi_sequence();

extern unsigned char type byte; extern unsigned char dec irray[6]; extern const unsigned chir hdlSk table; void pause(void); -unsigned get video(void); unsigned sena 8042(unsigned); unsigned sena-8042 data(unsigned); unsigned wait-to rx 8042(void); unsigned wait:to:send_8042(voio)i

1* L 0 CAL CON S TAN T S */

1/ these are the text words for the setup program

const display list[] = ( -

II EGA" "CGA to x 25" "CGA 80 x 25"; IIMonochrome",

}i

1* PRO G RAM S *1

1*=========== Send EOI to Interrupt Controller ==========*/ void eoi_sequence() { outportb(Ox20,Ox20)i }

1*======== Dump hex word on Console ==============*/

Page 107: Atbios Kit Nov89

E· 2·2 The Mise File

void lword(w) {lbyte(w »8)i lbyte(w)i}

1*======== Dump hex byte on Console ==============*1 void lbyte(outchar) {

}

unsigned char c; c = (outchar » 4) & OxOfi if (c > 9) c+= 7; co(c + '0'); c = outchar & OxOf; if (c > 9) c+= 7; co(c + '0');

1*======== Check for 0-9, a-f, A-F character =====*1 unsigned ishex(c) 1* returns true or false *1 {

}

if «c >= '0') && (c <= '9'» return (true); if «c >= 'a') && (c <= 'f'» return (true); if «c >= 'A') && (c <= 'F'» return (true); return(false)i

1*======== Check for a-z character ==============*1 unsigned islower(c) 1* returns true or false *1 {

}

if «c >= 'a') && (c <= 'Z/» return (true)i return(false)i

1*======== Check for a-z, A-Z character =======*1 unsigned isalpha(c) 1* returns true or false *1 {

}

if «c >= 'a') && (c <= 'Z'» return (true); if «c >= 'A') && (c <= 'Z'» return (true); return(false);

1*======== Write String on Console ==============*1 void write string(loc) { -while (peekb(bios cs(),loc) != 0) ( co(peekb(bios_cs(),loc++»i )

} -1*======== Set Interrupt Vector =============*1 void set vector(int number,seg,off) ( - -

}

disableC); poke(OxOO,int number * 4 off)· poke(OxOO,(int_number * ~) + ~,seg); enableC);

1*======== Read CMOS Ram ============*1 unsigned char incmos(unsigned address) ( outportb(Ox70,address I Ox80); return(inportb(Ox71»;

}

1*======== Write CMOS Ram ============*1 void outcmos(unsigned address,unsigned char value) ( outportb(Ox70,address I OxSO); outportb(Ox71,value);

}

1*======= return true if (type == ar9) =======*1 /I If you wish to dynamically deternl1ne the kind of machine, then these functions will check II the type byte. /I To determine CPU type, expand this f\J'lCtion with CPU testing.

II check for motherboard type

unsigned type(unsigned int arg) ( if«arg == at) II (arg == xt» ( if «arg == xt) && (peekbcs(&type_byte) == xt»\ return(true); if «arg == at) && (peekbcs(&type_byte) == at»\ return(true);

A-lYRe BiosKit

Page 108: Atbios Kit Nov89

}

if«arg == 86) I I (arg == 186) II (arg == 286) II (arg == 386»11 check for cpu type (

return(false); } return(false);

}

11=========================================================

#define swapped 1 II in myblock->status, this tells if stack is swapped

extern unsigned start block; extern unsigned current open; extern unsigned end block; extern unsigned watCh_flag;

variables end_variables pool regs;

1/ block size is passed as nunber of bytes needed.

unsigned acquire scratch block(unsigned id,unsigned block_size) ( --poolregs *block-ptr; setds system segment(); disabTe(); -if «current open + block size) < end_block) ( - -

}

II this open space is allocatable blocK-ptr = current ~; current open += block size· blocK-ptr -> length tig = block size; blocK-ptr -> user_ia = id; -

enable(); if«id & (watch flag & (WATCH MASK») 1= 0) ( - -write string("\n\rAcquire Block II); lword(blocKJ)tr); if(ia== FLOPPY) write string(1I Floppyll); if(id == HARD) write string(" DisK"); if(id == BOOT) write-string(" Boot"); if( id == CASSETTE) write string(" Cassll ); if(id == EQUIPMENT) writi string(" Equi"); if(id == MEMORY) write string(" Memll ); if( id == LPT) write string(" Lpt"); if(id == CC»1) write-string(" CornU); if(id == TOD) write-string(" Tod")· if(id == KEYBOARD) write string(" Kbll );

} -return(blocK-ptr );

II acquire the start block so we can flag system error current ~ = start blocK· sys errtOx1111); II this is an arbitrary code ena6leO; return(current open); II this is an error condition

} -

void release block(poolregs *block ntr) (_ ...r

~f«blockJ)tr ->user_id & «WATCH_MASK) & watch_flag» 1= 0)

write string("\n\rRelease Block II); lword(blocKJ)tr); if(blOcKjptr -> user id == FLOPPY) write strlng(" Floppy")· if(blOcKJ)tr -> user id'== HARD) write string(" DisK"); if(blocKJ)tr -> user-id == BOOT) write-string(" Boot"); if(blocKjptr -> user-id == CASSETTE) -write strlng(" Cass"J· if(blOcK-ptr -> user td == EQUIPMENT) write string(" EquillJ. if(blOcKJ)tr -> user td == MEMORY) write string(" Memll ); if(blocKJ)tr -> user-id == LPT) write string(" Lpt"); if(blocKJ)tr -> user-id == CC»1) write-string(" Com"); if(blockJ)tr -> user-id == TOD) write-string(" Tod"); if(blocKJ)tr -> user:id == KEYBOARD) write_string(1I Kbll );

The Mise File E·2·3

}

disable(); II If you wish to zero out the released blocK, then a clear blocK function could be 'created here.

Section E: The C Pro&rams

Page 109: Atbios Kit Nov89

)

E· 2·4 The Mise File

II clear_block(block-ptr,blocK-ptr .> length_tag);

blocK-ptr .> length tag = 0; current open = blocK-ptr; enable(J';

11-······_- register snapshots .••• _ .• -._--.--

/I this will execute if the "watch lt bit for the specified device is set

void snapshot in(unsigned device, struct callers far * frame) ( -

)

if(watch(device» ( write string("\n\rax="); lword(frame->ax); write-string(" bx=It); lword(frame->bx); write-string(" cx=")· lword(frame->cx); write-string(" dx=II)~ lword(frame->dx)i wri te-string(" Sp=II) ~ lword(frame·>sp); write-string(" bt?="): lword(frame->bj?)" write-string(" Si=II)! lword(frame->si)! write:string(" di="); lword(frame->di);

write string(lI\n\rds="); lword(frame->ds); write-string(" es="); lword(frame->es)i write-string(" ss="); lword(&frame->es + 1); /I this = old ss write-string(" cs="); lword(frame->cs); wr!te:str!ng(" ip=II); lword(frame->ip); wrlte strlng(" II). if(device == FLoppy)'write string(" FLOPPY II); if(device == HARD) write st'ring(" DISK II); if(device == BOOT) write-string(" BOOT II); if(device == CASSETTE) write string(" CASS II); if(device == EQUIPMENT) write string(" EQUI II); if(device == MEMORY) write string(" MEM II); if(device == LPT) write string(1I LPT II); if(device == COM) write-string(" COM II); if(device == TOO) write-string(It TOO II); if(device == KEYBOARD) write string(It KB It);

) -

void snapshot out(unsigned device,struct callers far *frame) ( -

)

if(watch(device» ( write string(It\n\rax="); lword(frame->ax); write-string(It bx="); lword(frame->bx); write-string(It cx="); lword(frame->cx); wri te-stri{'lg(It dx=")· lword(frame->dx)· write-string(It Sp=II)! lword(frame·>sp)! write-string(" bt:>=")! lword(frame->bj?)! write-string(It si=")! lword(frame->si)! write:string(" di="); lword(frame->di);

write string("\n\rds=II); lword(frame->ds); write-string(" es=")· lword(frame->es)" write-string(" ss="); lword(&frame->es'+ 1>; write-string(" cs=")· lword(frame->cs)" write-string(" ip=It)! lword(frame->ip)! write-string(" Carr~"); lword(frame->hags & Ox01>;

) -

void watch string(unsigned device,unsigned msg) ( -

if(watch(device» write string(ms9)i ) -void watch word(unsigned device, unsigned msg) ( -

if(watch(device» lword(msg)i ) . void watch byte(unsigned device, unsigned msg) ( -if(watch(device» lbyte(msg);

)

void watch char(unsigned device, unsigned msg) ( -if(watch(device» co(msg);

)

11==================================================

A-Type BiosKit

Page 110: Atbios Kit Nov89

II these will execute only in the cold-boot condition II they will not execute for wanm-boot

void cold string(unsigned msg) ( -

if(cold(» write string(msg); } -void cold word(unsigned msg) ( -

if(cold(» lword(msg); }

void cold byte(unsigned msg) ( -

if(cold(» lbyte(msg); }

void cold char(unsigned msg) ( -

if(cold(» co(msg); }

11============ set the timer counter on boot up ============

#define seconds 0 #define minutes 2 #def i ne hours 4

#define counts sec 18 #define counts-min 1092 #define counts:hr 60 * counts_min

uns i gned long llllJ l (uns i gned long, uns i gned) ; unsigned convert_binary(unsigned char);

unsigned set count(void) { -

}

unsigned char temp; unsigned long count, long_temp;

if «temp = incmos(hours» > Ox23) return(error); long_temp = convert_binary(temp); count = llllJl(long_temp,counts_hr)i

if «temp = incmos(minutes» > Ox59) return(error)i long_temp = convert_binary(temp)( count += lmul(long_temp,counts_mln)i

if «temp = incmos(seconds» > Ox59) return(error); long_temp = convert_binary(temp); count +=lmul(long_temp,counts_sec);

TIMER LONG = count; retur;;(ok);

1*=================================================== Return the drive type for a specified drive. drive 00-03 = floppy drive 80-81 = hard

----------------------------------------------------*1 unsigned char cmos drive type(unsigned char drive nr) ( - - -switch(drive nr) ( -case 0: return(incmos(Ox10) » 4): case 1: return(incmos(Ox10) & OxOf); case 2: return(incmos(Ox11) » 4): case 3: return(incmos(Ox11) & OxOf); case Ox80: if«incmos(Ox12) » 4) == 15) return(incmos(Ox19»; return(incmos(Ox12) » 4);

case Ox81: if«incmos(Ox12) & 15) == 15) return(incmos(Ox1a»; return(incmos(Ox12) & OxOf);

} returneO);

}

11========== return the cmos system memory size =====

The Mise File E-2-S

Section E: The C ProlUams

Page 111: Atbios Kit Nov89

E·2·6 The Mise File

unsigned cmos mem() { -

}

uns i gned teq'); temp = incmos(Ox16); temp = t~ « 8; temp 1= incmos(Ox15); return(t~);

11========== return the cmos extended memory size ===== unsigned cmos ext() { -

}

unsigned t~; temp = incmos(Ox18); temp = t~ « 8; temp 1= incmos(Ox17); return( t~) ;

1/==== return the cmos extended found memory size ===== unsigned cmos ext found() { - -

}

uns i gned teq')i temp = incmos(Ox31); temp = temp « 8; temp 1= incmos(0x30)i return(t~);

// ---- display the time ----------­variables end_variables timevars;

void display time(void) { -timevars *myblock; myblock = acqui re block(VUE); myblock ->ax = Ox0200; sys int(Ox1a,myblock)· co({(myblock->cx » 1~) & OxOf) I '0'); co«(myblock->cx » 8) & OxOf) 1 '0'); co(':')· co«(~lock->cx » 4) & OxOf) I '0'); co«(myblock->cx ) & OxOf) '0'); co(':')· co«(~lock->dx » 12) & OxOf) I '0'); co«(myblock->dx » 8) & OxOf) I '0');

}

// ---- display the date ----------­variables end_variables datevars;

void display date(void) { -datevars *myblock; myblock = acquire block(VUE); myblock ->ax = OX0400i sys_int(Ox1a,myblock)i

}

co«(myblock->dx » 12) & OxOf) I '0'); co«(myblock->dx » 8) & OxOf) I '0'); co('/')· co«(~lock->dx » 4) & OxOf) I '0'); co«(myblock->dx ) & OxOf) '0'); co(' /'). cO«(mYblock->cx » 12) & OxOf) I '0'); co«(myblock->cx » 8) & OxOf) I '0'); co«(myblock->cx » 4) & OxOf) '0'); co«(myblock->cx ) & OxOf) '0');

// this is the text list for the floppy drive types const drive list[] = { -

"No Drive", "360k", "1.2MII, "nOk", "1.44MII , "Unknown", /* "2.88M could go here if ill1llemented */ "Unknown",

A· Type BiosKit

Page 112: Atbios Kit Nov89

"Unknownll ,

};

11------- display the disk drive configuration -----­

void display drives(void) ( -unsigned next hard = 'C'; II the letter-code of the next hard drive

II find the number of floppy drives if«incmos(Ox14) & Ox01) 1= 0) {

}

if (cmos drive type(O) 1= 0) ( - -write string("\n\r Drive A: II).

}write:string(peek(biOS_CS(),&driVe_l1sttcmos_drive_type(0)]»;

if«(incmos(Ox14) » 6) & Ox03) > 0) {

}

if (cmos drive type(1) 1= 0) ( - -write string("\n\r Drive B: II).

}write:string(peek(biOS_CS(),&drive_lfsttcmos_drive_type(1)]»;

if«(incmos(Ox14) » 6) & Ox03) > 1) {

}

if (cmos drive type(2) != 0) ( - -write string("\n\r Drive C: II). write-string(peek(bios cs(),&drive l1sttcmos drive type(2)]»;

} - - - --if«(incmos(Ox14) » 6) & Ox03) > 2) {

}

if (cmos drive type(3) 1= 0) ( - -write string("\n\r Drive D: II).

}write:string(peek(biOS_CS(),&driVe_l1sttcmos_drive_type(3)]));

The Mise File E·2· 7

II The letters used for the disk drives can change depending on the number of floppy drives in the II system. Find the number of floppy drives

}

if«incmos(Ox14) & Ox01) 1= 0) (

if«(incmos(Ox14) » 6) & Ox03) > 1) next hard++; if«(incmos(Ox14) » 6) & Ox03) > 2) next~ard++;

} -if (cmos_drive_type(OxSO) 1= 0) ( write string("\nV Drive II); co(next_hard); write:string(": Type II);

II this should be printed in decimal II lbyte(cmos drive type(OxSO»;

} --if (cmos_drive_type(Ox81) 1= 0) ( write string("\n\r Drive II); co(next_hard+1); write:string(": Type II);

1/ this should be printed in decimal II lbyte(cmos drive type(Ox81»;

} --1*--------- display video type ------------*1 void display video(void) ( -write string("\n\r Default Video: II); write:string(peek(bios_cs(),&display_listCget_video()]»;

wrHe string("\n\rExpected Video: II); write:string(peek(bios_cs(),&display_listC(incmos(Ox14) » 4) & Ox03]»;

write_string("\n\r Current Video: II);

Section E: The C ProlUams

Page 113: Atbios Kit Nov89

E·2·8 The Mise File

/*--------- calculate cmos checksum -------------*/ unsigned calc cmos(void) ( -

}

unsigned j,x sum = 0; x = (incmos(6x2e) « 8) I incmos(Ox2f)i for(j=Ox10ij<=Ox2d;j++) sum += incmos(J): outcmos(Ox~e,sum » 8); outcmos(Ox2f,sum); return(x);

/*----------- display sys mem size -----------*/

display sys mem() ( --bin2dec(cmos mem(),&dec array); co(dec arraylO]); -co(dec-array[1]); co(dec-array[2]); co(dec-array[3]): co(dec-array[4]);

} -/*----------- display ext mem size -----------*/

display ext mem() ( --bin2dec(cmos ext(),&dec array); co(dec arraylO]): -co(dec-array[1]); co(dec-array[2]): co(dec-array[3]): co(dec-array[4]);

} -/*----------- set sys mem size -----------*/

set sys mem(unsigned sys size) ( - - -outcmos(Ox15,sys size); outcmos(Ox16,sys:size » 8); calc cmos 0 ;

} -/*----------- set ext mem size -----------*/ set ext mem(unsigned ext size) ( - - -outcmos(Ox17,ext size); outcmos(Ox18,ext:size » 8); calc cmosO;

} -/*== return the number of floppy drives in the system ==*/

unsigned number of floppies(void) ( - -

}

if «incmos(Ox14) & Ox01) == 0) return(O): return«incmos(Ox14) » 6) + 1);

/*==== display hard disk table parameters ====*/

void display hdisk types(void) ( --unsiened qq,jk cyls,heads,sectors approx size: // llSt the ta6le entries, calc t~e approximate disk size // use the sectors/track to accomodate the RLL drives /I format is: // type, cyls, heads, sectors, size write_string(ItType Cyl inders Heads Sectors Size\n\rlt):

jk = 0: qq=1· while(peek(btos cs(),jk+&hdisk table) 1= -1) ( - -// display drive type bin2dec(qq,&dec array): co(dec array[2]1; co(dec:array[3]): co~dec_array[4]): wrlte_strlng(11 II):

A-Type BiosKit

Page 114: Atbios Kit Nov89

II display cylinders cyls = peek(bios_cs(),jk+&hdisk_table); bln2dec(cyls,&dec_array); co(dec array[O]); co(dec-array[1]); co(dec-array[2]); co(dec-array[3]); co(dec-array[4]); wrHe_itring(1I II);

/I display heads heads = peekb(bios cs(),jk+2+&hdisk table); bin2dec(headS

6&dec:array); -

co(dec array[ ]); co(dec-array[1]); co(dec-array[2]); co(dec-array[3]); co(dec:array[4]);

write_string(1I II);

/1 display sectors sectors = peekb(bios csO,jk+14+&hdisk table); bin2dec(sectors,&dec-array); -co(dec array[O]); -co(dec-array[1]); co(dec-array[2]); co(dec-array[3]); co(dec:array[4]);

write_string(1I II);

II display size (cyls*heads*sectors) in Mbytes

approx_size = calc_hdisk_size(cyls,heads,sectors);

bin2dec(approx size,&dec array); co(dec_array[Or); -co(dec_array[1]); co(dec array[2]); co(dec-array[3]); co(dec:array[4])i

write_string(lI\n\r");

~+. JK =' jk + 16· 1/ look to next table entry if«qq & Ox060f) == 0) ( pause()i write string("Type Cylinders Heads Sectors Size\n\r");

} -}

}

1*---------- pause and wait for key ---------*/

void pause(void) { while(kbhit(»{ci()i}; /1 get any ~ing keys write string(" ---- hit any key for more ----\n\r")i while{lkbhit(»{};

}

1*--------- display NPX status -----------*/

void display npx(void) ( -write string("Exp4]!Cted: II). if«incmos(Ox14) & Ox02) =~ 0) ( write string(INo")·

} - , else ( write string(IIYes ll ).

} - , write string(" FoU'ld: II). if«SOITCH BYTE & Ox02) == 6) ( -write string("No")· } - ,

else ( write string(IIYesll ).

} - ,

The Mise File E·2·9

Section E: The C ProlUams

Page 115: Atbios Kit Nov89

E·2·10 The Mise File

}

11-------- return a long timeout count -----------

II - returns a long TIMER LONG + count( corrects for 24 hour rollover II - if rollover near, then delay unti rollover, then return count

unsigned long get current timer(void) ( --return(TIMER LONG); } -unsigned long set timeout count(l.I1signed COU'lt) ( --while«get_current_t!mer() + count) > TIMER_LONG_MAX); return(get current tlmer() + count);

} - -11---------- keyboard controller support -------

/*=================================================1 The 8042 keyboard controller uses ports Ox60 and Ox64. Ox60 = data in and out Ox64 = status in. The status bits are: Bit Description 7 Parity error 0 = odd (no error), 1 = even 6 rx timeout 1 = error 5 tx timeout 1 = error 4 inhibit 0/1 = inhibit/not inhibited 3 datalcommand port 60 = datalcommand 2 system flag 0= powerup, 1= reset 1 inp bfr full 0/1 = empty/full o out bfr full 0/1 = empty/full

8042 commands (to port 64):

Ox60 write next byte (Ox64) to controller: (use Ox4S) Bit Description 7 always 0 6 1 = PC c~tibility mode 5 1 = PC moc:Ie 4 1 = disable keyboard 3 1 = inhibit override 2 0 = reset system flag 1 always 0 o 1 = enable out bfr full into (IRQ1)

Oxaa self test 8042 returns Ox55 in out bfr (Ox6O) if OK .

xOcO read 8042 i~t port into out bfr (Ox60) bit Description of input port 7 0/1 = keylock switch locked/not locked 6 0/1 = CGA/MOA vidoe j~r 5 0/1 Mfg Jumper present/absent 4 0/1 system ram = 512/256 K

Oxd1 write next byte (Ox64) to controller bit Description 7 kb data out line 6 kb clock out line 1 Gate A20 o 1 = reset system

/==================================================*1 11------- reset the 8042

unsigned reset 8042() ( -unsigned stat = ok; /1 mask out interrupts in case they are still enabled outportb(Ox21£inportb(Ox21) I Ox02); II purge the 0042's output bUffer inportb(Ox60)· 1/ reset the A042 if(wait to send 8042() == error) stat = error; if(send!~2(Oxia) == error) stat = error; if(wait-to rx 8042() == error) stat = error; if(inportbtOx!O) != Ox55) stat = error; /1 configure 8042 if(wait to send 8042() == error) stat = error; if(se~8Gt2(Ox50) == error) stat = error;

A· Type BiosKit

Page 116: Atbios Kit Nov89

}

outportb(Ox60,Ox45); outportb(Ox21,inportb(Ox21) & -Ox02); return(stat)i

//----- this gets the video jumper byte from the 8042 ---­

// returns 2 = CGA, 3 = MDA

unsigned get video() ( -

}

unsigned t~ = OJ outportb(Ox21 Linportb(Ox21) I Ox02); wait to send o042(); senc:r8Q7;2(OxCO)i /I read the jumper conmand wait-to rx 8042(); temp-= TnpOrtb(Ox60)" outportb(Ox21,inportb(Ox21) & -Ox02)i if «temp & Ox40) == 0) return(2)i // return CGA index value, else return(3)i // return MDA index value

1/---- wait until 8042 ready to accept another byte ---­

unsigned wait to send 8042() { - - -

unsigned long jj = set_timeout_count(20)i // 1 second delay

The Mise File E-2-11

do ( if«inportb(Ox64) & Ox02) == 0) return(ok); } while (TIMER_LONG < jj); return(error);

}

1/--- wait for 8042 output buffer to be loaded ---­

unsigned wait to rx 8042() ( - - -unsigned long jj = set_timeout_count(20); /1 1 second delay

do ( if«inportb(Ox64) & Ox01) != 0) return(ok)i } while (TIMER_LONG < jj); return(error);

}

11--- send a conmand and wait until accepted --­

unsigned send 8042(value) ( -outportb(Ox64,value); return(wait to send 8042(»i

} - - -11--- check buffer ready and send· data

unsigned send 8042 data(value) { --unsigned trys = 10; while (trys-- > 0) (

if(wait to send 8042() == ok) { outportb(Ox60,value)i return(ok)i } } - - -return(error);

}

Section E: The C Pro&rams

Page 117: Atbios Kit Nov89

Things Worth Making A Note Of

Page 118: Atbios Kit Nov89

The Pod File E·3·1

THREE

The Pod File

The Pod.c (Power On Diagnostics )file contains power-up diagnostics and initializing routines. This file inits some of the peripherals and also calls the setups for most of the other function calls. A general convention to develop (it has been implemented for some cases) is to examine the status returned from a function call setup routine. to determine the degree of success in initializing a device (such as video, disk, keyboard, etc.) This returned status can then be used to display' an enhanced message during the POD.

/*************************************************************************************************** * : Copyright (c) FOSCO 1988 - All Rights Reserved

: Module Name: AT bios power on diagnostics

* Version: 1.01 * * Author: FOSCO * * Date: 12-31-88 * : Filename: biospod.c

* Language: MS C 5.1 * : Functional Description:

* This module does the power on diagnostics and initialization. When it finishes, it does : a bootstrap to load the system.

* Argunents: * * Return: * * Version History: : Added NMI disable bit to the read_swtiches function.

***************************************************************************************************/

/* INC L U D E F I L E S */

#include "atkit.h"

/* FUN C T ION PRO TOT Y PES */

void biospod(void); unsigned comm setup(void); unsigned lpt setup(void); void biospOdfvoid);

unsigned xchg(unsigned,unsigned,unsigned); unsigned ram test(unsigned segment,unsigned length); void move system segment(unsigned,unsigned); unsigned Char reid switches(void); unsigned rom checkfunsigned); void cout(unsigned char); unsigned checksum(unsigned,unsigned,unsigned); unsigned cold(void)i

/* G LOB A L V A R I A B L E S */

extern unsigned start block; extern unsigned current open; extern unsigned end block; extern unsigned blOCk beg; extern unsigned block:end;

variables end_variables podregs;

/* G LOB A L CON S TAN T S */

extern Siret;

Page 119: Atbios Kit Nov89

E·3·2 The Pod File

extern ~ isr; extern divide; extern bios id; extern date-stamp; extern bios:start;

1* L 0 CAL D E FIN I T ION S *1

#define pio~rt b Ox61 #define default equip OxOO6d #define boot retrys 6 #define dna OxOO #define inta01 Ox21 #define timer controlJ)Ort Ox43 #define timer-counter-o-POrt Ox40 #define timer-counter-2-POrt Ox42 #define port 5 Ox61 -#define cr - 13 #define escape 27 #define carry_bit Ox0001

1* PRO G RAM *1

II Biostop module already has found 64k of ram to operate with.

void biospod(void) { podregs *myblock; unsigned ext mem size = 0; uns i gned duIiiiy, -rom scan end, 1* end segment value for rom scan *1 i,r; -cs, 1* save for code segment value *1 error code; 1* temp save for returned error codes *1 uns i gfied cnar checksun; unsigned video status; II returned from video setup unsig~ equipment_status; II returned from equip setup cs = bl0S_CS()i

1* use top of 1st 64k for system segment *1 SYSTEM_SEGMENT_PTR = Ox1000·(sys_seg_size » 4);

1* set pool delimiters *1 setds system segment(); start~lock = current open = &block beg; end_bTock = &block_ena; -

1* set the equipment switch flag *1 SWITCH_BYTE = read_switches()i

1* load default interrupt vectors */'

for(i=0,j=0;i<31;i++,j+=4) { poke(OxOOOO,j,&Siret); /* load software defaults */ 1* override hardware defaults */

}

if «i >= 8) && (i <= 16» poke(OxOOOO,j,&Sdummy isr); poke(OxOOOO,j+2,cs); -

/* load default interrupt vectors for 8259 #2 */

for(i=0,j=Ox70*4;i<8;i++,j+=4) {

}

poke(OxOOOO,i,&Sdummy isr); poke(OxOOOO,J+2,cs); -

/* div by zero interr~t */ poke(OxOOOO,OxOOOO,&divide);

/* .•••.•• setup the 8255 if one exists ••••.••••.•• */

outportb(Ox63,Ox99)· /* set the control register */ outportb(port_b,Ox76)i /* disable the parity checkers */

1*·········· setup the dma controllers ..•.• _ .. _*/

#define DNA1 OxOO #def i ne DNA2 OxcO

outportb(DMA1+8 Ox04); // disable dma #1 outportb(DMA2+1&,Ox04); // disable dma #2

outportb(DMA1+13,OxOO); // master clear outportb(DMA2+26,OxOO);

A-Type BiosKit

Page 120: Atbios Kit Nov89

outportb(DMA1+8 OxOO); // now do dma setup outportb(DMA2+1A,OxOO);

outportb(DMA1+11,Ox40); // set the channel defaults outportb(DMA2+22,OxcO); outportb(DMA1+11,Ox41); outportb(DMA2+22,Ox41); outportb(DMA1+11,Ox42); outportb(DMA2+22,Ox42); outportb(DMA1+11,Ox43); outportb(DMA2+22,Ox43);

outportb(DMA2+20,OxOO); // enable cascade of chI 0

/*------- setup the 8259 interrupt controller -------*/

outportb(Ox20,Ox11); // icw1 outportb(Ox21,Ox08); // icw2 outportb(Ox21,Ox04); // icw3 outportb(Ox21,Ox01)i // icw4 outportb(Ox21,Oxff); // disable all interrupts

outportb(OxaO,Ox11); // icw1 outportb(Oxa1,Ox70); // icw2 outportb(Oxa1,Ox02); // icw3 outportb(Oxa1,Ox01)i // icw4 outportb(Oxa1,Oxff); // disable all interrupts

/* allow any stray interrupts to be reset */ enableO;

/*------- setup adapters and peripherals ------------*/

equipment status=equipment setup(); video_status=video_setup();

write string("\n\rll );

write-string(&bios id); write:string(&date:stamp);

The Pod File E-3-3

// If a restart sequence is generated which we do not recognize, we abort to a regular re-boot, // and display the unknown restart code. if(incmos(OxOf) != 0) // invalid restart code ( write string("\n\rlnvalid Restart Code -");lbyte(incmos(OxOf»;

} -cold string("\n\rBios at ••••••••••••• "); cold word(bios cs(»; colastring("\n\rLow 641C Ram Test •••••• 11); - -if(peek(OxOO,Ox412) == 0) // check low-ram error flag ( cold_string(IIOICII );

} else ( cold_string(IIErro,.II);

} cold string("\n\rVideo FU'1Ction •••••••• "); colastring(IIQlCII). colastring("\n\rEquipment FU'1Ction •••• 11); colastring(IIQICII); colastring(lI\n\rlCeyboard FliM:t i on ••••• 11); if(kiyboard setup() == ok) ( -cold_string(IIQlCII);

} else ( cold_stri ng(IIErrorl');

} enableO c cold strlng("\n\rSysVue •••••••••••••••• 11); sysvue_setupO; colastring(IIQlCII); colastring("\n\rMemory Size Function •• "); mem_size_setupOi colastring("OICII)i colastring("\n\rTimer Function •••••••• "); timer setupO; colastring(IIQlCII). -colastring(lI\n\rTime of Day Function •• II ); time of day setupO; if(sit count() == ok) // set the timer counter- - -( -cold_string(1I01C1I );

} else {

Section E: The C ProlUams

Page 121: Atbios Kit Nov89

E·3·4 The Pod File

cold_string(IIError"); } cold string("\n\rPrint Screen •••••••••• "); print_screen_setupO; colastring(II01(II); . colastring("\n\rCassette FlI1Ct1on ••••• "); cassette_setupO; colastri ng(IIOI(II). colastring(ll\n\rBootstrap F\.I"lCtion •••• "); boot_setupO; colc(string(II01(II);

1* enable speaker */ outportb(pio-POrt_b,inportb(pio-POrt_b) & -Ox03);

1*---------- setup timer 0 for the rtc ----------*/ outportb(timer control-PQrt,Ox36); outportb(timer-counter-O-POrt,Oxff); outportb(timer-counter-O-POrt,Oxff); outportb(Ox21,lnportb(OxZ1) & -Ox01); 1* enable the rtc */

1*---------- setup timer 2 for the beeper ----------*1 outportb(timer control-POrt,Oxb6)' outportb(timer-counter-Z-POrt,Ox3~); outportb(timer:counter:2-POrt ,OxOS);

/*-----------------------------------------------------Si ze and Test Ram - from 64K up to 640K

-------------------------------------------------------*/ cold_string(lI\nll);

for (i = 64; (i < 640) && (ram test(i « 6,32768) == ok); MEMORY_SIZE = += 64); ( -cold string("\rRam Test at •••••••• 1I);cold word(i « 6); colc(string(11 - OK II); -

}

/1 Now reset the sys segment to the top of ram. The function will copy the Of80h block to // the system segment then reset the stack segment register to it, then do a return.

MEMORY SIZE = (i = MEMORY SIZE - sys seg size/1024); move system segment(i « ~,sys seg slze); colc(string'flt\n\rSystem Segment at7 .... );cold_word(i«6);

1*-------------- now test ram above 1Meg --------------*/ II extended mem test returns ok/error // if ok - size is in cmos(30 and 31)

':iri te_string( II\n"); 1f (test ext mem() == ok) ( --ext mem size = incmos(Ox31) « 8 I incmos(0x30); if(ixt mem size == 0) ( --cold string("\rExtended Ram Not Found");

} -else { for (i = O;i <= ext mem size;; +=64) ( - -cold string("\rExt Ram at •••••••• 1I);cold word«i » 4) + Ox1000); colastring("O")' -colastring(11 - OK II).

} - , }

} else (

}

if(inportb(OxSO) < Ox80) ( cold string("\rError on AZO Control ••• ");

} -else ( cold stri~(II\rException Error ••••• 11); cold[byte(lnportb(OxSO) & -OxSO);

} -

/*-------- do a checksum on the rom bios prom ----------*/ cold string("\n\rRom checksum •••••••••• "); checKsum = checksum_bios_block();

A-Type BiosKit

Page 122: Atbios Kit Nov89

if (checlesll1l == 0) cold stdng(IIOK"); else -( write string("Error II); lbytercheclesll1l);

}

1* enable timer and kb interrupts *1 outportb(Ox21,inportb(Ox21) & Oxfc);

1*--------- setup the comm and lpt ports --------------*1 cold string("\n\rCOM Function •••••••••• II ); cOllln_setup(); colcCstring(IIOKII);

cold string("\n\rLPT Function •••••••••• II ); If)t_setup(); colcCstring(IIOK");

1*-------- check for game port ------------*1 if «inportb(Ox0201) & OxOf) == 0 ) EQUIP_FLAG 1= Ox1000;

1*----------------------------------------------------setup the floppy disk controller

-----------------------------------------------------*I cold string("\n\rFloppy Disk ••••••••••• "); if (Tdisk setup() == ok) ( -cold_string(IIOKII);

} else ( cold string(IOK")'

} - ,

1*--------------------------------------------------------setup the hard disk controller

;----------------------------------------------------- --*1 cold string("\n\rHard Disle Check ••••• "); if«error code = hdisk setup(» == ok) ( - -cold string(" •• OK");

} -else ( cold word(error code);

} - -I*--------------------------~--------------------------

The Pod File E·3·5

Check for optional rom modules from c8000 -> beginning of bios in 2k increments. A valid module has'55aa' in the first 2 locations, length indicator (length/512) in the 3rd location, and test/init. code starting in the 4th location. These modules may adjust the mem size downward to reserve scratch ram memory.

------------------------------------------------------ --*1 rom scan end = &bios start; rom:scan:end = (rom_scan_end » 4) 1 OxfOOO;

cold string("\n\rScan Rom from II); colaword(Oxc800); cold stdng(1I to II); colcCword(rom_scan_end); cold_string("\n\r");

I I for debuggi ng f I Ilrom scan end = OxdOOO; II keeps from re-loading ourself II rom-scan logic has problem with >= 64k blocks I!

for (i=Oxc800;i<rom_scan_end ;i = rom_check(i»;

cold_string("\n\rRom scan cCll11llete")i

1*---------------------------------------------------- --*/ 1* re-enable the rtc in case scan module disabled it */ outportb(Ox21,inportb(Ox21) & -Ox01);

1*=-=-=-=-=-= now do the boot =-=-=-=-=-=-=-=-=*1

Section E: The C ProlUams

Page 123: Atbios Kit Nov89

E·3·6 The Pod File

cold_string("\n\r>-------- Booting System -----------<\n\r\n");

myblock = acquire_block(POO);

while (0==0) // stay in this loop forever ( /* make sure kb interrupt is enabled */ outportb(Ox21,inportb(Ox21) & -Ox02); enableO; beep(); write_string("\n\r"); sys int(Ox19,myblock)i // try boot from boot module sys-int(Ox18,myblock); // try booting to SysVue

} -release_block(myblock)i

}

/*=====================================================*/

unsigned xchg(unsigned segment, unsigned address,unsigned value) (

}

register i,j; i = peek(segment,address); poke(segment, address, value); j = peek(segment,address); poke(segment,address,i); return (j);

/*----- read the cmos dipswitch -------------*/

char read switches() ( -outportb(Ox70,Ox94); return(inportb(Ox71»;

} /*-------------------------------------------------------*/

unsigned rom check( address) ( -unsigned length,next address; /* if not a modUle return next address */

if(peek(address,O) 1= Oxaa55) return(address + OxSO); 1* get length to checksum */ length = peekb(address,2)*512; // blocks are 512 bytes next_address = address + (length » 4);

if (checksum(address,length) == 0) (

}

if(address 1= bios cs(» /1 don't call ourselves III ( -cold string("\n\rRom Signature found at : II); cold_word(address)i far call(address,3)i

} -return(next address);

} -unsigned warm(void) {

}

if (RESET FLAG == Ox1234) return(true); return(faTse)i

unsigned cold(void) {

}

if (RESET FLAG 1= Ox1234) return(true); return(faTse)i

A-Type BiosKit

Page 124: Atbios Kit Nov89

The Equipment Driver E·4·1

FOUR

The Equipment Driver

The Equipment Configuration Driver is an Interrupt Function Call (Ox!!) that is used by DOS and other programs to determine the options which are present in a system. It is called with no input parameters and returns a value in the AX register describing the system options. The POD reads the configuration dipswitch and stores this value along with an adapter configuration byte into the word at 0040:0010.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * : Module Name: AT Bios equipment function

* Version: 1.01 * * Author: FOSCO * * Date: 10-20-89 * : Filename: biosequi.c

* Language MS C 5.1 * : Functional Description:

* Interrupt Ox11 - get equipment, configuration * : This function call returns an equipment configuration word.

: The equip_flag variable is set during the power on.

: Returns the Equipment Word in AX:

* Bit Description * 15,14 number of printers attached * 13 = 0 * 12 = 1 = game port attached * 11,10,9 number of rs232 cards attached * 8 = 0 * 7 6 number of diskette drives * 00=1, 01=2, 10=3, 11=4 only if bit 0 = 1 * 5 4 initial video mode * 60 - no video adapter * 01 - 40x25 bw using color card * 10 - 80x25 bw using color card * 11 - 80x25 bw using bw card * 3,2 not used * 1 0/1 = no 8087/8087 : 0 0/1 = boot from int 18/floppy disk

* Argunents: * None * * Return: : Equi pment word in AX

* Version History: * 1.01 : Replaced peeks and pokes with casts

***************************************************************************************************/

/* INC L U D E F I L E S */

#include "atki t.h"

unsigned equipment setup(void)i void interrupt cdecl far equipment(interrupt_registers)i

/* G LOB A L S */

extern _equipment;

Page 125: Atbios Kit Nov89

E·4· 2 The Equipment Driver

/* L 0 CAL 0 E FIN I T ION S */

/* PRO G RAM */

unsigned equipment setup() { -

}

link_interrupt(Ox11,&_equipment)i return(ok)i

void interrupt cdecl far equipment(interrupt_registers) { ax = EQUIP FLAGi

} -

A· Type BiosKit

Page 126: Atbios Kit Nov89

The Memory Size Driver E-5-1

FIVE

The Memory Size Driver

The Memory Size Driver is an Interrupt (Ox12) Function Call that is used by various programs (including DOS) to determine how much RAM is in the system.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * * Module Name: AT Bios memory size function * * Version: 1.01 * * Author: FOSCO * * Date: 10-20-89 * * Filename: atmem.c * * Language: MS C 5.1 * : Functional Description:

* Interrupt 12h - get memory size * * This function call returns the amount of System RAM in AX. * The value indicates the number of 1024 byte blocks of RAM. * * Arguments: * None * * Return: * Mem size in AX * * Version History: * 1.01 : Replaced peeks and pokes with casts

***************************************************************************************************1

1* INC L U D E F I L E S *1

#include "atkit.h"

1* FUN C T ION PRO TOT Y PES *1

unsigned mem size setup(void)i /1 called by pod to set the interrupt vector to the service routine void interrupt cdicl far mem_size(interrupt_registers)i /1 returns the mem size in 1kbyte blocks

/* G LOB A l S *1

extern _mem_sizei

1* 0 E FIN I T ION S */

1* PRO G RAM *1

unsigned mem size setup() { --

}

link_interrupt(Ox12,&_mem_size)i return(ok)i

void interrupt cdecl far mem_size(interrupt_registers) { ax = MEMORY SIZEi

} -

Page 127: Atbios Kit Nov89

Things Not Worth Writing Down

Page 128: Atbios Kit Nov89

The Keyboard Driver E·6·1

SIX

The Keyboard Driver

The Keyboard Driver is used to obtain keyboard input from the keyboard.

If a non-standard keyboard or alternate input device is being used, it is suggested that the keyboard function call structure be retained. The application will then be independent of the hardware characteristics of the actual input device, and may be exercised in a development environment with the standard keyboard input device.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * : Module Name: AT Bios keyboard driver

* Version: 1.06 * * Author: FOSCO * * Date: 11-01-89 * * Filename: atkb.c * * Language: MS C 5.1 * : Functional Description:

* Argunents: * * Return: * * Version History: * 1.01 : Added an nmi disable (out 70 with 8x) for re-boots (ctrl-alt_del).

* 1.02 * Modified buffer store to discard newest key on overrun. * * 1.03 * Iq>roved nuneric keypad handl ing. * * 1.04 * On "check for key in buffer", zeroed out only the zero bit rather than all the flag bits. : Disabled interrupts during the "check for" sequence to insure correct key code was returned.*

* 1.05 : Added F 11 and F 12 support

* 1.06 : Replaced peeks and pokes with casts

*********************************!*****************************************************************/

/* INC L U D e F I L e S */

#include "atkit.h"

/* FUN C T ION PRO TOT Y PES */

unsigned keyboard setup(void); void interrupt cdicl far keyboard io(interrupt registers); void interrupt cdecl far keyboar~isr()i -unsigned translate from column(uniigned char); void reset(void)i - -void int1b(void); void update leds(void)i void disabli keyboard(void)i void enable ieyboard(void)i unsigned seOd_8042_data(unsigned)i

/* G LOB A L V A R I A B L E S */

/* G LOB A L CON S TAN T S */

Page 129: Atbios Kit Nov89

E·6· 2 The Keyboard Driver

extern keyboard io; extern :keyboard[isri

/* L 0 CAL D E FIN I T ION S */

#define pio-port a Ox60 #define pio-POrtlb Ox61 #define status~rt Ox64 #define in bfr full Ox02 lI#define Suffer head Ox1a //#define buffer-tail Ox1c #define buffer oegin Ox1e lI#define buffer start Ox80 //#define buffer-end Ox82 #define wait for-key OxOO #define checK for key in buffer Ox01 #define get_fTags-Ox02 -

#define break code Ox80 /* add to key to get break code *1 #define tab key 15 #define ctl-key 29 #define left key 42 #define ri¥ht key 54 #define prlnt-screen 55 #define alt key 56 #def i ne caPi key 58 #define f1 59 #define f2 60 #define f3 61 #def i ne f4 62 #define f5 63 #def i ne f6 64 #define f7 65 #define f8 66 #define f9 67 #define f10 68 #define f11 87 #define f12 88 #def i ne nun key 69 #define scroll key 70 #def i ne nun 0 !2 #def i ne nun -1 79 #define nun-2 80 #define nun' 81 #define nun-4 75 #def i ne nun, 76 #define nun-6 n #def i ne nun, 71 #define nun-8 72 #def i ne nun:9 73

#define minus key 74 #define plus Key 78 #def i ne ins Key 82 #define del-key 83 #define sys:key 84

#define ack code Oxfa #define resind_code Oxfe

#define ins state Ox80 #define caPS state Ox40 #define nun state Ox20 #define scroll state Ox10 #define al t shTft Ox08 #define ctl-shift Ox04 #define left shift Ox02 #define right_shift Ox01

#define ins shift Ox80 #define caps shift Ox40 #define nun Shift Ox20 #define scroll shift Ox10 #define hold_state Ox08

#define alt column 3 #define ctl-column 2 #define shift column 1 #define base_column 0

/* L 0 CAL CON S TAN T S */

/*======== This is the keyboard table ====================*/

const unsigned char kb_table[89] [4] ={

A· Type BiosKit

Page 130: Atbios Kit Nov89

1* This table covers all keys. ** Some keys are pre-checked for special handling. ** Some special keys are padded out in this table. ** The format is: base,upper,ctrl,alt cases. ** The alt cases are handled as extended codes. *1 (a ,0 ,0 ,0), 1* base a padding for indexing*1 {27 ,27 ,27 ,-1 }, 1* key 1 - Escape key*1 ('1','I',-1 120) 1* key 2 - '1'*1 ('2' 'Q' 0 :121); 1* key 3 - '2' - special handling *1 ('3';'#';-1 ,122 ), 1* key 4 - '3'*1 ('4' '$' -1 ,123 ), 1* key 5 - '4'*1 ('5':'X';-1 ,124 ), /* key 6 - '5'*/ {'6','A',30 ,125 ),1* key 7 - '6'*1 {'7','&',-1 ,126),1* key 8 - '7'*1 {'8' ,'*',-1 ,127),1* key 9 - '8'*1 {'9' ,'(',-1 ,128),1* key 10 - '9'*1 {'O',')',-1 ,129),1* key 11 - '0'*1 {'-','_',31 ,130),1* key 12 - '-'*1 {'=','+',-1 ,131 }, 1* key 13 - '='*1 {8 ,8 ,127, -1 }, 1* key 14 - backspace*1 {9 ,-1 ,-1 , -1 }, 1* key 15 - tab*1 {'q' ,'Q',17 16),1* key 16 - 'Q'*I {'w' ,'~',23 17),1* key 17 - '~'*I {'e','E',S 18}, 1* key 18 - 'E'*I {'r' ,'R',18 19}, 1* key 19 - 'R'*I {'t' ,'T' ,20 20}, 1* key 20 - 'T'*I {/y',/Y',25 21),1* key 21 - 'Y/*I {/U / ,/U',21 22}, 1* key 22 - 'U'*I {'i','I',9 23}, 1* key 23 - '1'*/ {'o/,'O',15 24}, 1* key 24 - '0'*1 {'p',/P',16 25),1* key 25 - 'P/*I (/[/,/{',27, -1) 1* key 26 - 1[1*1 {'l' '}' 29 , -1 S, 1* key 27 - 'l'*1

{13 ,~3 ,10 , -1 }, 1* key 28 - CR*I {-1 ,-1 ,-1 -1}, /* key 29 - control shift *1 {'a','A',1 30 }, 1* key 30 - 'A'*I {/s','S',19 31}, 1* key 31 - 'S'*I {'d','D',4 32 }, 1* key 32 - 'D'*I {'f','F',6 33}, 1* key 33 - 'F/*I {/g','G',7 34}, 1* key 34 - 'G'*I {'h','H',8 35}, 1* key 35 - 'H'*I {'j','J',10 36}, 1* key 36 - 'J'*I ('k','K',11 37), /* key 37 - 'K'*/ {'l' ,'L',12 38}, 1* key 38 - 'L'*I {/·',':',-1 -1}, 1* key 39 - ';'*1 {3~ , '"' , -1 -1}, 1* key 40 " '*1 {'\' '-' -1 -1} 1* key 41 - "'*1 {-1 :-1 '-1 ; -1 }: 1* key 42 - left shift *1 {92"J,,~8, -1}, 1* key 43 - '\'*1 {'z', Z',26 , 44 }, 1* key 44 - 'Z'*I {'x','X',24 45}, 1* key 45 - 'X'*I {'c' 'C' 3 46} 1* key 46 - 'C'*I {'v':'V';22 , 47 }; 1* key 47 - 'V'*I {'b','B',2 48}, 1* key 48 - 'B'*I {'n','N',14 49}, 1* key 49 - 'N'*I {'m','M',13 50}, 1* key 50 - 'M'*I {',' ,'<',-1 -1),1* key 51 - ','*1 {'.','>',-1 -1}, /* key 52 '.'*1 ('I' ", -1 -1) 1* key 53 - '1'*1 {-1 :-i '-1 ; -1 }: 1* key 54 - right shift - *1 {'*' -1 ~14 -1} 1* key 55 - prt-scr - *1 {-1 '-1' -1' -1}' 1* key 56 Alt - *1 {32 :32 ;32', 32 }; 1* key 57 - space bar*1 {-1 ,-1 ,-1, -1}, 1* key 58' - caps-lock - *1 /* funct10n key cases*1 {59,84,94,104 }, 1* key 59 - F1*1 {60,85,95,105 }, 1* key 60 - F2*1 {61,86,96,106 }, 1* key 61 F3*1 {62,87,97,107 }, 1* key 62 - F4*1 {63,88,98,108 }, 1* key 63 - F5*1 {64,89,99 109 }, 1* key 64 - F6*1 {65,90,106,110 }, 1* key 65 - F7*1 {66,91,101,111 }, /* key 66 - F8*1 {67,92,102,112 }, /* key 67 - F9*1 {68,93,103,113 }, /* key 68 - F10*1 {-1,-1,-1,-1 }, 1* key 69 - num-lock - *1 {-1,-1,-1,-1 }, 1* key 70 - scroll-lock - *1 1* num key pad - cases are base,upper,ctrl,alt*1 {71,'7',119,-1 }, 1* key 71 - home*1 {72,'8',-1 -1} 1* key 72 - cursor up*1 {73,'9',13~,-1 S, 1* key 73 - ~ge up~1 {'-','-' -1,-1 }, 1* key 74 - m1nus slgn*1 {75,'4',~15,-1 }, 1* key 75 - cursor left*1 {-1,/5',-1 -1} 1* key 76 - center key*1 {77,'6',11~,-1 S, 1* key 77 - cursor r1ght*1

The Keyboard Driver E·6·3

Section E: The C Pro&rams

Page 131: Atbios Kit Nov89

E·6·4 The Keyboard Driver

('+','+' -1,-1 ), 1* key 78 - plus sign*1 (79,'1',117,-1 ), 1* key 79 - end*1 (80,'2',-1 -1 ), 1* key 80 - cursor down*1 (81,'3',11A,-1), 1* key 81 -.page down*1 {82,'O',-1,-1 }, 1* key 82 - lnsert *1 {83,'.',-1,-1 }, 1* key 83 - delete */ {-1, -1,-1,-1 }, 1* key 84 - sys key */ {-t, -1,-1,-1 }, /* key 85 */ {-1 -1 -1 -1} /* key 86 */ {13~,13~,1~7,13~ }, /* key 87 - F11 */ {134,136,138,140 }, 1* key 88 - F12 *1

};

1* PRO G RAM */

1*==========================================*/ 1*==========================================*1 1* Interrupt 16h - Keyboard function call */ 1*==========================================*1 1*==========================================*1 1*==========================================*/ unsigned keyboard setup(void) ( -

}

unsigned status = ok' link interrupt(Ox16,1 keyboard 10): link-interrupt(Ox09,&-keyboardrisr); if(reset 8042() == error) status = error; BUFFER H£AD = buffer begin; BUFFER-TAIL = buffer~gin; BUFFER-START = buffer begin: BUFFER-END = buffer bigin + 32: outportb(Ox21,inportb(Ox21) & -Ox02); enable keyboard(); , /loutpOrtb(pio~rt b,inportb(pio~rt_b) 1 OxcO); 1* reset the port *7 II outportb(pl0~rt b,inpQrtb(pio~rt_b) & -Ox80); KB FLAG = 0: // reset the flags KB-FLAG 1 = 0; 1/ reset the flags KB-FLAG-2 : 0; 1/ reset the flags KB-FLAG~ = 0: II reset the flags return(it&tus):

/*==========================================*/

void interrupt cdecl far keyboard_io(interrupt_registers) ( enable 0; switch(ax » 8) {

} }

case wait for key: while (BU1FER-HEAD == BUFFER TAIL) { - -enableO; disableO;

}: ax = peek40(BUFFER HEAD): BUFFER HEAD +: 2: if (BUFFER HEAD >=-BUFFER END) SOFFER HEAD = BUFFER START; enable(); - - - -break;

case check for key in buffer: disable();- - --flags &= -zero bit; II clear only the zero bit in the flags ax = peek40(BU1FER HEAD); if (BUFFER HEAD ==-BUFFER TAIL) flags 1= zero_bit; enable(); - -break;

case get flags: ax = (ax-& OxffOO) I KB_FLAG; break;

1*======================================================*1 1* ==== keyboard hardware interrupt service routine ==== *1 variables unsigned char scan code,scan_byte,col: unsigned scan wordr,temp: end_variables-kb_regs:

A· JYpe BiosKit

Page 132: Atbios Kit Nov89

The Keyboard Driver E·6·5

void interrupt cdecl far keyboard isr(interrupt registers) { --

kb regs *myblock: mySlock = acquire_block(KEYBOARD); enable(); .

disable keyboard(); /* get ican code from input port */ myblock->scan_code = i~rtb(pio-POrt_a); myblock->scan_word = -1; /* preset scan word to default no-load */

switch (myblock->scan code) { -/* first do all the special handling keys */

case ack code: KB FLAG 2 1= Ox10; briak; -

case resend code: KB FLAG 2 1= Ox20; briak; -

case sys key: break; -

case tab key: if«KB F[AG & (left shift I right shift» 1= 0) mybloc1(->scan_word = 15*256; -else myblock->scan_word = 15*256+9; break;

case ctl key: KB_FLAG T= ctl_shift; break:

case break code+ctl key: KB FLAG &=--ctl shift; briak; -

case left key: KB FLAG 1= left shift; briak; -

case break code+left key: KB FLAG &=--left shift; briak; -

case right key: KB FLAG I=-right shift; briak; -

case break code+right key: KB FLAG &=--right shift; briak; -

case print screen: if«KB FLA~ & ctl shift) 1= 0) myblocK->scan_wora = 114*256; else {

if«KB FLAG & (left shift 1 right shift» 1= 0) srs_int(OX05,myblOCK); -e se myblock->scan word = 55*256+'*'·

} - , break;

case break code+print screen: /* print screen break */ break; - -

case alt key: KB FLAG I= alt shift; /*-if«K FLAG-& alt shift) == 0) */ ALT INPUT-= 0; -break;

case break code+alt key: KB FLAG &=--alt shift· iffALT INPUT !=-O) myblock->scan word = ALT INPUT; breaic;- --

case caps key: if «KB F[AG 1 & caps shift) == 0) /* if kiy not depressid */

Section E: The C ProlUams

Page 133: Atbios Kit Nov89

{

}

E·6·6 The Keyboard Driver

KB FLAG 1 1= caps shift; KB:FLAG-A= caps_state;

break;

case break code+caps key: KB_FLAG_1 1= -caps_snift; break;

case nun key: if «KB rLAG 1 & num shift) == 0) 1* if key not depressed *1 {

KB_FLAG_1 1= nun_shift; KB FLAG A= nun state;

} - --if«KB FLAG & ctl shift) 1= 0) 1* do Pause mode wI (

KB FLAG 1 1= hold state; iff CRT AOD~ t= 7)-( -outportb(Ox3d8,CRT MODE SET);

} - -eoi sequence(); ena6le keyboard(); while (K8 FLAG 1 & hold state) 1=0) ()

} - - -break;

case break code+nun key: K8 FLAG 1 I- -nun snift; break; - -

case scroll key: if «K8 FLAU 1 & scroll shift) == 0) 1* if key not depressedi*1 {

}

KB FLAG 1 1= scroll shift; ~ff(KB_rLA~_1 & (ctT_shift I alt_shift» == 0)

1/ don't change state if ctrl or alt keys down KB FLAG A= scroll state;

) - -

if«K8 FLAG & ctl shift) 1= 0) (- -

eoi sequence(); ena6le keyboard(); if«KB-FLAG & alt shift) t= 0) (- -

sys int(Ox18,myblock); } -else /* break condition */ (

BIOS 8REAK = Ox80; sys Tnt(Ox1b,myblock);

} -} break;

case break code+scroll key: K8 FLAG 1 1= -scroll snift; break; - -

case ins key: if «K8 rLAG & alt shift) 1= 0) (- -

assemble alt numeric(myblock->scan code); } - - -else { if «K8 FLAG & ins shift) == 0) {- -

KB FLAG A= ins state; 1* toggle insert state */ KB-FLAG 1 1= ins shift;

} - - -// If in either nun state or shift state, but not bithe, code = '0' II else code = 0 - -if«K8 FLAG & nun state) == 0) {- -if «K8 FLAG & ( left shift I right shift» == 0) mybloci->scan word =-ins key*2S6; -

else - -

A-Type BiosKit

Page 134: Atbios Kit Nov89

}

myblock->scan word = ins keY*256+'0'; } - -else ( if «KB FLAG & (left shift I right shift» 1= 0) mybloci->scan_word :: ins_key*256;-

else myblock->scan word = ins keY*256+'0';

} - -break;

case break code+ins key: KB FLAG 1 1= -ins snifti break; - -

case minus key: myblock->scan_word = 74*256+'-'; break;

case plus key: myblock->scan word = 78*256+'+'; break; -

The Keyboard Driver E-6-7

case del key: ~f«KB_FrAG & (ctl_shift I alt_shift» == (ctl_shift I alt_shift»

if «KB FLAG & (left shift I right shift» == 0) (- - -

RESET FLAG = Ox1234; /* warm boot */ ) -else (

RESET FLAG = 0; /* cold boot */ ) -disableO· incmos(Ox60); // set NMI mask far call(bios cs(),&reset);

} - -else (

}

ifC(KB FLAG & nun state) 1= 0) (- -

if«KB FLAG & (left shift I right shift» == 0) mvbloci->scan_word :: 83*256+' .'; -else myblock->scan word = 83*256;

} -else (

ifC(KB FLAG & (left shift I right shift» 1= 0) mvbloek->scan_word:: 83*256+'.'; else myblock->scan word = 83*256;

} -break;

case break code+del key: break; - -

default: /* not a special handling key */

if CCmyblock->scan code & Ox80) == 0) /* do only the makes for these * / ( myblock->scan_code &= Ox7f; /* clear the break bit */

/* release the hold state if it is active */ iflCCKB_FLAG_' & hold_state) 1= 0) KB_FlAG_1 &= -hold_state; e se ( switch (myblock->scan code) ( -case nun 0: case nun-': case nun-2: case nun': case nun-4: case nun-S: case num-6: case nun,: case nun-8: case nun-9: if (CKB_~LAG & alt_shift) 1= 0)

Section E: The C ProlUams

Page 135: Atbios Kit Nov89

} }

E·6·8 The Keyboard Driver

assemble_alt_numeric(myblock->scan_code); else { myblock->col = 0t" 1* BASE = 0 (all extended codes) *1 if «KB FLAG & a t shift) 1= 0 )

- - ~lock->col = alt column; 1* ALT = 3 (all suppressed) */ else if «KB FLAG & ctl shtft) 1= 0) -

- - myblock->col = ctl_column; 1* CTRL = 2 (all extended codes *1

if «KB FLAG & (num state» 1= 0) myblocK->scan wor~= peekbcs(&kb table[myblock->scan code] [1]);

else - - -myblock->scan_word = peekbcs(&kb_table[myblock->scan_code] [myblock->coll)«8;

} break:

case f1: case f2: case f3: case f4: case f5: case f6: case f7: case f8: case f9: case f10: case f11: case f12: myblock->scan word = translate from column(myblock->scan code): if «myblock->scan word & OxffUO) == 0) -myblock->scan_wor~= myblock->scan_word « 8: break;

default: mvblock->scan word = translate from column(myblock->scan code): j'-if not an extended code return *7 -

}

if«myblock->scan word & OxffOO) == 0) ( -mvblock->scan byte = myblock->scan word; j'-caps lock correction */ -

if«KB FLAG & caps state) 1= 0) {- -if «(myblock->scan byte >= 'A') && (myblock->scan byte-<= 'Z/» II =( lock->scan byte >= 'a/) && ( lock->scan 6yte <= 'Z'»)

lock->scan pyte A= Ox20; } -myblock->scan_word = (myblock->scan_code « 8) I myblock->scan_byte:

} break:

} break;

if(myblock->scan word 1= -1) /* load scan word into buffer */ { -//-------------------------------------------------/I increment the t~rary tail pointer myblock->temp = BUFFER TAIL + 2; // check for wrap-around and reset to start if needed if (myblock->temp == BUFFER END) mvblock->temp = BUFFER START; /1 if overwrite wfll not ha~L then store the scan word

}

if (myblock->temp 1= BUFFER EAD) ( -poke40(BUFFER_TAIL,~lock->scan-word); II now update the tatl BUFFER TAIL = myblock->temp;

} -else ( beep();

} 11-------------------------------------------------

1* read the in service register to see if eoi is needed *1 outportb(Ox20,OxOb): if«inportb(Ox20) & Ox02) 1= 0) ( outportb(Ox20,Ox20); enable keyboard();

} -update_ledsO;

A· Type BiosKit

Page 136: Atbios Kit Nov89

release block(myblock): } -1*========== end of keyboard isr routine ===========*1 unsigned translate from column(unsigned char scan code) < - - -unsigned char col = 0, if «KB FLAG & alt sh,ft) 1= 0 ) relturn(peekbcS(&kb:table[Scan_code] [alt_column]) « 8); e se < if «KB FLAG & ctl shift) != 0) col = ctl column,' 1* 2 *1 else - - -< if «KB FLAG & (left shift 1 right shift» 1= 0) col = snift column: 7* 1 *1 -

} -} return (peekbcs(&kb table[scan code] [col]»:

} --1*---------------------------------------------*1 assemble alt numeric(unsigned char scan code) ( - - -unsigned char code; code = peekbcs(&kb table[scan code] [1]): if «code >= '0') 1& (code <=-'9'» (ALT INPUT *= 10) + (code & OxOf):'

} -1*-- update the keyboard leds if state has changed --*1 void update leds(void) ( -

}

~f«(KB_FLAG & Ox70) » 4) 1= (KB_FLAG_2 & Ox07»

}

II check update busy bit if «KB FLAG 2 & Ox40) == 0) < --eoi s~e(): ena5le keyboard(): KB FLA~ 2 l= Ox40; II set update busy i ffsenaao 2 data(Oxed) == ok) II send the led conmand < --

}

delay call(0,10000): II wait about 10 millisecs KB FLXG 2 &= Oxf8: II build new led bits KB:FLAG:2 1= (KB_FL~G & Ox70) » 4: eOl sequence(); ena5le keyboard(): . I I sena the led code if(send 8042 data(KB FLAG 2 & Ox07) 1= ok) ( - - --II send enable if we had a tx error send 8042 data(Oxf4);

} - -KB FLAG 2 &= -Ox40: II clear update busy

} - -enable():

void disable keyboard() ( -send 8042(Oxad);

} -void enable keyboardO ( -send 8042(Oxae):

} -1*=======================================================*1

The Keyboard Driver E·6·9

Section E: The C Pro&rams

Page 137: Atbios Kit Nov89
Page 138: Atbios Kit Nov89

The Video Driver E·7·1

SEVEN

The Video Driver

The Video Driver is used to operate the CRT display.

If a video adapter is not installed in a system, it is wise to retain the video function, and internally modify it to direct output to an alternate device. This permits character oriented video output (such as the "write_tty" command) to retain PC compatibility during the development phases. As an example, the video driver might relay characters to a serial channel output routine, but the application could be exercised on a system with a video device installed.

Note: Screen flickering - some early generation video adapters do not have clean memory-write/refresh-read timing and flickering may be observed when updating the screen. Most of the currently available adapters, in our experience, seem to minimize this flickering effect. If you observe flickering, the general method to pursue to minimize this is to sample the horizontal re-trace status, (usually bit 0 of the status port, 3BA or 3DA), and write into display memory only when the adapter is in retrace (moving the blanked beam from right to left to start a new line). The vertical sync time can also be used for writing.

Note: 24 line scrolling - The standard Write-TIY function scrolls all 25 lines. A 24 line scroll may be a desirable option in order to maintain a "status" line at the bottom of the screen. This may be accomplished by modifying the Write-TIY function to either always scroll 24 (or 25) or to sense a flag (or variable) to determine how many lines should be scrolled.

/*************************************************************************************************** * : Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

* Module Name: AT Bios crt driver * * Version: 1.03 * * Author: FOSCO * * Date: 10-20-89 * * Filename: atcrt.c * : Language: MSC 5.1

: Functional Description:

: This driver manages the video display.

* Argunents: * * Return: * * Version History: * 1.01 * Corrected some get cursor ~sition statements; added active page index to the * peekb40(cursor-POsn+(peekb40(active-psge)«1» uses active page # as word index * into cursor co-ordinates table in segment 40:50-5f. * 1.02 * Added some graphics in.,rovements * 1.03 : Used typecast segment 40: variables

**************************************************************************************************/

/* INC L U D E F I L E S */

Page 139: Atbios Kit Nov89

E·7·2 The Video Driver

#include "atkit.h"

/* FUN C T ION PRO TOT Y PES */

void $iret(void);

unsigned video setup(void)c void interrupt-cdecl far vldeo_io(interrupt_registers);

extern void move row (unsi~ned,unsigned,unsi~ned,unsi~ned); extern void clear row (unslgned,unsigned,unslgned,unslgned)i extern void move-graphics row ( unsigned,unsigned;unsignedr,unsigned); extern void clear graphics row ( unsigned,unsi9nea;unsi~ned;unsigned); unsigned check mode(vold); void load 6845~te(unsigned,unsigned char); void loadr6845-word(unsi~ned,unsigned)c unsigned expana byte(unslgned char,unslgned char); void set the cursor to loc(unsigned); void store cursor~sition(unsigned,unsi9ned); unsigned fTnd-PQSltion(void); void scroll end(void); uns i·gned swi{)(uns i gned); unsigned POsltion(unsi~ned char,unsigned char); unsigned rom check(unslgned)i unsigned fina-P8ge-POsitionCunsigned char);

/* G L 0 8 A L V A R I A 8 L E S */

extern unsigned redirect_flag;

/* G L 0 8 ALe 0 N S TAN T S */

extern _video_io;

/* L 0 CAL D E FIN I T ION S */

#define cursor-POsn Ox50

#define ~ 0 #define dOwn 1 #define is graphics Ox01 #define is:alpha Ox02

#define bell Ox07 #define backspace OxOS #define carriage return OxOd #define l ine_fiea OxOa

#define VIDEO_IO Ox10

#define color address Ox03d4 #define mono iddress Ox03b4 #define ega_address Ox03cO

/*=== command equates ===*/

#def i ne set mode 0 #define set-cursor shape #define set-cursor:Position 2 #define resa cursor-PQsition 3 #define readrli~ht~ 4 #define set ictlVe-PBge 5 #define scroll ~ ~ #define scroll-dOwn 7 #def i ne read ae current 8 #define write ac current 9 #define write-c current 10 /* OA */ #define set color 11 /* 08 */ #define write...{)ixel 12 /* OC */ #define readJ)1xel 13 /* OD */ #define write tty 14 /* OE */ #define return VIdeO state 15 /* OF */ #define write_string- 19 /* 13 */

/* L 0 CAL CON S TAN T S */

/*------ constants ----------*/ extern const unsigned char video font [128] [8]; extern const unsigned char mode table[8]· extern const unsigned char column tabletS]· extern const unsigned char video-Parms[4][~6];

A-Type BiosKit

Page 140: Atbios Kit Nov89

The Video Driver E· 7·3

II We do not use the length table in biostop.asm because it only has four entries. const unsigned length table[8] = { -2048,2048,4096,4096,16384,16384,16384,4096

};

1* PRO G RAM *1

1*------------- video setup ---------------------*1 variables end_variables video_setup_regs;

unsigned video setup(void) ( -video_setup_re~s *myblock; myblock = acqulre_block(VIDEO);

1* reset any video cards *1 outportb(color_address + 4, 0); outportb(mono address + 4, 1); inportb(mono address + 6); inportb(color address + 6); outportb(ega_address, 0);

1* load vector for this routine *1 link interr~t(Ox10,& video io); set_vector(Ox1d,bios_cs(),&video-Parms[0]); II set default ~rt address to cOlor board II this is done in ease we have an EGA ADDR_6845 = color_address;

}

1* determine type of video *1

switch (EQUIP FLAG & Ox0030) ( -

}

case 0x30: 1* monochrome *1 ADDR 6845 = mono address; myblOck -> ax = Ux0002; sys_int(Ox10,myblock);

break;

ease OxOO: 1* none - assume color */ case Ox20: 1* cga 80 *1 myblock -> ax = Ox0003; sys int(Ox10,myblock); break;

case Ox10: /* cga 40 *1 myblock -> ax = Ox0001; sys_int(Ox10,myblock); break;

rom_check(OxcOOO);

release_block(myblock);

return(ok);

1*=== 1*=== 1*===

MAIN VIDEO ROUTINE

variables uns i gned i, j, reg index, video segment· unsigned perm segment,parm olfset,fi{l word; uns i gned row, co l , line CCU'lt'; -unsigned char outchar; unsigned temp,temp cursor,fill length; end_variables videO_regs; -

===*1 ===*1 ===*1

void interrupt cdecl far video io(interrupt registers) ( --video regs *myblock; enabli();

myblock = acquire_block(VIDEO);

if (ADDR 6845 1= 0) { -if (ADDR 6845 == mono address) {- -myblock->video segment = OxbOOO; 1* mono card *1

} -

Section E: The C Pro&rams

Page 141: Atbios Kit Nov89

E· 7 -4 The Video Driver

else { myblock->video segment = OxbBOO;

} -switch (ax» 8) {

/* color card */

/*=============================================*/ /*=== ===*/ /*=== AH = 0 = set mode ===*/ /*=== AL = mode to be selected (0-9) ===*/ /*=== ===*/ /*=============================================*/

case set_mode:

if «SWITCH BYTE & Ox30) == OxlO) { -

CRT MODE = 7; /* if mono, force mode 7 */ ADDf 6845 = mono address; mybleck->video segment = OxbOOO;

} -else {

}

ADDR 6845 = color address· mybleck->video_segment = 6xbBOO;

if «ax & Oxff) 1= 7) CRT MODE = ax; /* if color, use selected mode */ else { if «SWITCH BYTE & OxlO) == Ox20) CRT MODE = 0; else CRT_MODE = 2;

} - -

CRT MODE SET = ~kbcs(&mode table[CRT MODE]); outportb{(ADDR_6845) + 4, CRT_MODE_SET1;

myblock->panm offset = peek(OxOO,Ox74); myblock->panm:segment = peek(OxOO,Ox76)i

if (CRT MODE >=2) myblock->parm offset += 16; /* 16 */ if (CRT-MODE >=4) myblock->panm-offset += 16; /* 16+16 */ if (CRTJMOOE ==7) myblock->panm:offset += 16; /* 16+16+16 */

CURSOR_MODE = swap(peek(myblock->parm_segment,(myblock->panm_offset+10»);

for (myblock->reg index=O;myblock->reg index < 16;myblock->reg index++) ( - - -l~ad 6845_byte(myblock->reg_index,peekb(myblock->parm_segment,myblock->parm_offset+myblock-

>reg 1 ncleX»; }-

CRT START = 0; ACTTVE_PAGE = 0; /* set active page to zero */

/* enable video and correct port setting */

outportb«ADDR_6845) + 4,peekbcs(&mode_table[CRT_MODE]»;

CRT_MODE_SET = peekbcs(&mode_table[CRT_MODE]);

CRT_COLS = peekbcs(&column_table[CRT_MODE]);

CRT_LENGTH = peekcs(&length_table[CRT_MODE]);

for. (myblock->i = 0; myblock->i < 8; ~lock->i++) poke40(cursor-POsn + myblock->i, 0); / clear all cursor positions */

if (CRT MODE == 6) /* set paLlette register */ ( -outportb«ADDR 6845) + 5,Oxlf); CRT PALLETTE =-Oxlf;

} -else ( outportb«ADDR 6845) + 5,OxlO); CRT PALLETTE =-Ox30;

} -if (check mode() == is graphics) mvblock->Till_word = 0; else myblock->fill_word = Ox0720;

myblock->fill_length = 2 * CRT_LENGTH;

A-Type BiosKit

Page 142: Atbios Kit Nov89

The Video Driver E-7-S

CURSOR_MODE = Ox0607;

for (myblock->i = 0; myblock->i < myblock->fill_length; myblock->i += 2) 1* clear the screen */ ( poke(myblock->video_segment, myblock->i, myblock->fill_word);

)

break;

1*===========================================*/ 1*=== ===*/ /*=== AH = 1 = set the cursor shape ===*/ /*=== ===*/ /*=== CH = start line ===*/ /*=== CL = stop line ===*/ 1*=== ===*/ /*===========================================*/

case set_cursor_shape:

CURSOR_MODE = cx; load_6845_word(10,cx);

break;

/*=====================================*/ 1*=== ===*/ 1*=== AH = 2 = set cursor position ===*/ /*=== ===*/ /*=== OH = row ===*/ /*=== OL = column ===*/ ./*=== BH = page ===*/ /*=== ===*/ /*=====================================*/

case set_cursor-POsitfon:

poke40(cursor-POsn+ «bx » 8) « 1), dx);

if (ACTIVE_PAGE == (bx » 8» load 6845 word(14 «CRT START) +

- «T(dx» A) * cRT_COLS) + (dx & Oxff) ) « 1) »1 »; break;

/*=============================================*/ /*=== ===*/ 1*=== AH = 3 = read cursor position ===*/ 1*=== ===*/ /*=== BH = page I OH = row ===*/ /*=== I OL =·column ===*/ 1*=== CX = cursor mode ===*/ /*=== ===*/ 1*=============================================*/ case read_cursor-POsition:

cx = CURSOR_MODE; dx = CURSOR_POSN + «bx » 8) « 1);

break;

/*=============================================*/ /*=== ===*/ /*=== AH = 4 = read light pen position ===*/ /*=== ===*/ /*=== AN = 0 = no info ===*/ /*=== AN = 1 = info ===*/ /*=== ON = row ===*/ 1*=== OL = column ===*/ /*=== CN = raster line ===*/ /*=== BX = horz. position ===*/ /*=== ===*/ /*=============================================*/

case read_light~n:

ax = ax & OxOOff; /* set no light pen return code */

break;

/*==========================================*/ /*=== ===*/ /*=== AN = 5 = set active page ===*/ 1*=== ===*/ /*=== AL = active page # ===*/ /*=== ===*/

Section E: The C Pro&rams

Page 143: Atbios Kit Nov89

E· 7·6 The Video Driver

/*==========================================*/

case set_active-P8ge:

ACTIVE PAGE = ax; CRT ST~RT = CRT LENGTH * (ax & OxOOff); dx = peek40(eursor-POsn+«ax & OxOOff) « 1»; load 6845 word(12,~RT START / 2); lo~6845-word(14,(CRT START + ««ax »-8) * CRT COL! ) + (dx & Oxff) ) « 1) »1 »; -break;

/*=============================================*/ /*=== ===*/ /*=== AH = 6 = scroll up ===*/ /*=== ===*/ /*=== AL = # rows to scroll (0 = blank) ===*/ /*=== cx = row,col of ~r left corner ===*/ /*=== ox = row,col of lower right corner ===*/ /*=== 8H = attribute for blanked line ===*/ /*=== ===*/ /*=============================================*/

case scroll up: if (check mOde() == is_graphics) { -if «ax & Oxff) == 0) /* blank the field */ { myblock->i = (dx » 8) - (ex» 8)'; for (myblock->line count = 0; myblock->line count <= myblock->i; myblock->line_count++) { - -for (myblock->row = (ex » 8); myblock->row <= (dx »8); myblock->row++) {

}

clear graphics row(myblock->video segment, «mybTock->row-* 320) + (ex & OxfT», (dx & Oxff) - (ex & Oxff) + 1,0);

} } else /* scroll the field */ { /* i will = the # of rows to scroll */ myblock->i = ax & Oxff;

for (myblock->line count = O;myblock->line count < myblock->iimyblock->line eount++) { - - -

} }

}

for (myblock->row = (ex » 8); myblock->row < (dx »8); myblock->row++) {

}

move graphics_row(myblock->video_segment, «mY6lock->row + 1) * 320) + (ex & Oxff), (mybloek->row * 320) + (ex & Oxff), (dx & Oxff) - (ex & Oxff)+1);

myblock->row = dx » 8· clear graphics row(myb[ock->video segment, (myblOck->row • 320) + (cx & Oxffl, (dx & Oxff). - (ex & Oxff) + 1,0);

else /* alpha mode scroll */ { if «ax & Oxff) == 0) /* blank the field */ { myblock->i = (dx » 8) - (ex » 8); for (myblock->line count = 0; myblock->line count <= myblock->i; myblock->line eount++) { - - -for (myblock->row = (cx » 8); myblock->row <= (dx »8); myblock->row++) {

}

clear row(myblock->video segment, «mybTock->row * CRT COL!) + (cx & Oxff» * 2, (dx & Oxff) - (cx & Uxff) + 1, (bx & OxffOO) I Ox20);

} } else /* scroll the field */ { myblock->i = ax & Oxff; for (myblock->line count = 0; myblock->line_count < myblock->i; myblock->line_count++) { -

for (myblock->row = (ex » 8); myblock->row < (dx »8); myblock->row++) { move_row(myblock->video_segment,

A-Type BiosKit

Page 144: Atbios Kit Nov89

} }

}

}

«(myblock->row + 1) * CRT_COLS)+(cx & Oxff»*2, «myblock->row * CRT COLS)+(cx & Oxff»*2, (dx & Oxff)-(cx & Oxlf)+1);

mvblock->row = dx» 8; clear row(myblock->video segment, «mybTock->row * CRT COL~)+(cx & Oxff»*2, (dx & Oxff)-(cx & Oxif)+1, «bx & OxffOO) I Ox20»;

break;

/*===================================================*/ /*=== AH = 1 = scroll down ===*/ /*=== ===*/ /*=== AL = # rows to scroll (0 = blank window) ===*/ /*=== cx = row, col of upper left corner ===*/ /*=== ox = row, col of lower right corner ===*/ /*=== BH = attribute for blanked line ===*/ /*=== ===*/ /*===================================================*/

case scroll_down:

if (check mode() -- is_graphics) { -if «ax & Oxff) == 0) /* blank the field */ {

The Video Driver E· 7-7

myblock->i = (dx » 8) - (cx » 8); for (myblock->line count = 0; myblock->line count <= myblock->i; myblock->line count++) { - - -for (myblock->row = (cx » 8); myblock->row <= (dx »8); myblock->row++) <

} }

}

clear graphics row(myblock->video segment, «mybTock->rowW)20)+(cx & Oxff»,-(dx & Oxff)-(cx & Oxff)+1,0);

else /* scroll the field */ < for (mvblock->line count = 0; myblock->line_count < (ax & Oxff); myblock->line count++) < -for (myblock->row = (dx » 8); myblock->row > (cx »8); myblock->row--) <

} }

}

move graphics row(myblock->video segment, «my6lock->row - 1) * 320) + (cx-& Oxff), (myblock->row * 320) + (cx & Oxff), (dx & Oxff)-(cx & Oxff)+1); .

mvblock->row = cx » 8" clear graphics row(myb{ock->video segment, (myblOck->row w 320) + (cx & Oxffl, (dx & Oxff)-(cx & Oxff)+1,0);

} else < if «ax & Oxff) == 0) /* blank the field */ < for (myblock->row = (dx » 8); myblock->row < (cx »8); myblock->row--) < for (myblock->col=(cx & Oxff); myblock->col< (dx & Oxff); myblock->col++)

} }

< pokeb(myblock->video segment, «(myblock->row * CRT COLS) + myblock->col)*2),Ox20);

} -

else /* scroll the field */ < for (mvblock->line count = 0; myblock->line_count < (ax & Oxff); myblock->line count++) < -for (myblock->row = (dx » 8); myblock->row > (cx »8); myblock->row--) <

}

move row(myblock->video segment, «(mYblock->row - 1) * ~RT COLS)+(cx & Oxff»*2, «myblock->row * CRT COLS)+(cx & Oxff»*2, (dx & Oxff)-(cx & Oxlf)+1);

Section E: The C ProlUams

Page 145: Atbios Kit Nov89

E· 7·8 The Video Driver

myblock->row = cx » 8;

clear row(myblock->video segment «mybTock->row * CRT COL! + (cx & Oxff»*2), (dx & Oxff)-(cx & OXTf)+1,

} }

}

«bx & OxffOO) I Ox20»;

break;

1*=============================================*/ 1*=== ===*/ /*=== AH = 8 = read attr and char at cursor ===*/ /*=== ===*/ /*=== BH = page # I AL = char ===*/ 1*=== for alpha only AH = attrib ===*/ 1*=============================================*/ case read_ac_current:

if (check_mode() == is_graphics) ( for (myblock->j = 0; myblock->j < 128; myblock->j++) ( myblock->temp = true; for (myblock->i=O; myblock->i <= 7; myblock->i++) ( /* if mode is 640 x 200 */ if(CRT MODE == 6) ( -

}

if(~kb(myblock->video segment (myblock->row * 320) + t(mybloc'->i & Oxfe) * 40) + myblock->col + «mvblock->i & 1) * Ox2000» 1= peekbcs(&video_font[ax & Ox007f] [myblock->i]» myblock->temp = false;

else /* 320 x 200 mode *1 ( if(~ek(myblock->video segment, (myblock->row * 320) +-«myblock->i & Oxfe) * 40) + (myblock->col * 2) + «myblock->i

Ox2000» 1=

}

}

ex~nd byte(peekbcs(&video_font[ax & Ox007f] [myblock->i]),3» mybloci->temp = false;

if (myblock->temp == true) (

ax = (ax & OxffOO) I mvblock->j; break; /* get out with the find */

}

} } else /* --- alpha read --- */ ( ax = peek(myblock->video segment,find-P8ge nnsition(bx » 8»; } _ -r-

break;

/*==============================================*/ 1*=== ===*/ /*=== AH = 9 z write attr and char at cursor ===*/ 1*=== ===*/ 1*=== BH = page # ===*/ 1*=== for al~a only ===*/ 1*=== CX = # write ===*/ 1*=== AL = character ===*/ /*=== BL = attribute ===*/ /*=== ===*/ /*==============================================*/

case write_ac_current:

if(check mode() == is graphics) (- -

myblock->row = peekb40(cursor-PQsn+«bx » 8) « 1) +1); myblock->col = peekb40(cursor-PQsn+«bx » 8) « 1»; for (myblock->i=O; myblock->i <= 7; myblock->i++) ( 1* if the mode is 640 x 200 */ if(CRT MODE == 6) ( -pokeb(mvblock->video segment (myblock->row * 320)-+ «myb(ock->i & Oxfe) * 40) + myblock->col +

A-Type BiosKit

& 1) *

Page 146: Atbios Kit Nov89

}

«myblock->i & 1) * Ox2000) peekbcs(&video font[ax & Ox607f] [myblock->i));

} -else <

}

/* if the mode is 320 x 200 */

poke(myblock->video segment (myblock->row * 320J + «myblock->i & Oxfe) * 40) + (myblock->col * 2) + «myblock->i & 1) * Ox2000) ex~nd_byte(peekbcs(&video_font[ax & Ox007f] [myblock->i]), bx & Ox83»;

} else ( myblock->temp = find-P8ge~sition(bx » 8); for (myblOCK->; = 0; myblOCK->i < cx; myblock->i++) (

The Video Driver E-7-9

poke(myblock->video segment,myblock->temp+(2 * myblock->i),«bx « 8) I (ax & Oxff»); } -

}

break;

/*===============================================*/ /*=== . ===*/ /*=== AH = 10 = write char at cursor position ===*/ /*=== ===*/ /*=== BH = page • ===*/ /*=== for alpha onlyl ===*/ /*=== CX = • to write ===*/ /*=== AL = character ===*/ /*=== ===*/ /*===============================================*/

case write_c_current:

if(check mode() == is graphics) < - -myblock->row = peekb40(cursor-POsn+«bx » 8) « 1)+1); myblock->col = ~ekb40(cursor-POsn+«bx » 8) « 1»; for (myblock->i=O; myblock->i <= 7; myblock->i++) < /* if the mode is 640 x 200 */ if(CRT MODE == 6) < -pokeb(myblock->video segment-(myblock->row * 320)-+ «myb[ock->i & Oxfe) * 40) + myblock->col + «myblock->i & 1) * Ox2000) peekbcs(&video font[ax & Ox607f] [myblock->i));

} -else < /* if the mode is 320 x 200 */

poke(myblock->video segment (myblock->row * 320J + «myblock->i & Oxfe) * 40) + (myblock->col * 2) + «myblock->i & 1) * Ox2000) expand byte(peekbcs(&video font[ax & Ox007f] [myblock->i]),3»;

} - -}

} else < myblock->temp = find~ge~sition(bx » 8); for (myblock->i = 0; myblock->i < cx; myblock->i++) { pokeb(myblock->video segment,myblock->temp + (2 * myblock->i),ax);

} -}

break;

/*==============================================*/ /*=== ===*/ /*=== AH = 11 = set color for MRES graphics ===*/ /*=== ===*/ /*=== BH = 0 ===*/ /*=== Bl = background color ===*/

Section E: The C Proerams

Page 147: Atbios Kit Nov89

E· 7 ·10 The Video Driver

1*=== ===*1 1*=== BH = 1 ===*1 1*=== BL = pallette select ===*1 1*=== ===*1 1*==============================================*1 case set color: 1* get current ~llette value *1 if«bx » 8) == 0) 1* this is color 0 *1 { 1* turn off low 5 bits of current color */

CRT PALLETTE &= OxeO-CRT-PALLETTE 1= (bx 1 Ox1f); 1* turn off hlgh three bits of input *1

} else 1* select pallette */ (

CRT PALLETTE &= Oxdf; 1* turn off pallete select bit *1 ifC{bx & Ox01) 1= 0) CRT PALLETTE 1= Ox20; 1* turn on pallette select bit */

} -outportb«ADOR 6845) + S,CRT PALLETTE); break; - -

1*===========================================*1 1*=== ===*1 1*=== AH = 12 = write pixel ===*1 1*=== ===*/ 1*=== OX = row 0-199 ===*1 1*=== CX = column 0-639 ===*/ 1*=== AL = pixel value (1 or 2 bits) ===*1 1*=== bit 7 = 1 = XOR lower bits ===*/ 1*=== ===*1 1*===========================================*1 case write-pixel:

1* calc row address for even/odd */ myblock->row = dx * 40 + «dx & 1) * (Ox2000-40»: if(CRT MODE == 6) 1* write one 1 bit *1 { -

1* col variable is used for bit mask *1 myblock->col = 1 « (ex X 8);

}

1* calc address for 1 bit in 8 *1 myblock->row += ex I 8;

pokeb(myblock->video_segment,myblock->row,«peekb(myblock->video_segment,myblock->row) & -myblock->col) I «ax & Ox0001) « (cx X 8»»;

else 1* write 2 bits *1 { 1* col variable is used for bit mask *1 myblock->col = 3 « (cx X 4):

1* calc address for 2 bits in 8 */ myblock->row += cx/4;

r keb(myblOCk->video_segment,myblock->row,C(peekbCmyblock->video_Segment,myblock->row) -myt)lock->col) I

«ax & Ox0003) « (cx X 4»»;

}

break;

1*==========================================*1 1*=== ===*1 1*=== AH • 13 • read pixel ==.*1 1*·=· ===*1 1*=== OX = row 0-199 I AL = pixel ===*1 1*=== CX = column 0-639 ===*1 1*=== ===*1 1*==========================================*1 case read-pixel:

1* calc row address for even/odd *1 myblock->row = dx * 40 + «dx & 1) * (Ox2000-40»;

if(CRT MODE == 6) { - 1* read one 1 bit *1

1* calc address for 1 bit in8 *1

A-1Jpe BiosKit

Page 148: Atbios Kit Nov89

myblock->row += cx/8;

ax :I (ax & OxffOO) I «peekb(myblock->video_segment,myblock->row) » (ex X 8» & 1);

) else {

1* read 2 bits */

)

1* calc address for 2 bits in 8 *1 myblock->row += cx/4;

ax = (ax & OxffOO) I «peekb(myblock->video_segment,myblock->row) » (cx X 4» & 3);

break;

/*=========================================*/ /*=== ===*/ 1*=== AH = 14 = write tty ===*/ /*=== ===*/ /*=== Al = character to write ===*1 /*=== Bl = fground color in graphics ===*1 1*=== use active page ===*1 /*=========================================*1 case write_tty:

if(redirect flag 1= 0) ( -myblock -> ax = ax & OxOOff; myblock -> dx :I 0; sys int(Ox17,myblock);

} -1* get current cursor *1 myblock->row = peekb40(cursor-POsn + (ACTIVE PAGE « 1)+1); myblock->col = peekb40(cursor-POsn + (ACTIVE:PAGE « 1»;

switch (ax & OxOOff) ( case bell: beep(); break;

case backspace: if (myblock->col !=O) myblock->col--; break;

case carriage return: myblock->col = 0; break;

case line feed: if (mybloek->row == 24) ( /* find the fill attribute *1 myblock -> ax = Ox0800; II set bh to active page myblock -> bx = ACTIVE PAGE" myblock -> bx = myblOCK -> ~x « 8; sys int(VIDEO IO,myblock); II set bh to Slank line attribute myblock -> bx = (myblock -> ax & OxffOO);

myblock -> ax = Ox0601; 1* scroll call */ myblock -> cx = 0" myblock -> dx = (~4 « 8) I (CRT_COlS - 1); sys int(VIDEO IO,myblock);

} - -else { myblock->row++;

}

break;

default: /* any other character */

myblock -> ax = (write c current « 8) I (ax & OxOOff); myblock -> bx = ACTIVE-PXGE" myblock -> bx = myblocK -> ~x « 8; myblock -> ex = 1; sys_int(VIDEO_IO,myblock);

The Video Driver E· 7 ·11

Section E: The C Pro&rams

Page 149: Atbios Kit Nov89

E· 7 ·12 The Video Driver

myblock->col++; if (myblock->col >= CRT_COLS) {

)

)

myblock->col = 0; if (myblock->row == 24) ( /* find the fill attribute */ myblock -> ax = Ox0800; myblock -> bx = ACTIVE PAGE· myblock -> bx = myblOCK -> bX « 8; sys int(VIOEO_IO,myblock); mybTock -> bx = (myblock -> ax & OxffOO);

myblock -> ax = Ox0601; myblock -> cx = O· myblock -> dx = (24 «8) I (CRT_COlS - 1); sys int(VIOEO IO,myblock); ) - _. .

else { myblock->row++;

}

break;

myblock->temp = (myblock->row « 8) I (myblock->col & OxOOff); poke40(cursor-PQsn+«ACTIVE_PAGE) « 1),myblock->temp);

load 6845 word(14,(CRT START + «my6lock~>row * CRT_CDLS) + myblocx->col ) « 1) »1 );

break;

/*===========================================*/ /*=== ===*/ /*=== AH = 15 = return video state ===*/ /*=== ===*/ /*=== AH = # of cols ===*/ /*=== AL = mode ===*/ /*=== BH = page ===*/ /*=== ===*/ /*===========================================*/

case return_video_state:

ax = (CRT COLS « 8) I CRT MODE; bx = (bx 'OxOOff) I (ACTIVE_PAGE « 8);

break;

/*================================~===================*/ /*=== ===*/ /*=== AH = 19 = write string ===*/ /*=== ===*/ /*=== ES:BP = pointer to string ===*/ /*=== CX = length of string ===*/ /*=== OX = cursor position ===*/ /*=== BH = page # ===*/ /*=== ===*/ /*=== AL = 0 = write string - don't move cursor ===*/ /*=== BL = attribute ===*/ /*=== AL = 1 = write string - move cursor ===*/ /*=== BL = attribute ===*/ /*=== AL = 2 = write char and attribute ===*/ /*=== - don't move cursor ===*/ /*=== AL = 3 = write char and attribute ===*/ /*=== - move cursor ===*/ /*=== ===*/ /*====================================================*/

case write_string:

/* if count> 0 and o~ode 0-3 */ if «cx != 0) && «ax & OxOOff) <= 3» ( /* save current cursor for this page */ myblock->temp_cursor = peek40(cursor-PQsn+(bx » 8)«1);

/* set cursor to callers position */ myblock -> ax = (set cursor-PQsition « 8); myblock -> dx = dx; -myblock -> bx = bXi sys int(VIOEO IO,mvblock); mybTock->row = myblock -> dx » 8· myblock->col = myblock ->dx & Ox06ff;

A· Type BiosKit

Page 150: Atbios Kit Nov89

} }

}

for (myblock->i = 0i myblock->i < cx; myblock->i++) ( myblock->outchar = peekb(es,bp+myblock->i);

}

if «myblock->outchar == backspace) II (myblock->outchar == carriage return) II (myblock->outchar == line feea» { -myblock -> ax = (write tty « 8) I myblock->outchari myblock -> bx = bXi -sys int(VIDEO IO,myblock)i mybTock->row = (peek40(cursorJPOsn+(bx » 8)«1» » 8; myblock->col = peek40(cursor-PQsn+(bx » 8)«1);

} else { myblock -> cx = 1; myblock -> bx = bx· if (ax & OxOOff > ~) (

}

myblock -> bx = peekb(es,bp); bp++;

myblock -> ax = (write ac current « 8) I myblock->outchar; sys int(VIDEO IO,mybloek); mybTock->col++; if (myblock->col » (CRT COlS» { -myblock->row++; if (myblock->row >=25) {

} }

myblock->col = 0i myblock -> ax = (write tty « 8) I line_feed; sys int(VIDEO_IO,mybloek); mybTock->row--;

1* update cursor */ myblock -> ax = (set cursorJPOsition « 8); myblock -> dx = (mybTock->row « 8) I myblock->col; sys int(VIDEO IO,myblock)i

} - -1* restore original cursor *1 if «ax & 1) == 0) ( poke40«cursorJPOsn + CCbx »8) « 1»,mvblock->temp cursor); myblock -> ax = (set cursorJPOsition « 8); -myblock -> dx = myblOck->temp cursor; . sys int(VIDEO IO,myblock); -

} - -break;

1*===========================================*1 1*=== ===*1 1*=== default case for invalid opcodes ===*1 1*=== ===*1 /*===========================================*/

release blockCmyblock); } -

1*=============================================*1 /*=== ===*1 1*=== SUPPORTING FUNCTIONS ===*1 1*=== ===*1 1*=============================================*/ /1 find position - returns offset page*row*col

unsigned findJPOsi tionO ( }returnCfind-P8geJPOsitionCACTIVE_PAGE»;

unsigned find-P8geJPOsition(unsigned char page) ( unsigned temp, length· unsigned char row,col; temp = peek40(cursorJPOsn + Cpage « 1»; row = temp » 8; col = temp;

The Video Driver E-7 -13

Section E: The C Pro&rams

Page 151: Atbios Kit Nov89

E·7·14 The Video Driver

length = CRT lENGTH; teq:> = length * ~ge; return(teq:> + position(row,col»;

}

/*---**--- calc buffer address of character at AX = row,col **--- returns ax offset of character in buffer */ unsigned position(unsigned char row,unsigned char col) ( return«(row * CRT COlS)+col)«1);

} -/*---**--- scroll end */

void scroll end() { -if (CRT MODE != 7) outportb(Ox3d8,CRT MODE SET);

} - - -/*---**--- convert cursor position to buffer offset */ unsigned cursor to offset() ( - -

return«(peek40(cursor-POsn) » 8) * CRT_COlS * 4) + CURSOR_POSN & OxOff); }

/*---**--- convert input row-col to buffer offset */

/* input is row, col position */ unsigned calc offset(unsigned input) ( -return«(input » 8) * CRT COlS * 4) + input & OxOff);

} -/*---**---*/

return alpha or graphics mode flag

unsigned check mode() { -if «CRT MODE >= 4) && (CRT MODE <= 6» return(is_graphics); return(ii alpha); -

} -/*---**--­**---*/

expand the byte for mediun res. double the input byte to an output integer

unsigned expand byte(unsigned char the byte, {- -

register t~ = O· unsigned char mask = Ox80; while (mask != 0) {

}

t~ = temp « 2; if «the bYte & mask) != 0) if«color & Ox80) == 0)

else temp 1= (color & Ox03);

t~ A= (color & Ox03); mask = mask » 1;

unsigned char color)

return«(temp » 8) & OxOOff) 1 «temp «8 ) & OxffOO»; }

/*---------------------------------------------------*/ /*--- ---*/ /*--- load a word into the 6845 reg 'n' and 'n'+1 --*/ /*--- ---*/ /*---------------------------------------------------*/ void load 6845 word (unsigned address,l.I1Signed value) ( --

load 6845 ~te(address, value » 8); load:6845!byte(address + 1, value);

} - -

A-Type BiosKit

Page 152: Atbios Kit Nov89

/*------------------------------------------------*/ /*--- ---*/ /*--- load a byte into the 6845 reg 'n' ---*/ /*--- . ---*/ /*------------------------------------------------*/ void load 6845 byte(unsigned address,unsigned char value) ( --outportb(ADDR 6845 address); outportb«(AOaR 6845) + 1),value);

} -unsigned swap(unsigned aword) ( return«aword » 8) I (aword « 8»;

}

The Video Driver E· 7 ·15

Section E: The C Pro&rams

Page 153: Atbios Kit Nov89
Page 154: Atbios Kit Nov89

The Floppy Disk Driver E·8·1

EIGHT The Floppy Disk Driver

The Floppy Disk Driver is used to operate the floppy disk.

This driver structure has been organized to support up to four (4) floppy disk drives. The normal AT style disk controller does not provide the motor and select logic to do so. Two possible options are to:

1. Install a second controller at an alternate address and sense which port address should be referenced for each drive. This would entail declaring a "port" variable which would be used on the inport and outport commands.

2. Install a controller which does support four drive configurations. If such a controller is not commercially available, one may design and construct such a device by duplicating the standard functions and adding the required motor and select logic. Since newer LSI based floppy disk controllers (such as the Intel 82072) simplify this task, one may wish to consider this alternative.

Presuming that the new perpendicular-recording 4 Mbyte floppy disk drives will become desired options, the disk parameter tables are organized for easy expansion. By inspecting the defined tables in the source file, one will observe that some entries are already included for the 4 Mb drives. Take note that these drive parameters (and the 4Mb drives) have not been installed or tested on the Bios development system, so that some additional development work will be required to implement the 4 Mb drive type.

The standard location in the CMOS RAM for storing the drive types for Drive A: and B: is cell 10 hex. We have chosen the "reserved" cell 11 hex for storing the type byte for floppy Drives C: and D:.- If these should conflict with some other use, they may be re-assigned as you wish.

For those of you who are creating diskless systems, our Annabooks PromKit publication provides additional information on how the standard floppy disk driver may be replaced / chained / enhanced so a different physical device may be used for a logical floppy disk.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * : Module Name: AT Bios enhanced floppy disk driver

* Version: 1.02 * * Author: FOSCO * * Date: 10-20-89 * * Filename: atdisk.c * : Functional Description:

* Argunents: * * Return: * * Version History: * 1.01

Page 155: Atbios Kit Nov89

E·8· 2 The Floppy Disk Driver

* Moved misplaced perm table entry for 720k drive from index 2 to index 3 * 1.02 * Replaced peeks and pokes with casts : Moved variables to myblock

***************************************************************************************************/

/* INC L U 0 E F I L E S */

#include "atkit.h"

/* FUN C T ION PRO TOT Y PES */

void fdisk setup(void); void interrupt cdecl far disk io(void); void interrupt cdecl far disk:isr(void);

unsigned char send fdc(unsigned char); void send rate(unsTgned); unsigned retry(unsigned); unsigned char med change(unsigned); unsigned char calc sectors(unsigned); unsigned char cmos-type(unsigned char); unsigned char get~rm(unsigned,unsigned char); unsigned char wait int(void); unsigned recal(unsTgned); unsigned char seek(unsigned); void wait for head(unsigned); uns i gned Char-read i d( uns i gned) ; unsigned char get Tdc status(unsigned); unsigned char reaa dSKchng(unsigned); unsigned char resuTts(void)c unsigned char chk stat 2(VOld); vo id send spec i fy - conmind( uns i gned) ; void FOC reset(uniigned); void delay call(unsigned,unsigned)i unsigned cnar dma setup(unsigned,unsigned,unsigned); void purge fdc(voTd)c unsigned cnar fdc_inlt(unsigned);

/* G LOB A L CON S TAN T S */

extern disk io; extern :disk:isr;

/* G LOB A L V A R I A B L E S */

/* L 0 CAL 0 E FIN I T ION S */

#define FOC STATUS Ox42 #define olsf 10 Ox90 /* ~old drive/media type */ #define LAST:TRACK Ox94 /* 94-97 holds last track number */

#define RATE 500 OxOO #define RATE~OO Ox01 #define RATE-2S0 Ox02 #define RATE-1000 Ox03 #define INT 'LAG BIT7 #define MOTOR_WAIT Ox25

#def i ne BAD CtI) Ox01 #define BAD-ADOR MARK Ox02 #define WRITE PROTECT Ox03 #define RECORD' NOT FNO Ox04 #define MEDIA ~HAN~ Ox06 #def i ne BAD oRA OxOS #def i ne OMA-BOONOARY Ox09 #define MEO-NOT FND OxOc #define BAD-CRC- Ox10 #define BAD-FOC Ox20 #define BAD-SEEK Ox40 #define TIM~_OUT OxSO

/* function code definitions */

#define RESET OxOO #define READ STATUS Ox01 #define READ-SECTORS Ox02 #def i ne WR I T~ SECTORS Ox03 #define VERIFY SECTORS Ox04 #define FORMAT-TRACK OxOS #define DISK PXRMS Ox08 #define OIS~TYPE Ox1S #define DISK-CHANGE Ox16 #define FORMXT SET Ox17 #define SET_MED'IA Ox18

A· Type BiosKit

Page 156: Atbios Kit Nov89

#define BAD_FUNCTION Ox19

#define TRY Oxff

/* FOC port definitions */

#define OOR PORT Oxlf2 #define NSR-PORT Oxlf4 #define OAT~ PORT OxlfS #define DIR ~ORT Ox3f7 #define ORR:PORT Ox3f7

#define RQM BIT7 #define 010 BIT6 #define BUSY BIT4 #define OSKCHANGE_BIT BIT7

/* DNA port definitions */

#def i ne OMA MASK OxOa #def i ne DMA -..oDE OxOb #define OMA-FLFF OxOc #define OMA-ADR Ox04 #define DMA-BASE OxOS #define DMA:PAGE Ox81

/* OMA literal definitions */

#def i ne OMA ON Ox02 #define OMA-OFF Ox06 #def i ne OMA -RX MOOE Ox46 #define DMA-TX-MODE Ox4a #def i ne OMA -VRrt MODE Ox42 #define TX ~IR Ux01 #define RX:PIR OxOO

/* FOC commands */

#def i ne FOC READ Oxe6 #define FDC-WRITE OxcS #def i ne FDC-FORMA T Ox4d #define FDC:READID Ox4a

!*=== These are the floppy disk parameter tables =====

The Floppy Disk Driver E·8·3

* The tables are organized as an Array of up to 8 Drive types, each supporting up to 8 media types. * Each i tam is 16 bytes long * */ /* DISK TABLE indexes */

#define OT SPEC1 0 /I specify cornmand 1 #define OT-SPEC2 1 /I specify cornmand 2 #define DT-OFF TIM 2 // motor off count #define OT-BYT-SEC 3 // bytes/sector #define DT-SEC-TRK 4 // sectors/track #define DT-GAP) // gap #define DT-oTL 6 // dtl #def i ne DT-GAP3 7 // gap 3 for format cornmand #define OT-FIL BYT 8 /I fi II byte for format cornmand #define OT-HD TIM 9 // head settle time #define OT-STI TIM 10 // motor start time #define DT1NAx-TRK 11 // max , of tracks for drive #def i ne DT-RA T! 12 // data rate #define DT-TYPE // drive and media type (not used) #define DT:STEP 14 /1 double step flag

#define drive established Ox08 #define drive-field Ox07 #define drive-none 00 #define drive~ 01 #define drive-12 02 #define drive~O 03 #define drive-14 04 #define drive:28 05

#define media established Ox80 #define media-field Ox70 #define media-none OxOO #define media~ Ox10 #define media-12 Ox20 #define media~O OxlO #define media-14 Ox40 #define media-28 OxSO // media definitions for transition table

Section E: The C Pro&rams

Page 157: Atbios Kit Nov89

E·8·4 The Floppy Disk Driver

#def i ne m none OxO #define m~ Ox1 #define m-12 Ox2 #def i ne m f20 0x3 #define m-14 Ox4 #define m:28 OxS

#define m_wait Ox2S

1* L 0 CAL CON S TAN T S *1

const unsigned char transition table[8] [4]= { II This table covers the s~ence of media type to try for II each drive type in establishing the media in the drive. II The media is defaulted to the first item in this table II for a particular drive type. When we attempt retries, we II step through the possible media types until we come II to "none" marking the end of the table.

1* drive type 0 (None) *1 {m none,m_none,m_none,m_none}, 1* drive type 1 ( 360) *1 {m~, m none,m_none,m_none}, 1* drive type 2 ( 1.2) *1 {m 126 m~, m_none,m_none}, 1* drive type 3 ( 720) *1 {m~ , m none,m none,m none}, 1* drive type 4 (1.44) *1 {m-14, mf20, m-none,m-none}, 1* drive type 5 (2.88) *1 {m:28, m:14, m~O, m:none}, 1* drive type 6 unused *1 {m_none,m_none,m_none,m_none}, 1* drive type 7 unused *1 {m_none,m_none,m_none,m_none}, }i

const unsigned char fdisk table [8] [8] [16]= { 1* this entry is for compatibility with the XT disk driver *1 { 1* ---- drive type 0 = None (Default to 360) ----*1

{OxOaf,2,m_wait626960x2a,-1

60xSO,OxOf6,15,8,39,RATE_25O,drive_36OImedia_36O,0,0},

{O,O,O,O,O,O,O, , , ,0,0,0, ,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

},

{ 1* ---- drive type 1 = 360 ----*1

1* 0 = no media in 360 kb drive *1 {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

1* 1 = 360 kb media in 360 kb drive *1 {OxOaf,2,m_wait,2,9,Ox2a,-1,Ox50,OxOf6,15,8,.39,RATE_250,drive_36OImedia_36O,0,O},

1* 2-7 not used *1 {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

},

{ 1* ---- drive type 2 = 1.2 ------*1

1* 0 = no media in 1.2 mb drive *1 {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

1* 1 = 360 kb media in 1.2 mb drive *1 {Oxaf,2,m_wait,2,9,Ox2a,-1,Ox50,OxOf6,15,8,39,RATE_300 ,drive_12Imedia_36O,1,O},

1* 2 = 1.2 mb media in 1.2 mb drive *1 {Oxaf,2,m_wait,2,15,Ox1b,-1,Ox54,OxOf6,15,8,79,RATE_500 ,drive_12Imedia_12,O,0},

1* 3-7 = not used *1 {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

},

{ 1* ---- drive type 3 = 720 ------ *1

A-Type BiosKit

Page 158: Atbios Kit Nov89

/* ° = no media in 720 kb drive */ {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

/* 1-2 = not used *1 {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

The Floppy Disk Driver E·8·5

/* 3 = 720 kb media in 720 kb drive *1 {OxOaf,2,m_wait,2,9,Ox2a,-1,Ox50,OxOf6,15,8,79,RATE_250 ,drive_720Imedia_720,O,O},

/* 4-7 = not used */ {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

},

{ /* ---- drive type 4 = 1.44 ------*/

/* ° = no media in 1.44 mb drive *1 {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

/* 1-2 = not used *1 {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

1* 3 = 720 kb media in 1.44 mb drive *1 {Oxaf,2,m_wait,2,9,Ox2a,-1,Ox50,OxOf6,15,8,79,RATE_250 ,drive_14Imedia_720,O,0},

/* 4 = 1.44 kb media in 1.44 mb drive */ {Oxaf,2,m_wait,2,18,Ox1b,-1,Ox6c,OxOf6,15,8,79,RATE_500 ,drive_14Imedia_14,O,O},

/* 5-7 = not used */ {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

},

{

/*---- drive type 5 = 2.88 ------*/

// The 2.88 Meg drives have not been tested. // These tables are included as a help to integrating 2.88 drives into your system. II The correct parameters must be determined in conjunction with the drlve manufacturers II specifications.

/* ° = no media in 2.88 mb drive */ {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

/* 1-2 not used */ {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

/* 3 = 720 kb media in 2.88 mb drive */ {Oxaf,2,m_wait,2,9,Ox2a,-1,Ox50,OxOf6,15,8,79,RATE_250 ,drive_28Imedia_720,O,0},

/* 4 = 1.44 kb media in 2.88 mb drive */ {Oxaf,2,m_wait,2,18,Ox1b,-1,Ox6c,OxOf6,15,8,79,RATE_500 ,drive_28Imedia_14,O,O},

/* 5 = 2.88 kb media in 2.88 mb drive */ {Oxaf,2,m_wait,2,36,Ox1b,-1,Ox53,OxOf6,15,8,79,RATE_100O,drive_28Imedia_28,O,O},

/* 6-7 not used */ {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

},

{ 1*---- drive type 6 = reserved ------*/ {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}, {O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},

},

{ 1*---- drive type 7 = reserved ------*/

Section E: The C Pro&rams

Page 159: Atbios Kit Nov89

E·8·6 The Floppy Disk Driver

(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,0,0,0,0,0,0,0,0,0,0,0,~,0,0,0), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),

},

};

/* PRO G RAM */

/********************************************************* * : FOSCO Enhanced Floppy Disk Driver

: Copyright FOSCO 1988, 1989

**********************************************************1 /*

This driver uses a drive/media id byte as follows:

bit 7 0/1 = media not established I established

bit 6-4 media t~ 000 = no establlshed media 001 = 360 (40/SO track) 010 = 1.2 (SO track) 011 = 720 (SO track) 100 = 1.4 (SO track) 101 = 2.8 (SO track) 110 - 111 reserved

bit 3 = 0/1 = drive not established I established

bit 2-0 Drive type 000 no established drive type 001 = 360 (40 track) 010 = 1.2 (SO track) 011 = 720 (SO track) 100 = 1.4 (SO track) 101 = 2.8 (SO track) 110 - 111 reserved

The drive/media bytes are located at 40:90-93 for up to four drives.*1

1*======================================================*1 1*=================== START OF CODE ====================*1 1*======================================================*1 variables unsigned char fd drive type; unsigned char fastate; uns i gned char fa fdc comnand; unsigned char fadna-comnand· unsigned char fasector trac~; unsigned char famedia type; unsigned char fafcode; unsigned char fadrive; unsigned char fanr sectors; unsigned char fdrheid; unsigned char fasector; unsigned char fatrack; unsigned fd max track; unsigned famax-sectors; unsigned fai; -unsigned fatry count; unsigned fameOi'a index; unsigned char ena-track,end head,end sector,num sectors,sectors track; unsigned dma address; - - - -unsigned loni lcheck; unsigned nibble, upper byte, lower byte, length; unsigned char error byte, time out flag; end_variables fdisk:regs; - -

1*-------------- setup the controller -----------*1 void fdisk setup () ( -fdisk regs *myblock· mybloek = acquire_b(ock(FLOPPY);

link_interrupt(Ox13,&_disk_io);

A-Type BiosKit

Page 160: Atbios Kit Nov89

link interrupt(OxOe,& disk isr)· set_vector(Ox1e,bios_cs(),lfdisk_tableCO] [0] [0]);

outportb(Ox21,inportb(Ox21) & -BIT6); II unmask SEEK STATUS = 0; 1* clear seek status *1 MOT~ COUNT = O· 1* clear motor count *1 MOTOR-STATUS = 0; 1* clear motor status *1 DISK_~TATUS = 0; 1* clear disk status *1 HF CNTRL 1= 1; RT~ WAIT ~LAG 1= 1· pokib40(~ISK 1~+O,O); pokeb40(DISK-ID+1,0); pokeb40(DISK-ID+2,0); pokeb40(DIS~ID+3,0);

1* clear drive 0 state *1 1* clear drive 1 state *1 1* clear drive 2 state *1 1* clear drive 3 state *1 pokeb40(DISK ID+O,cmos type(O»; pokeb40(DISK-ID+1,cmos-type(1»; pokeb40(DISK:ID+2,cmos:type(2»; pokeb40(DISK_ID+3,cmos_type(3»;

int's

RTC WAIT FLAG &= Oxfe; 1* allow for rtc wait *1 MOT~R_COONT = get-PBrm(myblock,2); 1* set motor count */

myblock -> dx = OxOOOO; myblock -> ax = OxOOOO; 1* reset the FDC *1 sys_int(Ox13,myblock); release blocK(myblock);

) -1*========================================================*1 1*========================================================*1 1*========================================================*1 1*======== BEGINNING OF MAIN ROUTINES ===================*1 1*========================================================*/ /*========================================================*1 1*========================================================*/ 1* handle the floppy disk function service call *1 void interrupt cdecl far disk io(interrupt registers) ( --

The Floppy Disk Driver E·8· 7

fdisk regs *myblock; /1 disible(); II some XT type disk controllers will pre-enable myblock = acquire_block(FLOPPV);

1/ enableO;

snapshot_in(FLOPPV,&es);

myblock->fd fcode = ax » 8· myblock->fdrdrive = dx & OxOOff; myblock->fdrnr sectors = ax & OxOOff; myblock->fdrheid = dx » 8· myblock->fdrsector = cx & OxOOff; myblock->f~track = cx » 8;

flags &= -Ox0001; /* clear the carry flag for returns *1 DISK_STATUS = 0; 1* clear status *1 if «(ax » 8) 1= 0) && «dx & OxOOff) > 3» { II bad function code because of drive number

DISK STATUS = BAD CMO; ax = (BAD CMO « 8) 1 (ax & Oxff); flags 1= 1; 1* sit return error-flag *1

) else ( 1* make sure any residual status is unloaded */ purge fdc(); /* set the data rate register to a default value *1 outportb(DRR_PORT,RATE_250);

switch (myblock->fd fcode) ( -case RESET: 1* reset the disk controller */ watch string(FLOPPV,"Reset"); Foe reset(myblock); ax = (DISK STATUS « 8) Il (ax & Oxff); if «ax & UxffOO) != 0) fags 1= 1; break;

case READ STATUS: watch strTng(FLOPPV,"Read Status"); ax = ~ISK STATUS « 8· if «ax &-OxffOO) != 0) flags 1= 1; break;

Section E: The C Pro&rams

Page 161: Atbios Kit Nov89

E·8·8 The Floppy Disk Driver

case READ SECTORS: /* read sectors */ watch strTng(FLOPPY,"Read sectors"); MOTOR-STATUS &= -INT FLAG; rnybloek->fd fde comnind = FDC READ; myblock->fdrdma-command = OMA-RX MODE; goto read_write:verify; --

case WRITE SECTORS: watch stri;lg(FLOPPY6"Write sectors"); MOTOR-STATUS /= Ox8 ; mybloek->fd fde command = FDC WRI!!i myblock->fdrdma-command = DMA-TX JlllWE; goto read_write:verify; --

case VERIFY SECTORS: watch strinj(FLOPPY,"Verify sectors"); MOTOR-STATUS &= -INT FLAG; rnybloek->fd fde_commind = FDC_READ; rnyblock->fdrctna command = DMA VRFY MODE; goto read_write:verify; --

read_write_verify:

// if a media change sensed, then de-establish media if (med change(myblock) == error) ( -andb40(DISK ID+myblock->fd drive,OxOf); myblock->fdrmedia index = U;

} --rnyblock->fd try count = 3-do // this-is the major loop, try the major operation 3 times ( watch_string(FLOPPY,"\n\rMajor Loop");

// if media not established, then set media type = drive type // set media_index = 0, set media type by index

if «peekb40(DISK ID+myblock->fd drive) & media established) == 0) ( - - -// set the media index for the first possible type of media myblock->fd_drive_type = peekb40(DISK_ID+myblock~>fd_drive) & Ox07i

II set the DISK to with the first media type to try pokeb40(DISK ID+myblock->fd drive,(peekb40(DISK ID+myblock->fd drive) &

-media field) I - - -- (peeibcs(&transition table[myblock->fd drive type] [0]) « 4»;

// set the media type according to the drive type [iriaex = U] }myblOCk->fd_media_type = (peekb40(OISK_ID+myblock->fd_drive) » 4) & Ox07i

do II this is the minor loop /1 do I.I1ti l we rim out of retrys (

watch string(FLOPPY," Minor Loop II); purge:fde()i 1* make sure any residual status is unloaded */

/I set ~ drive and media indexes before doing the dna setup, /I which needs to know how many bytes per sector for calcing xfr length myblock->fd drive type = peekb40(DISK tD+myblock->fd drive) & Ox07i myblock->fdrmedia-tYDe = (peekb40(DISf ID+myblock->fa drive) » 4) & Ox07; watch strinj(FLOPJSY:h Disk to byte = Ill; -watch:Pvte(FlOPPY,peekb40(OISK_ID+myblock->fd_drive»;

if (ana setup(myblock,es,bx) == ok) ( -/* send the specify command *1 send fde(3); sena-fde(get-P8rm(myblock,O»i s~fde(get-P8rm(myblock,1»;

send_rate(myblock)i

if (fde init(myblock) == ok) { -

if (send fdc(rnyblock->fd track) == ok) {- -if (send fdc(rnyblock->fd head) == ok) {- -if (send fdc(myblock->fd sector) == ok) {- -if (send fdc(get narm(myblock,3» == ok) { _ ..r-

if (send fde(get narm(myblock,4» == ok) ( _ ..r-

if (send_fde(get,J)8rm(myblock,S» == ok)

A-Type BiosKit

Page 162: Atbios Kit Nov89

The Floppy Disk Driver E·8·9

( if (send_fdc(get-P8rm(myblock,6» == ok) (

if(get fdc status(myblock) == ok) ( --

operation orb40(DISK_ID+myblock->fd_drive,media_established); break; II get out with good

} }

}

} }

} }

}

} }

}

while (retry(myblock) == error); watch string(FLOPPY,"\n\rDISK STATUS = 1I);watch byte(FLOPPY,DISK STATUS);

} - --while «--myblock->fd try count> 0) &&

«peekb40(DISK-ID+ffiyblock->fd drive) & media established) == 0) && «DTSK STATUS & TIRE OUT) 1= TIME-OUT»;

ax = (DISK STATUS « 8) T (calc sectors(myblock»; -if «ax & OxffOO) != 0) flags 1= 1; break;

case FORMAT TRACK: 1* format track *1 watch string(FLOPPY,"Format trackll)t" mybloek->fd fdc_command = FDC_FORMA ; myblock->fdd'na command = DMA TX MODE; II if media-not-established then set media t'(Pe = drive type if «peekb40(DISK ID+myblock->fd drive) & medla established) == 0)

pokeb40(DI~K ID+myblock->ld drive -(piekb40(DISK ID+mMblock->fd drive) & Ox07) 1

«piekb40(DISK_ID+ffiyblock->fd_drive) & Ox07) « 4»;

MOTOR STATUS 1= Ox80; /* indicate write operation *1 if (mid change(myblock) == ok) 1* check for media change */ ( -watch string(FLOPPY,"\n\rNo media chan2ell); send ldc(3); /* send specify command / sendfdc(get.J)8rm(myblock,O»; se~fdc(~et..P8rm(myblock,1»c watcn strlnglFLOPPY,"\n\rSpeclfy Command Sent"); send rate(myblock); if (ams setup(myblock,es,bx) == ok) ( -

} }

watch string(FLOPPY,"\n\rDma Setup Ok"); if (fac init(myblocK) == ok) ( -

}

watch string(FLOPPY,"\n\rFDC Init Ok"); if (send fdc(get nArm(myblock,3» == OK) ( - .....-watch string(FLOPPY,"\n\rSent parm 311

);

if (send fdc(get nArm(myblock,4» == OK) ( - .....-watch string(FLOPPY,"\n\rSent parm 411 );

if (send fdc(get nArm(myblock,7» == OK) ( _ ..r-

} }

}

watch_string(FLOPPY,"\n\rSent parm 7");

send fdc(~et-P8rm(myblock,8»; 1* send command *1 watcn_strmglFLOPPY,"\n\rFDC Commands all sent");

get fdc status(myblock); watCh_string(FLOPPY,"\n\rFDC status rx'd");

ax = DISK STATUS « 8-if «ax &-OxffOO) != 6) flags 1= 1; break;

case DISK PARMS : 1* read drive parameters */ watch strTng(FLOPPY,"Read disk parms ll );

ax = Ex = cx = dx = es = 0i 1* reset all registers *1 if (myblock->fd drive> OxeO) { -lax = (ax & Oxff) 1 (BAD_CHO « 8); flags 1= 1; 1* set return error flag *1

Section E: The C ProlUams

Page 163: Atbios Kit Nov89

E·8·10 The Floppy Disk Driver

else { if «EQUIP FLAG & Ox01) 1= 0) 1* there are drives present */ { -di = dx; II save old dx temporarily dx = EQUIP FLAG » 6; 1* return J of drives in dx */ if (di > dx) 1* called for a non-existent drive *1 di = 0; 1* return with null parameters *1 else { di = 0; if (cmos type(myblock->fd drive) 1= 0) 1* get parms for this type */ (- -

myblock->fd_drive_type = myblock->fd_media_type = cmos_type(myblock->fd_drive) & Ox07;

di = &fdisk table[myblock->fd drive type] [myblock->fd media t~] [0]; myblock->f~sector track = peikbcs(Ifdisk table[mybloCk->f~dr1ve type] [myblock-

>fd medi a type] [DT-SEC TRf]); - --- mY6lock->f~max-track = peekbcs(&fdisk table[myblock->fd drive type] [myblock-

>fd media type][DT~-TRK]); - --- cx-= «myblOck->fd max track « 8) & OxffOO) / (myblock->fd sector track & Ox3f);

dx = (1 « 8) I dx':' - - -bx = cmos type(myb(ock->fd drive) & Ox07; es = bios-cs(); II nieds to be our code segment

) -)

) ) break;

case DISK TYPE: 1* read disk type *1 watch_strTng(FLOPPY,"Read disk type");

ax &= OxOOff; 1* no drive */

~f «peekb40(DISK_ID+myblock->fd_drive) & drive_field) 1= drive_none)

if «peekb40(DISK_ID+m¥block->fd_drive) & drive_field) .= drive_36O) ( ax /= Ox0100; 1* 40 track, no change line */

) else (

) ax /= Ox0200; /* 80 track, change line */

) break;

case DISK CHANGE: /* return change line condition */ watch strTn\J(FLOPPY,"Read disk change line"); 1* if-no dr1ve - then return a timeout condition */ if «peekb40(DISK ID+myblock->fd drive) & drive field) == drive_none. ) ( - - -

DISK STATUS /= TIME OUT; ) - -else { /* if 360 k drive - always return disk change */ if «peekb40(DISK ID+myblock->fd drive) & drive field) == drive 360) DISK STATUS = MEDTA CHANGE; - - -else- -1* if 720, 1.4, or 2.8 drive - read the change line */ if (read dskchng(myblock) f. 0 ) DISK STATUs. MEDIA CHANGE;

) - -ax = (DISK STATUS « 8) I (ax & Oxff); if «ax & UxffOO) 1= 0) flags /= 1; break;

case FORMAT SET : /* set disk type */ watch_stri"g(FLOPPY,"Set disk type");

1* set drive to requested format/media */ myblock->fd_drive_type = peekb40(DISK_ID+myblock->fd_drive) & Ox07;

switch (ax & OxOOff) /* use requested type for switch */ ( case 1: /* 360/360 */ if(mvblock->fd drive type == drive 360) pokeb40(DISK I~+myblOck~>fd drive,fmedia 360 drive_360 / media_established»; break; - - -

case 2: /* 360/1.2 */ if(mvblock->fd drive type == drive 12) pokeb40(DISK_I~+myblOck~>fd_drive,fmedia_360 drive_12 / media_established»;

A-Type BiosKit

Page 164: Atbios Kit Nov89

The Floppy Disk Driver E·8·1I

break;

case 3: /* 1.2/1.2 */ if(mvblock->fd drive type == drive 12) pokeb40(DISK_I~+myblOck~>fd_drive,(media_12 drive_12 1 media_established»; break;

case 4: /* 720/720 */ if(mvblock->fd drive type == drive 720) pokeb40(DISK_I~+myblock~>fd_drive,(media_720 drive_720 1 media_established»; break;

default: DISK STATUS = BAD CMO; /* bad conmand * / breai; -

} ax = (DISK STATUS « 8) I (ax & Oxff); if «ax & UxffOO) 1= 0) flags 1= 1; break;

case SET MEDIA : /* set media type */ watch st'Fing(FLOPPY,IISet media type"); // get the max tracKS called for myblock->fd max track = (cx » 8) 1 «cx « 2) & 0x300); // get the max sectors called for myblock->fd max sectors = cx & Ox003f; if (cmos type(myblock->fd drive) 1= 0) (- -

myblock->fd drive t~ = cmos type(myblock->fd drive) & Ox07; watch string(FLOP'Y, '\n\rDrive 1S ")iwatch byte(FLOPPY,myblock->fd drive); watch-string(FLOPPY,"\n\rDrive type 1S ");watch_byte(FLOPPY,mybloci->fd drive type); // -myblock->fd drive type = peekb40(DISK ID+ffiyblock->fd drive)& Ox07; -// use the transition tible for this drive - -for (myblock->fd i= O;peekbcs(&transition table[myblock->fd drive type] [myblock->fd il) 1=

O·myblock->fd i++) - - - - -, ( -myblock->fd media tvce = peekbcs(&transition table[myblock->fd drive type] [myblock->fd ill; watch_stri"g(FLOPPV:"\n\rMedia type is ");watch_byte(FLOPPY,my6lock->fd_media_type); -

if «myblock->fd max sectors == peekbcs(&fdisk table[myblock->fd drive type] [myblock->fd medi a typel [DT SEC TRfJ» && \ - --

- - - (ffiyblock->fd_max_track == peekbcs(&fdisk_table[myblock->fd_drive_typel [myblock->fd media typel [DT MAX TRK]»)

-{ - - - .

// return the disk perms ptr to the caller di = &fdisk_table[myblock->fd_drive_typel [myblock->fd_media_typel [0]; es = b10S cso-// set the dis~ id to the established supported media pokeb40(DISK ID~lock->fd drive,myblock~>fd drive type 1 (myblock->fd_media_type « 4) drive established I media established); - -watch-string(FLOPPi',"\n\rAedia established, drive byte is: II); watch~te(FLOPPY,peekb40(DISK ID+myblock->fd drive»; 1/ need a break to say OK here-III -goto set media exit;

} --} if (peekbcs(&transition table[myblock->fd drive typel [myblock->fd i]) == 0) DISK STATUS = MED NOT FlO; - - -

} - - -set media exit: ax = (DISf STATUS « 8) I (ax & Oxff); if «ax & UxffOO) 1= 0) flags 1= 1; break;

default: /* invalid function code - return bad code */ watch string(FLOPPY,"Bad COIIEnd"); DISK !TATUS = BAD CMO; ax =-(BAD CMO «8) I (ax & Oxff); flags 1= T; /* set return error flag */

} /* end of switch */

}

snapshot_out(FLOPPY,&es);

MOTOR_COUNT = get-P8rm(myblock,2); /* set motor count */ release_block(mybTock);

} /* end of disk_io */

/*=======================================================*/

/*=======================================================*/

Section E: The C Pro&rams

Page 165: Atbios Kit Nov89

E·8·12 The Floppy Disk Driver

1* reset the disk system *1 void FOC reset(fdisk regs *myblock) (- -

unsigned i· unsigned c~ar status;

disable(); status = (MOTOR STATUS «4) 1 8; II if a motor is on, set the drive select bits accordingly switch (status & OxfO) { 1* motor 2 on *1 case Ox20: status 1= Ox01; break;

1* motor 3 on */ case Ox40: status 1= Ox02: break;

1* motor 4 on */ case Ox80: status /= Ox03; break;

} outportb (OCR PORT,status): 1* reset disk controller */ SEEK STATUS =-0; outpOrtb (OCR PORT,status 1 Ox04); 1/ reset the reset bit enable(); 7* enable interrupts */ /* wait for interrupt */ if (wait int() == error) { DISK STATUS 1= BAD FOC; return; } for (i =-0; i < 4: i++) /* number of drives-*I ( 1* send command *1 if (send_fdc(8) == error) { DISK_STATUS /= BAD_FOC; return; } 1* check results *1 if (results() 1= ok) { DISK STATUS 1= BAD FOC; return· }

}if (peekb40(FOC_STATUS) 1= {i / OxcO» { ~ISK_STATUS 1= BAD_FOC; return; }

send specify command(myblock); } - -1*======================================================== When the hardware interr~t occurs from the floppy disk, this function sets bit 7 1n the seek status flag and sends an end·of-interrupt command to the 8259. ----_._--_._._----------_ •• _------_ ••••••• _._--_. __ ._---*/

void interrupt cdecl far disk isr (void) { -

SEEK STATUS 1= INT FLAG: outportb (Ox20,Ox20); /* send eoi */ } - -1*===:================::=======================:=========== Return the drive type for a specified drive. --_ .. _-_._-.--.- .. __ ._._------.---_._----_._--._---_.-_._*/

unsigned char cmos t~ (unsigned char drive nr) { - ,~ -unsigned char drive type = 0; switch(drive nr) -( -case 0: drive type = incmos(Ox10) » 4· break; case 1: drive-type = incmos(Ox10) & Ox6f; break: case 2: drive-type = incmos(Ox11) » 4· Dreak; case 3: drive-type = incmos(Ox11) & Ox6f: break:

} -if (drive_type 1= 0) drive_type 1= drive_established; return(drlve type):

} -1*======================================================== Send a byte to the Foe.

---------------------------_._.-_._---------------------*/ uns i gned char send fdc( uns i gned char pann) { -unsigned long i = set_timeout_count(5):

do { if «inportb(MSR PORT) & OxcO) == RQM) { -

A-Type BiosKit

/1 wait at least 1 sec

Page 166: Atbios Kit Nov89

The Floppy Disk Driver E·8·13

}

} }

outportb(DATA PORT,parm); delay_call(O,;O); 1* delay at least 50 useconds *1 return (ok);

while CTIMER LONG < i); DISK_STATUS T= TIME_OUT; return (error);

1*==========================================================

Get the indexed value from the disk parameter table.

------------------------------------------------------ --*1 (nsigned char getJ)8rm(fdisk_regs *~lock,unsigned char index)

}returnCpeekbcS(&fdisk_table[myblock->fd_drive_type) [myblock->fd_media_type] [index]»;

1*========================================================== Send the specify command to the FDC.

------------------------------------------------------ --*1 void send specify command (fdisk regs *myblock) ( - - -send fdc(3); sendrfdc(getJ)8rm(myblock,O»; sendrfdc(get nArm(myblock,1»; 1* send command *1 } _ -r-

1*=======================================================*1 1*=======================================================*1 1*=======================================================*1 1*====================================================== Turn motor on and wait for motor start up time if this is a write operation. Proceed inmediately if a read operation. 1. save the last state of the motor. 2. turn on the selected motor. 3. if not a write, exit inmediately. 3. if a write, if the same motor was already on, exit, else wait for the delay.

------------------------------------------------------ --*1 void motor on(fdisk regs *myblock) ( - -

}

unsigned char this_motor, last_motor, wait;

disable(); MOTOR COUNT = Oxff; 1* hit' timer with max on-ccx.nt *1 last motor = MOTOR STATUS & OxOf; wait-= MOTOR STATUI & Ox80; MOTOR STATUS-= this motor = (1 « ~lock->fd drive); outportb(DOR_PORT,(this_motor « 4) I OxOc I ffiybLock->fd_drive); enable(); if«last motor != this motor) && (wait != 0» (- -II delay for a write and a motor start II force a delay in 1/8 seconds II delay = (resolution,ccx.nt) in milliseconds *1 delay_cal l (125

6getJ)8rm(myblOCk, 10»;

MOTOR COUNT = xff; 1* hit' timer with max on-ccx.nt */ watch string(FLOPPY,"\n\rMotor on Delay = II); watch:hYte(FLOPPY,get nArm(myblock,10»; } _ -r-

1*======================================================== Wait for the hardware interrupt to occur. Time-out and return if no interrupt.

------------------------------------------------------ --*1 unsigned char wait int (void) ( -1* this time out should be 3 secs *1 unsigned long i = set_timeout_ccx.nt(3 * 20);

Section E: The C ProlUams

Page 167: Atbios Kit Nov89

}

E·8·14 The Floppy Disk Driver

disable()· outportb(6x21,inportb(Ox21) & -BIT6): enable(); .; do ( }if«SEEK_STATUS & INT_FLAG) 1= 0) { SEEK_STATUS &= -INT_FLAG: return (ok): }

while (TIMER LONG < i); DISK_STATUS T= TIME_OUT: SEEK_STATUS &= -INT_FLAG; return (error);

I*=================~=====================================

Send the data-transfer-rate command to controller

--------------------------------------------------------*/ void send rate(fdisk regs *myblock) ( - -outportb(DRR PORT,peekbcs(&fdisk table[~kb40(DISK ID+mvblock->fd drive) & Ox07] [(peekb40(DI!K_ID+inyblock->fd_drTve) » 4) & Ox07] tIfT_RAtE]»: -

}

1*================================:=:::==:=::::=::::=====

Process the interrupt received after recalibrate or seek.

--------------------------------------------------------*/ unsigned char chk stat 2 (void) { - -if (wait int() == error) return (error): if (sena-fdc(8) == error) return (error): if (resuTts() == error) return (error): if «peekb40(FDC STATUS) & Ox60) == Ox60) /* normal termination */ ( -watch string(FLOPPY,It\n\rSeek Error, fdc status was - It): watch~te(FLOPP!!peekb40(FDC STATUS»: DISK_STATUS 1= BAD_SEEK; -return (error);

} return (ok);

}

/*======:::==:=============================================

Initialize dma controller for read, write, verify operations.

---------------------------------------------------------*/ unsigned char dma setup(fdisk regs *myblock,unsigned es,unsigned bx) ( - -disable(); /* disable interrupts */ outportb(DMA FLFF,OxOO)· /* set the first/last ff */ outportb(DMA]tASK,DMA_OFF): /* disable chamel whi le loading */

outportb(DMA MOOE ,myblock->fd dna cocmw.d); /* output mode byte * / if (myblock->fd dma command =- DNX VRFY MOOE) /* ana verify command? */ { /* yes */- - - -myblock->dma address = 0; myblock->lowir byte = 0; myblock->upper~te = 0; myblock->nibbli = 0:

} else { myblock->dma address = es + (bx » 4); myblock->nib6le = myblock->ana address » 12; myblock->upper byte = myblock->dna address » 4· myblock->lower~te = (myblock->dmi address «4) 1 (bx & OxOOOf);

} - -myblock->length = «myblock->fd nr sectors * 128) « get-P8rm(myblock,3» - 1; watch_string(FLOPPY,"\n\rTransfir Tength = II); watch word(FLOPPY,myblock->length); outportb(DMA ADR,myblock->lower byte); /* output low address */ outportb(DMA-ADR,myblock->upper~te); /* output high address */ outportb(DMA-PAGE,myblock->nibbTe)· /* output page address */ outportb(DMA-BASE,myblock->length 1 Oxff); // output low byte length outportb(DMA-BASE,mvblock->length »8): // output high byte length enable(): -/* enable interrupts */

outportb(DMA_MASK,DMA_ON); /* init disk channel */

A-Type BiosKit

Page 168: Atbios Kit Nov89

The Floppy Disk Driver E·8·1S

myblock->lcheck = 0; myblock->lcheck = «myblock->upper byte & Oxtt) « 8) I (myblock->lower byte & Oxtt); myblock->lcheck = myblock->lcheck + (unsigned long) myblock->lengthi -if (myblock->lcheck & OxffffOOOO) /* test for overflow */ ( /* overflow */ .

}

DISK STATUS = DMA BOUNDARY; watcn string(FLOP~,II\n\rDMA overflow"): return (error):

return (ok); }

/*==========================================================

Move the head to the selected track.

--------------------------------------------------------*/ unsigned char seek(fdisk regs *myblock) { -//unsigned char drive type,media t~: if «SEEK STATUS & (T « mybloci->fd drive» == 0) /* need recal */ {- -

SEEK_STATUS 1= (1 « myblock->fd_drive): /* mark recal will be done *1

/* try 2 attemps at recalibrate, then if failed, return error *1 if (recal(myblock) == error) (

DISK STATUS = 0; if (recal(myblock) == error) return (error);

} pokeb40(LAST TRACK+(myblock->fd drive)eO): 1* clear track number *1 /* if we want track zero, then just walt for head and exit *1 if (myblock->fd track == 0) ( wait for head(myblock): return (ok): }

} - - -if (peekbcs(&fdisk table [myblock->fd_drive_type] [myblock->fd_media_type] [DT_STEP]) 1= 0)

myblock->rd track *= 2; if (peekb40(LAST TRA~K+myblock->fd drive) == myblock->fd track)

}

return{ok)t - -1* ~ate new POSitlon *1

pokeb40(LAST TRACK+myblock->fd drive,myblock->fd track); if (send fde{OxOf) == error) return (error): -if (s~fde(myblock->fd drive) == error) return (error); if (sendrfdc(~lock->f~track) == error) return (error): if (chk stat 2() == error) return (error): wait for heaa(myblock): return ('ok):

/*=========================================================

Recalibrate the drive.

------------------------------------------------------ -*1 unsigned recal(fdisk regs *myblock) { -

}

if (send fde(7) == error) return (error); if (s~fdc(myblock->fd drive) == error) return (error); /* send comnand *1 -if (chk stat 2() == error) return (error); /* return with error *1 return (ok): 1* return with no error *1

1*===========================================================

Determine whether a retry is necessary. Returning an OK says don't retry any more Returning an ERROR says retry again

------------------------------------------------------ ---*1 unsigned retry(fdisk regs *myblock) { -

unsigned char media t~: 1* if operation timed out - say no retry *1 if «DISK STATUS & TIME OUT ) == TIME OUT) return (ok): 1* if media is establisned - say no retry *1 if «peekb40(DISK_ID+myblock->fd_drive) & media_established) 1= 0) return (ok):

1* we have to step through the media *1 II ~et the next possible media type for this drive type medla_type = peekbcs(&transition_table[myblock->fd_drive_typel [++myblock->fd_media_indexl);

Section E: The C ProlUams

Page 169: Atbios Kit Nov89

E·8·16 The Floppy Disk Driver

if (media type == media none) II then at end of possibles (- -

}

II dis-establish media I I return - no more andb40(OISK_IO+myblock->fd_drive,-(media_established 1 media_field»; return(ok); .

II insert the new media type into the DISK ID and return saying try again pok~0(OISK_IO+myblock->fd_drive,(peekb40{DISK_IO+myblock->fd_drive) & -media_field) (medta_type « 4»;

DISK STATUS = 0; poke640(FOC STATUS,O); return(error); 1* return saying retry *1

}

1*======================================================= Read anything from the controller following an interrupt. This may include up to seven bytes of status.

--------------------------------------------------------*/ unsigned char results (void) {

}

unsigned long i; unsigned char count, flag;

for (count = 0; count < 7; COU'lt++) . I I get up to seven bytes ( flag = error; i = set_timeout_cOU'lt(2); II set delay to 50-100 ms.

do { if «inportb(MSR PORT) & OxcO) =- OxcO) 1* data available from FOC */ ( -

}

pokeb40(FOC STATUS+cOU'lt,inportb(OATA PORT»; 1* save status *1 delay call(U,100); 1* at least 100 us-for the FOC */ flag =- ok;

/* check busy bit *1 if «inportb(MSR PORT) & BUSY) == 0) return (ok);

} -while (TIMER LONG < i)· if (flag == error) ( DiSK STATUS 1= TIME OUT; return (error); )

} --DISK_STATUS 1= BAD_FOC; 1* too many bytes *1 return (error);

/*========================================================

Purge the Foe of any status it is waiting to send.

--------------------------------------------------------*/ void purge fdc (void) { -

}

while «inportb(MSR PORT) & OxcO) == OxcO) ( -

inportb(OATA PORT); /* read status */ delay call(O;SO); 1* at least 50 us for the FOe */

} -

/*=======================================================

Read the state of the disk change line.

--------------------------------------------------------*/ unsigned char read dskchng(fdisk regs *myblock) ( - -motor on(myblock); /* turn motor on *1 return (inportb(OIR PORT) & DSKCHANGE BIT);

} - -1*======================================================= Execute the FOe read id command.

------------------------------------------------------ --*1 unsigned char read_id (fdisk_regs *myblock)

A-Type BiosKit

Page 170: Atbios Kit Nov89

The Floppy Disk Driver E-8-17

{ if (send fde(FDC READID) == error) return(error); if (sena-fde(mybTock->fd head « 2 I myblock->fd_drive) == error) return (error); return (get fde status(myblock»; }-

/*====================================================== Wait for the head to settle after a seek.

-------------------------------------------------------*/ void wait for head(fdisk regs *myblock) ( - - -unsigned char wait;

wait = get~rm(myblOCk69); /* get head settle */ if «MOTOR STATUS & Ox8 ) 1= 0) // if write { /* yes */

if (wait == 0) /* wait zero? */ { /* yes */ if «~kb40(DISK ID+(myblock->fd drive» » 4) & Ox07) wait = Ox14; /*-default 360 heaa time */ else wait = OxOf; /* default others head time */

} } else { if (wait == 0) /* is wait zero? */ return; /* yes, return */

} delay call(1,wait); /* delay n miLLiseconds */

} -/*========================================================= Checks for a media change, reset media changes and check media changes.

Returns: ok = medi a not changed, error = medi a changed

-------------------------------------------------------*/ unsigned char med change(fdisk regs *mybLock) { - -

}

if (read dskchng(mybLock) == 0) return (ok); /* clear-media estabLished and media type */ andb40(DISK_ID+mybLock->fd_drive,-media_estabLished);

disabLe(); MOTOR STATUS &= -(1 « myblock->fd drive); /* turn off motor status */ -enable(); motor_on(mybLock)i FDC reset(mybLock); mybTock->fd track = 0; seek(mybloci) ; mybLock->fd track = 1; seek(mybLoci); DISK STATUS = MEDIA CHANGE; if (read_dskchng(mYSlock) 1= 0) DISK_STATUS = TIME_OUT; return (error);

/*======================================================== Seek to the requested track and initialize the controller

--------------------------------------------------------*/ unsigned char fde init(fdisk regs *myblock) ( --motor on(myblock); if (seek(myblock) == error) return (error); if (send fdc(myblock->fd fde command) == error) return(error)i if (send[fde«(myblock->Td_head «2) & 81T2) I myblock->fd_drlve) == error) return(error);

} return (ok);

/*======================================================= Wait untiL an operation is compLete, then accept the status from the controller.

Section E: The C ProlD"ams

Page 171: Atbios Kit Nov89

E·8·18 The Floppy Disk Driver

--------------------------------------------------------*/ unsigned char get_fdc_status(fdisk_regs *myblock) (

}

myblock->time out flag = wait int(); if (results()-== error) return (error); if (myblock->time_out_flag == error) { if (DISK STATUS == 0) return(ok); else return(error);

} -if «peekb40(FDC STATUS) & OxcO) == 0) { -if (DISK STATUS == 0) return(ok); else return(error);

} -if «peekb40(FDC_STATUS) & OxcO) 1= Ox40) { DISK_STATUS 1= BAD_FDC; return(error); }

mvblock->error byte = peekb40(FDC STATUS + 1); j*-get controlTer status */ -if «myblock->error byte & BIT7) 1= 0) {DISK STATUS = RECORD NOT FND;} else if «myblock->error:pyte & BIT5) 1= 0) {DISK-STATUS = BAD CRfi} -else if «myblock->error~yte & BIT4) 1= 0) {DIS~STATUS = BADiDMA;) else if «myblock->error]bYte & BIT2) 1= 0) (DIS~STATUS = RECaRD NOT FNOi) else if «myblock->error~te & BIT1) 1= 0) {DIS~STATUS a WRITE ~ROT~CT;} else if «myblock->error:pyte & BITO) 1= 0) {DISK-STATUS = BAD_~DR_MARK;) else (DISK STATUS 1= B~ FDC;) -if (DISK STATUs 1= 0) return(error); return( OK);

/*=======================================================

calculate number of sectors that were actually transferred_

returns: number of sectors transferred

--------------------------------------------------------*/ unsigned char calc sectors (fdisk regs *myblock) { - -

if (DISK_STATUS 1= 0) return (0);

myblock->sectors_track = get-PBnm(myblock,4); myblock->end track = ~kb40{FOC STATUS + 3); myblock->endrhead = peekb40(FOC tTATUS + 4)­myblock->end'sector = ~kb40(F~C STATUS + ~); myblock->num-sectors = 0; -if (myblock->end track 1= myblock->fd track)

myblOCK->num sectors += mybTock->sectors track; if (myblock->end head T= myblock->fd head) -

myblocK->num_sectors += mv6lock->sectors track; myblock->num_sectors += (myblock->end_sector - mybTock->fd_sector); return(myblock->num sectors);

} - .

/*====================================================*/

A· Type BiosKit

Page 172: Atbios Kit Nov89

The Hard Disk Driver E·9·1

NINE

The Hard Disk Driver

The Hard Disk Driver is used to operate an optional hard disk drive. This driver supports the standard AT type of hard disk controller. Other disk interfaces such as SCSI, ESDI, and SMD may require drastically different hardware level interaction, but the Bios register interface will remain the same as in this driver. If you are developing any of these drivers, this module may be used as a starting point, since the functional requirements at the Bios function call interface remain the same.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * * Module Name: AT Bios hard disk driver * * Version: 1.04 * * Author: FOSCO * * Date: 10-20-89 * * Filename: athard.c * * Language MSC 5.1 * : Functional Description:

* Interrupt 13h - hard disk driver * * AH = 0 - do a reset on the controller, set recal needed * * AH = 1 - read the last operation status into AL * :--------------- for the following operations -------------* DL = drive number (Ox80-0x81) * DH = head number * CH = track number * CL = sector number (except for Format) * AL = number of sectors (except for Format) : ES:BX - data buffer address (except for Fo~t)

* * AH = 2 - read sectors * * AH = 3 - write sectors * * AH = 4 - verify sectors * * The above commands return in AL the # of sectors succesfull * * AH = 5 - format track * ES:BX points to (4 sector bytes) * # of sectors * Each field (1 per sector) = * C = Cylinder (track) number * H = head number * R = sector number * N = number of bytes per sector encoded as: * 00 = 128 bytes per sector * 01 = 256 bytes per sector * 02 = 512 bytes per sector : 03 = 1024 bytes per sector

* AH = 6 - not used * * AH = 7 - not used * * AH = 8 - Return the Drive Parameters * : AH = 9 - Initialize the drive pair

* AH = 10 - Read Long * * AH = 11 - Write Long * * AH = 12 - Seek

Page 173: Atbios Kit Nov89

E·9· 2 The Hard Disk Driver

* * AH = 13 - Alternate disk reset * * AH = 14 - not used * * AH = 15 - not used * * AH = 16 - test drive ready * * AH = 17 - Reca librate * * AH = 18 - not used * * AH = 19 - not used * * AH *

= 20 - controller diagnostic

* AH = 21 - read drive type * * * Returns: * Carry Flag Clear = ~ood operation - AH a 0 * Carry Flag Set = Fallure - AH = failure code * * Argunents: * * Return: * * Version History: * 1.01 * DMA overrun check was being called with the cx register instead of the ax register. Changed * calls to pass ax. * 1.02 * Corrected previous error in check overrunc (test for nr sectors = Ox7f). * Corrected error in check error byte functlon * 1.03 - -* Changed init routine to check for any disks present before linking * vector 40h. * 1.04 * Replaced ~ks and pokes with casts * Moved varlables to ~lock * Changed setup to skip vectoring if no hard disks present * Changed most function calls to pass only myblock pointer for argunents * Corrected error in FORMAT case (using wrong block index) * ***************************************************************************************************1

1* INC L U D E F I L E S *1 #include lIatkit.hll

1* FUN C T ION PRO TOT Y PES *1

1*================ function prototypes ===================*1 unsigned hdisk setup(void); void interrupt-cdecl far hdisk io(interrupt registers); void interrupt cdecl far hdisk:isr (void); -

unsigned char calc hsectors(unsigned char,unsigned char,unsigned char); unsigned wait for Tnt(void)i unsigned not 5usyfvoid); unsigned cheek overrun(unsigned,unsigned,unsigned); unsigned wait for data(void); unsigned checi hdrstatus(void); unsigned check-stitus byte(void); unsigned check-error ~te(void); unsigned load comnana(unsigned); unsigned hi_rigs(unsigned long);

1* G lOB A l V A R I A B l E S */

1* G lOB A L CON S TAN T S *1

extern canst unsigned char hdisk_table;

1* L 0 CAL D E FIN I T ION S */

#def i ne OOTPUT REQ BIT OxOS #define ecc_mOae oi02

#define sencCconmand load_con.nd(myblock)

11--------- bios ram usage definitions ---------­

#define bad_bat OxSO

A-Type BiosKit

Page 174: Atbios Kit Nov89

#define bad_chksm Ox40

11--------- error code definitions -----------­#def i ne NO ERROR OxOO #define BAD' CMO Ox01 #define BAD-ADDRESS Ox02 #define BAD-SECTOR Ox04 #define BAD-RESET OxOS #define BAD-PARMS Ox07 #define BAD\)MA Ox09 #define BAD-SECTOR FLAG OxOa #define BAD-CYLIND~R OxOb #define -BAD-FORMAT OxOd #define BAD-CONTROL OxOe #def i ne BAD -DMA ARB OxOf #define BAD-ECC- Ox10 #define BAD-ECC OK Ox11 #define BAD-HDC- Ox20 #define BAD-SEEK Ox40 #def i ne T I M~ ooT Ox80 #define NOT IEADY Oxaa #def i ne UNo~F ERR Oxbb #define BAD WIITE Oxcc #define BAD-STATUS OxeC #define BAo:SENSE Oxff

11--------- function code definitions --------­

#define RESET OxOO #define READ STATUS Ox01 #define READ-SECTORS Ox02 #define WRIT~ SECTORS Ox03 #def i ne VER I FY SECTORS Ox04 #define FORMAT-TRACK OxOS #define BAD FuRcTION Ox06 #define GET-PARAMETERS OxOS #define INIT DRIVE Ox09 #define READ-LONG OxOa #define WRITr LONG OxOb #define SEEK OxOc #define ALT RESET OxOd #define TEST DRIVE READY Ox10 #define RECAtIBRATr Ox11 #define DIAGNOSTIC Ox14 #define GET DISK TYPE Ox1S #define PARr HEAD'S Ox19 #define FORMiT UNIT Ox1a #define BAD_COMMAND Ox1b

#define, TRY Oxff

11----------- I/O port definitions ----------­#define Ho_PORT Ox1fO

II controller task register file (ports) (frame)

II for a port write -

/1 0 - write data 1/ 1 - pre-ceq) 1/ 2 - sector count // 3 - sector number 1/ 4 - low cyl 1/ S - high cyl // 6 - size/drive/head // 7 - command register

// for a port read // 0 - read data // 1 - error register 1/ 2 - sector count II 3 - sector number 1/ 4 - low cyl 1/ S - high cyl // 6 - size/drive/head // 7 - status register

#define Ho_REG_PORT 0x3f6

//----- controller internal command codes -----------­

#def ne HOC RECAL Ox10 #def ne HOC-READ Ox20 #def ne HDC:READ_LONG Ox22

The Hard Disk Driver E·9·3

Section E: The C Proerams

Page 175: Atbios Kit Nov89

E;.9·4 The Hard Disk Driver

#def i ne HDC WR I TE 0x30 #define HDC~ITE LONG Ox32 #define HDC-VERIFT Ox40 #define HDC-FORMAT Ox50 #define HDC-INIT Ox60 #define HDC-SEEK' Ox70 #define HDC-oIAG Ox90 #define HDC:SET_PARM Ox91

/* L 0 CAL CON S TAN T S */

//const char ndisk_table[1] [1] [16]:

/* PRO G RAM */

variables unsigned char hd frame[8]: unsigned hd tabli seg: unsigned hdrtable-off:

/* The comnand block is bui l t in this frame */ /* pointers to drive parameter table */

unsigned hdxfr seg: unsigned hdrxfr-off:

/* pointers to the transfer area */

end_variables haregs:

/*-------------- setup the controller -----------*/

unsigned hdisk setup() ( -unsigned error code = ok: hdregs *mybloci; unsigned char drive type: myblock = acquire_bTock(HARD):

HD NUM = 0: /* clear number of drives */ HD-CONTROL = 0:/* clear control byte */ HD:STATUS1 = 0:/* clear disk status */

if (incmos(Ox8e) & (bad bat I bad chksm) 1= 0) ( --outcmos(Ox8e,incmos(Ox8e) & -Ox10): error_c~ = error:

} else ( /* get disk type for drive 1 from cmos */

drive type = incmos(Ox12) » 4: if (drive type 1= 0) /* there are 1 or more drives */ ( -

VECTOR_40 = VECTOR_13: /* move floppy vector to interrupt 40 */

link_interrupt(Ox13,hdisk_io): /* link 13 for functions and 76 (IRQ14) for isr */

link_interrupt(Ox76,hdisk_isr):

set vector(Ox41,bios cs(),&hdisk table): /* set default table addresses to type 0 */ set:vector(Ox46,bios:cs(),&hdisk:table);

outportb(Oxa1,inportb(Oxa1) & -Ox40): /* enable IRQ 14 */

outportb(Ox21,inportb(Ox21) & -Ox05): /* enable IRQ 2 in slave mode */

if(drive_type == 15) drive_type = incmos(Ox19): /* get extended type */

/* set pointer to table[typel into int 41 vector */ poke(OxOO.Ox41 * 4,&hdisk table+«drive type-1)*16»: HD_NUM = 1: // say there 1S one drive -

drive type = incmos(Ox12) & OxOf: if (drive type 1= 0) /* there are 1 or more drives */ ( -

if(drive_type == 15) drive_type = incmos(Ox1a): /* get extended type */

/* set pointer to table[typel into int 46 vector */ poke(OxOOLOx46 * 4,&hdisk_table+«drive_type-1)*16»: HD NUM = ~: /1 say there are two drlves

} -/* test the hard disk controller */ myblock->dx = Ox0080: myblock->ax = DIAGNOSTIC « 8; sys int(Ox13,myblock): if r(myblock->flags & carry bit) != 0) { -error code = Ox1782: /* return error code */

} -/* do a reset on the drive(s) */

A· Type BiosKit

Page 176: Atbios Kit Nov89

}

} }

myblock->dx = OX0080i myblock->ax = RESET « 8: sys int(Ox13,myblock); if f(myblock->flags & carry bit) != 0) { -error code = Ox1790i /* return·error code */

} -

release block(myblock): return(error_code)i

The Hard Disk Driver E·9·5

/*=================================================*/ /*======== BEGINNING OF MAIN ROUTINES ============*/ /*=================================================*/

/* handle the floppy disk function service call */

void interrupt cdecl far hdisk io (interrupt registers) ( --hdregs *myblocki

if«dx & Ox0080) == 0) /* if dl <= 7f, then divert to floppy disk */ ( // fdisk chain is an assembly language routine which // unstacks the pushed registers, then executes an int 40 // to the floppy driver. This prevents the stack from // becoming too deep. DOS has a problem with its stack // being too short to support many nested, interrupts. fdisk chain(): /1 does not return here !!I

} -enableO: myblock = acquire_block(HARD):

snapshot_in(HARD,&es)i

flags &= -Ox0001: 1* clear the carry flag for returns */

HD_STATUS1 = 0; 1* clear status */

// set prec~ - varies for drive zero or one III if «dx & Oxff) > Ox81) ax = BAD_COMMAND «8: /* bad drive number *1

if(HD_NUM == 0) ax = BAD_COMMAND « 8; /* no hard drives */

if«dx & Ox7f) > (HD_NUM - 1» ax = BAD_COMMAND « 8; /* bad drive number */

if «dx & Ox01) == 0) II drive 0: ( myblock->hd table seg = peek(OxOO,Ox0106); myblock->hdrtable-off = peek(OxOO,Ox0104);

} --else // drive 1: ( myblock->hd table seg = peek(OxOO,Ox011a); myblock->h~table-off = peek(OxOO,Ox0118);

} - - .

// set the control byte . HD CONTROL = (HD CONTROL & OxcO) I peekb(myblock->hd table seg,myblock->hd table off+8); "-set the register port - - --outportb(HD REG PORT,peekb(myblock->hd table seg, myblock->hd table off+8»; " build the frime - - --myblock->hd frame[1] = peek(~lock->hd table seg, myblock->hd table off+5) » 2; myblock->h~frame[2] = ax & OxOOff: - - 1/ sector ccUit -myblock->h~frame[3] = cx & Ox3f; " sector number myblock->h~frame[4] = cx » 8; 1/ cyl low myblock->hdrframe[5] = (cx » 6) & Ox03" // cyl high myblock->h~frame[6] = «dx & Ox01) «,) «dx» 8) & OxOf) I OxaO; myblock->hd[frame[71 = 0; // pre-clear t~is item

/1 normalize es:bx to xfr seg:xfr off = xxxx:OOOx myblock->hd xfr seg = es + (bx »-4); myblock->hd[xfr:off = bx & OxOOOf;

/* now execute the CASE for the selected function */

switch (ax» 8) ( case RESET: /* reset the disk controller */ watch string(HARD,"RESET"); mybloek->ax =_01 II do a reset on the Floppy controller first sys int(Ox40 myglock)i if f(dx & Ox60ff) > Ox81) // not legal drive' {

ax = myblock->ax; // pass results back to caller

Section E: The C Pro&rams

Page 177: Atbios Kit Nov89

E-9-6 The Hard Disk Driver

flags = myblock->flags; } else II do the hard drive too ( /1 enable the IRQ outportb(Oxa1,inportb(Oxa1) & Oxbf); // reset the controller outportb(HD_REG_PORT, 4);

II DELAY 5-10 USECS delay_call(0,10);

II set the head, and clear the reset bit outportb(HD REG PORT,HD CONTROL & OxOf); if(not busyr) == error)-( -

HD STATUS1 = BAD RESET; watch string(HARD',"NOT BUSY BAD RESET");

} -else ( watch string(HARDt"Not busy was 0K"); if(inportb(HD POR +1) 1= Ox01) ( -

HD STATUS1 = BAD RESET; watch string(HARD',"Port 1 not = 01 bad reset");

} -else ( watch string(HARDt"Init and Recal the drives ll

);

myblock->ax = INI DRIVE« 8; myblock->dx = Ox0080; . sys_int(Ox13,myblock);

myblock->ax = RECALIBRATE « 8; myblock->dx = OxOO8O; sys int(Ox13 cmyblock); / I Tf two drlVes, do the next one if (HD NUM > 1) ( -myblock->ax = INIT DRIVE « 8; mYblock->dx = OxOO!1; sys_int(Ox13,myblock);

myblock->ax = RECALIBRATE « 8; myblock->dx = Ox0081· sys int(Ox13,myblock);

} -HD STATUS1 = 0; 1/ clear the error bits watch string(HARD,"Gooci reset");

} -HD STATUS1 = 0; II clear the error bits watch string(HARD,"Gooc:I reset");

} -} break;

case READ STATUS: watch strTng(HARD,"READ STATUS"); ax = fax & OxffOO) I HD-STATUS1; break; -

case READ SECTORS: watch strTng(HARD,"READ SECTORS"); mybLock->hd frame[n = IlDc READ; if(myblock->hd_frame[21 ==-0) < HD_STATUS1 z BAD_CMD; break; }

watch string(HARD,"\n\rChecking OVerrt.rl")· if(Chick_OVerrt.rl(myblOCk->hd_frame[21,myb[OCk->hd_xfr_off,myblOCk->hd_frame[n) == ok)

watch_string(HARD,"\n\rOverrt.rl ok");

if(send command == ok) ( -watch string(HARD,II\n\rSent command"); // ~t commands II do thTs loop for each sector do (

if(wait for int() == ok) II wait-for-data ready interrupt ( watch_string(HARD,"\n\rReady for datall );

1/ do the sector transfer rep in(myblock->hd xfr seg, myblock->hd xfr off,HD PORT,256); mybTock->hd_xfr_ofr +=;12; - - -

A-Type BiosKit

Page 178: Atbios Kit Nov89

The Hard Disk Driver E·9· 7

(

}

} watch string(HARD,"\n\rXFR donell ); if (cneck hd status() == error) break; watch strTng(HARD,"\n\rStatus was OK");

} -while( - -myblock->hd frame [2] 1= 0);

} -

break;

case WRITE SECTORS: watch striiig(HARD,IIWRITE SECTORSII); mybloC'k->hd_frame[n = HD'C_WRITE;

if(myblock->hd_frame[2] == 0) ( HD_STATUS1 = BAD_CHO; break; )

II check for transfer overrun ~f(Check_overrun(myblock->hd_frame[2],myblOCk->hd_Xfr_Off,myblock->hd_frame[n)

watch string(HARD,"\n\rOVerrun okll); if(sefid command == ok) ( -watch_string(HARD,II\n\rSent commandll );

II wait for data request if(wait for data() == ok) ( --watch string(HARDt"\n\rReady for datall ); II dO this loop Tor each sector do ( 1/ do the sector transfer rep out(mvblock->hd xfr seg,myblock->hd xfr off,HD PORT,256); mybTock->hd xfr off-+= ;12; - - -watch string(HAR'D,"\n\rXFR donell );

if(waTt for int() t= ok) break, 1/ wait for completion watch string(HARO,II\n\rCompletlon Interrupt rx'd"); if (cneck hd status() == error) break; watch strTng(HARD,II\n\rStatus was OK");

} -while«(HO STATUS & OXOS) 1= 0) && (--myblock->hd frame[2] t= 0»; if(inportb(HD_PORT+2) t= 0) -

watch_string(HARD,"\n\rXfer Aborted = original error code = II); watch word(HARD,HD STATUS1); HD_STXTUS1 = UNDEF:ERR; }

} )

} break;

case VERIFY SECTORS: watch string(HARD,"VERIFY SECTORS"); mybloC'k->hd frame[n = HOe VERIFY; if(send command == ok) -{ -if (wait for int() == ok) ( --check hd status();

) --} break;

case FORMAT TRACK: watch string(HARD,IIFORMAT TRACK"); mybloek->hd frame[n = HDe FORMAT; myblock->h~frame[2] = peeKb(myblock->hd table seg, myblock->hd_table_off+14); i f(send command == ok) - -( -watch_string(HARD,"\n\rSent conmand");

// wait for data request interrupt if(wait for data() == ok) ( --watch string(HARD,"\n\rReady for .t .. ); // do-this loop for each sector do ( II do the sector transfer rep out(mvblock->hd xfr seg,myblock->hd xfr off,HD PORT,256); mybTock->hd xfr off-+= ;12; - - -watch string(HAR'D,"\n\rXFR done"); if(waTt for int() != ok) break, 1/ wait for completion watch_string(HARD,"\n\rCompletlon Interrupt rx'd");

== ok)

Section E: The C ProlUams

Page 179: Atbios Kit Nov89

}

E·9·8 The Hard Disk Driver

if (check hd status() == error) break; watch strTngl'HARD,II\n\rStatus was OKII);

} -while«(HD STATUS & Ox08) 1= 0) && (--myblock->hd frame[2] 1= 0»; II if the controller is still asking for more dati, then it is an error

}if(inportb(HD_PORT+2) 1= 0) HD_STATUS1 = UNDEF_ERRi

break;

case GET PARAMETERS: wateh_string(HARD,IIGET_PARAMETERSII);

II build ch = max cyls, cl = max sectors II get lower 8 bits of max cyls . ax = peek(myblock->hd_table_seg,myblock->hd_table_off)-1; ex = ax « 8; ex 1= «ax » 2) & OxOOcO);

II ~et max sectors ex 1= (peekb(myblock->hd_table_seg,myblock->hd_table_off+14»;

I I bui ld ell = max heads, dl = tI drives dx = (peekb(myblock->hd table seg,myblock->hd table off+2)-1) « 8; dx 1= HD_NUM; - - --

ax = 0; break;

case INIT DRIVE: watch strTng(HARD,IIINIT DRIVE")i myblock->hd frame[7] = RDc SET ~ARM; I I set max neads --myblock->hd_frame[61 = (myblock->hd frame[6] & OxfO) 1 \ (peekb(myblock->hd table_seg,mybloci->hd_table_off+2)-1); II set sector count myblock->hd_fr~[2] = peekb(myblock->hd_table_seg,myblock->hd_table_off+14); II set low cyllnder = 0 myblock->hd frame[4] • 0; II set high-cylinder = 0 myblock->hd_frame[5] = 0;

if(send command == ok) { -

}

if(not busy() == ok) { -check hd status();

} --break;

case READ LONG: watch strTng(HARD, "READ LONG"?! mybloek->hd_frame[7] = RDC_REAU_LONG;

if(myblock->hd_frame[2] == 0) { HD_STATUS1 = BAD_CMD; break; }

II check for transfer overrun 1/ watch string(HARD lI\n\rCheckfng OVerrun")· if(check-overrun(myb(ock->hd frame[2],myblock->hd xfr off,myblock->hd frame[7]) == ok) {- - - - -1/ watch strfng(HARO,"\n\l"OVerrun okll); 1/ commandlphase if(send command == ok) { -// watch_string(HARD,"\n\rSent command"); 1/ ouput commands // do thTs loop for each sector do {

if(wait for int() == ok) 1/ wait-for-data ready interrupt { watch_string(HARD,"\n\rReady for data"); /1 do the sector transfer rep in(myblock->hd xfr seg,myblock->hd xfr off,HD PORT,256); mybTock->hd_xfr_ofT +=;12; - - -

}

// read the 4 extra bytes pokeb(myblock->hd xfr seg,myblock->hd xfr off++, nportb(HD PORT» pokeb(myblock->hdrxfr-seg,myblock->hdrxfr-off++, nportb(HD~T» pokeb(myblock->hdrxfr-seg,myblock->hdrxfr-off++, nportb(HD:PORT» pokeb(myblock->h~xfr:seg,myblock->h~xfr:off++, nportb(HD_PORT»

A· Type BiosKit

Page 180: Atbios Kit Nov89

The Hard Disk Driver E·9·9

}

/I watch string(HARD,"\n\rXFR done"); if (check hd status() == error) break; /I watcfCstring(HARD,"\n\rStatus was 0K");

} while(--myblock->hd frame[2] > 0);

} -

break;

case WRITE LONG: watch striiig(HARO, "WRITE LONG")i myblock->hd_frame[7] = H~C_WRIT~_LONG;

if(myblock->hd_frame[2] == 0) < HO_STATUS1 = BAD_CMD; break; }

II check for transfer overrun if(check overrun(myblock->hd frame[2],myblock->hd xfr off,myblock->hd frame[7]) == ok) < - - - - -watch string(HARD,"\n\rOVerrun Ok"); if(send command == ok) < -watch_string(HARD,"\n\rSent command");

II wait for data request interrupt if(wait for data() == ok) < --watch string(HARD,"\n\rReady for data"); II do-this loop for each sector do < II do the sector transfer rep out(mvblock->hd xfr seg,myblock->hd xfr off,HD PORT,256); mybTock->hd_xfr_off-+= ;12[__ - - -II ecc mode - sind 4 more oytes outportb(HO PORT,peek(myblock->hd xfr seg,myblock->hd xfr off++» outportb(HO-PORT,peek(myblock->hdrxfr-seg,myblock->hdrxfr-off++» outportb(HO-PORT,peek(myblock->hdrxfr-seg,myblock->hdrxfr-off++» outportb(~O:PORT,peek(myblock->hd[xfr:seg,myblock->hd[xfr:off++» watch strlng(HARD,"\n\rXFR done"); if(waTt for int() 1= ok) breaki II wait for completion watch string(HARD,"\n\rCompletlon Interrupt rx'd"); if (cneck hd status() == error) break; watch strTng"(HARD,"\n\rStatus was OK");

} -while«(HD STATUS & Ox08) 1= 0) && (--myblock->hd frame[2] 1= 0»; II if the controller still asking for more then an error. if(inportb(HD PORT+2) 1= 0) HD STATUS1 = UNDEF ERR;

} - - -}

} break;

case SEEK: watch string(HARO,ISEEK"); myblock->hd frame[7] = HOC SEEK; if(send command == ok) -< -

if(wait for int() == ok) check hd status(); if(HD STATU~1 == BAD SEEK) HD ~TATUs1 = 0;

} - --break;

case ALT RESET: watch string(HARO,"ALT RESET"); break; -

case TEST DRIVE READY: watch strTng(HAIfD,"TEST DRIVE READYIl); if(not busy() == ok) - -< -outportb(HD PORT+6,myblock->hd frame[6]); check hd status(); -

} --break;

case RECALIBRATE: watch string(HARD,"RECALIBRATE"); mybloek->hd frame[7] = HOC RECAL; if(send command == ok) -< -

if(wait for int() == ok) < --check hd status();

} --

Section E: The C ProlUams

Page 181: Atbios Kit Nov89

)

E·9·10 The Hard Disk Driver

else (

if(wait for int() == ok) check ha stitus();

) --if(HO STATUS1 == BAD SEEK) HO STATUS1 = 0; break; --

case DIAGNOSTIC: watch string(HARO,"OIAGNOSTIC"); /* maKe sure interrupts are disabled when changing the interrupt mask */ disableOo outportb(6xa1,lnportb(Oxa1) & - Ox40); outportb(Ox21,inportb(Ox21) & - Ox20); enableO; . if(not bUsy() == ok) /* ok to start diag */ ( -outportb(HO PORT+7,HOC OIAG); if (not busy() == ok) - /* wait for completion */ { -if «HO ERROR = inportb(HO PORT+1» 1= 1) (- -

HO STATUS1 = BAD HOC; ) - -

) else (

HO STATUS1 = TIME_OUT; ) -

) break;

case GET DISK TYPE: watch stFing(IARO,"GET DISK TYPE"); 1/ cyTs = peek(hd tible ieg,hd table off) /1 heads = peekb(ha table seg,ha table off+2) // sectors = peekb(hdCtable:seg,hdCtable:off+14)

cx = hi regs«~k(mvblock->hd table seg,mvblock->hd table off)-1) * peekb(myblock->hd table seg,mY6lock->hd table off+2)-* -peekb(myblock->hdCtable:seg,mVblock->hdCtable:off+14»;

dx = (peek(mvblock->hd table seg,mvblock->hd table off)-1) * peekb(myblock->hd table seg,ffiyblock->hd table off+2) * peekb(myblock->hdCtable:seg,mVblock->hd[table:off+14);

ax = Ox0300; break;

default: /* invalid function code - return bad code */ HO STATUS1 = BAD CMD10 ax-= (BAD CMD «-8) (ax & Oxff>; break; -

) /* end of switch *1

ax = (ax & OxOOff) I (HO STATUS1 « 8); if«ax & OxffOO) != 0) fTags 1= 1;

if (watch( HARD» (

}

/1 display port ins write stringC"\n\rPort ins 1f1 = ");lbyte(inportb(HO PORT+1»; write-stringC" 1f2 = II); lbyteCinportb(HO PORT+2»; -write-stringC" 1f3 = II); lbyte(inportbCHO-PORT+3»; write-stringC" 1f4 = II); lbYte(inportb(HO-PORT+4»; write-stringC" 1f5 = II); lbyte(inportbCHO-PORT+5»; wri te-stringCIt 1f6 = II); lbyteC inportbCHO-PORT+6»; wr!te:str!ngc" 1f7 II II); lbYteCinportbCHO:PORT+7»; wrlte_strlngc"\n\r");

snapshot out(HARD(&eS); release 6lock(myb ock);

) -/*====================================================*/

/* check for the controller not busy */ unsigned not busy(void) ( -/* ~et current count and add 5 secs to it */ unslgned long delay_count = set_timeout_count(5 * 20);

enable();

A-Type BiosKit

Page 182: Atbios Kit Nov89

}

// clear status byte HD_STATUS1 = NO_ERROR;

do { if «inportb(HD PORT+1) & OxSO) == 0) return(ok); } while (TIMER_LONG-< delay_count);

// set time out error HD_STATUS1 = TIME_OUT;

// return error condition to caller return(error)i /* time out */

1*====================================================*/

void interrupt cdecl far hdisk isr (void) ( -

}

HD INT FLAG = -1' outportb(OxaO,Ox~O); outportb(Ox20,Ox20)i 1* send eo; *1

1*====================================================== Wait for the hardware interrupt to occur. Time·out and return if no interrupt • ....••.••.....•••...••...•..•.•....••..•...•••.....•. *I

unsigned wait for int (void) ( - -/* this time out should be 3 secs */ unsigned long delay_count = set_timeout_count(3 * 20);

enable();

do

The Hard Disk Driver E·9·11

( if(HD INT FLAG 1= 0) { HD INT FLAG = 0; HD_STATUS1 = 0; return (ok); } } while «TIM~R LONG < delay count»-HD INT FLAG =-0; HD STATUsT 1= TIME OUT; return(error); - -

}

1*====================================================== Wait for the data request. Time·out and return if no request • ........•..•............•...••..............•.•....•. *I

unsigned wait for data (void) ( - -unsigned long delay_count = set_timeout_count(2 * 20);

enable(); /* this time out should be 2 sees */ do ( if«inportb(HD PORT+1) & OUTPUT REQ BIT) != 0) { return(ok)i } } while (TIMER LON~ < delay count)i- -HD STATUS1 =-TIME OUT; -return (error); -

)

1*========================================================= recalibrate the drive.

·······.···.··· .... ····· .. ·· .... ·.··········.···.···*1

1/··················································

unsigned check hd status() ( - -

if(check status byte() == error) return(error); if«inportb(HD P~T+1) & Ox01) == 0) return(ok); return(check error byte(»;

} --II···················································· II This is a reminder of what is in the tables Ilconst char status mask[S]={Ox80,Ox20,Ox40,Ox10,OxQ4} Ilconst char status:err [S]={OxOO,Oxcc,Oxaa,Ox40,Ox11} Ilconst char status_key [S]={OxOO,OxOO,Ox40,Ox10,OxOO}

unsigned check_status_byte()

Section E: The C Pro&rams

Page 183: Atbios Kit Nov89

(

}

E·9·12 The Hard Disk Driver

unsigned i· unsigned c~ar tempi HO STATUS1 = 0; // start with a clear temp = HO STATUS = inportb(HO PORT+7); if(watch(RARO» -

( write string("\n\rHO STATUS = II); lbyte(temp)i write_string("\n\r")i } if«temp & Ox80)-'= 0) return(oi); if«temp & Ox20) t= 0) ( HO STATUS1 = OXCCi return(error) } if«temp & Ox40) == 0) ( HO-STATUS1 = Oxaa; return(error) } if«temp & Ox10) == 0) ( HO-STATUS1 = Ox40; return(error) } if«temp & Ox04) != 0) ( HO-STATUS1 = Ox11; ) return(ok); -

//-----------------------------------------------------const unsigned char error table[8] = \ ( -BAD SECTOR, /* OxSO - bad block */ BAD-ECC! /* Ox40 - bad data ecc */ UNDE'F EKR /* Ox20 - not used * / BAD SE'CTOR, /* Ox10 - id not found */ UNOE'F ERR, /* Ox08 - not used */ BAD cRo, /* Ox04 - aborted comnand * / BAO-SEEKL /* Ox02 - trk 0 not found on recalibrate */ BAD:ADORI:SS, /* Ox01 - data address mark not found */ );

unsigned check error byte() ( --

)

unsigned i = 0, temp = O· temp = HO ERROR = inportb(HD PORT+1); watch strTng(HARO~"\n\rError-Byte from 1F1 ="); watch_byte(HARO,temp)i whilef(temp & OxfT) t= 0) ( if«temp & OxSO) != 0) (

}

HO STATUS1 = peekb(bios cs(),&error table[i])i watch_string(HARD,"\n\rError Byte returned ="); watch_byte(HARO,HD_STATUS1)i return(error);

temp «= 1; i++; }. w~tch_string(HARO,II\n\rNO error detected"); return (ok)i

//---------------------------------------------------------1/ check for transfer overrun // if ecc mode than use 7f04 as max, else use SOOO

unsigned check overrun(nr sectors,xfr off,ecc char) { - - - ~

)

if (nr_sectors < Ox7f) return(ok); 1/ always ok

if«ecc char & ecc mode) 1= 0) (- -

if «nr sectors == Ox7f) && (xfr off < 4» return(ok); ) - -else ( if(nr sectors == Ox7f) return(ok)· if«nr sectors == OxSO) && (xfr o~f == 0» return(ok);

) - -HO STATUS1 = BAD OMA; return(error)i -

//----------------------------------------------------uns i gned load comnand( hdregs *myparm) ( -unsigned count = 10000;

I I hdregs *myparm; 1/ myparm = arg;

/ I check for time out on drive being ready 1/ watch string(HARO,"Load comnand entry\n\r"); do -( 1/ check for controller and drive ready if (not busy() == ok) ( -1/ watch string(HARO,"not busy DK\n\r"); // select drive -outportb(HO_PORT+6,myparm->hd_frame[6]);

A· Type BiosKit

Page 184: Atbios Kit Nov89

}

} }

if (check status byte() == ok) ( - -

}

1/ watch string(HARD,"status byte was ok\n\r")i // reset the interrupt flag byte HD_INT_FLAG = 0; .

// enable the interrupts disableO· outportb(6xa1,inportb(Oxa1) & Oxbf)i outportb(Ox21,inportb(Ox21) & Oxfb); enableO;

/1 check for retries if«HD CONTROL & OxcO) != 0) ( -

if«(myparm->hd frame[7] & OxfO) >= Ox20) && \ «myparm->hd frame[7] & OxfO) <= Ox40» . myparm- >hd frame [7] 1= Ox01;

} -if (watch (HARD» (

}

I / output the conmands

write string("\n\rPort outs 1f1 = II); lbyter~rm->hd frame[1])· wrlte string(" 112 = II); lbyte(myparm->hd frame [2] ) write-string(" 113 = II); lbyte(myparm->haframe[3]) write-string(1I 1f4 = II); lbyte(myparm->haframe[4]) write-string(" 1f5 = II); lbyte(myparm->haframe[5]) write-string(1I 1f6 = II): lbyte(myparm->haframe[6]) write-string(" 1f7 = II); lbyte(myparm->haframe[7]) write:string(lI\n\r ll ); -

outportb(HD PORT+1,myparm->hd frame[1]); outportb(HD:PORT+2,myparm->haframe[2]); outportb(HD PORT+3,myparm->haframe[3]); outportb(HD-PORT+4,myparm->haframe[4]); outportb(HD-PORT+5,myparm->haframe[5]); outportb(HD:PORT+6,myparm->haframe[6]); outportb(HD_PORT+7,myparm->hd[frame[7]): return(ok);

while(count-- > 0); return(error);

1*====================================================*1 1*====================================================*1 1*====================================================*1

The Hard Disk Driver E-9-13

Section E: The C Pro&rams

Page 185: Atbios Kit Nov89
Page 186: Atbios Kit Nov89

The Boot File E·I0·1

TEN

The Boot File

The Boot.c File is the bootstrap function call routine which is used to load DOS from a floppy disk device. The boot routine attempts to read the boot sector of the specified drive and if successful transfers control to the loaded routine (which in tum loads the remainder of the operating system).

To allow flexibility in the way the system attempts to boot, there is a "boot_list" in the boot program which defines the drives which will be used in the boot process. This list may specify the hard or floppy drives in any order.

If your Boot requirements are non-standard or specific to a dedicated application, you may wish to modify the standard boot routine. All the standard system initialization has been done by the POD when the boot routine is finally called. A specialized boot program may load an operating system or start executing an application directly. If one is not using an operating system to support an application, one must not design and code the application so that it makes reference to non-existent operating system features!

The boot routine should exit if the boot process is not completed. This will allow the POD routine to attempt an alternate path, such as defaulting to SysVue.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988 - All Rights Reserved * : Module Name: AT Bios bootstrap routine

* Version: 1.00 * * Author: FOSCO * * Date: 12-01-88 * * Filename: atbootoc * * Language: MS C 501 * : Functional Description:

: This module does the bootstrap load to get DOS loaded and running.

* We look at the boot list to determine what drives should be used for the boot atten.,ts. * The boot sector is loaded into 0000:7cOO and control is transferred to that address. : If the boot cannot be performed, then we exi t.

* Argunents: * * Return: * : Version History:

***************************************************************************************************/

/* INC L U D E F I L E S */

#include "atkitoh"

/* FUN C T ION PRO TOT Y PES */

unsigned boot setup(void)· void interrupt cdecl far boot(void)i void boot_jump(unsigned,unsigned,unsigned)i

/* G LOB A L V A R I A B L E S */

Page 187: Atbios Kit Nov89

E·I0·2 The Boot File

1* G lOB A l CON S TAN T S */

// this is the list of possible boot deviceSr in the order in which they should be tried. // If all the named drives are tried and fai , then exit 1/ The list is terminated bY a -1

const unsigned boot_list[] ={OxOO,Ox80,Ox01,Ox81,-1,};

IIThis example shows the boot preference order to be: II Drives A:, C:, B:, and 0:

II Programmers Caution: /I Some versions of DOS may not allow booting from B: or D: due to DOS internal programs 1/ defaulting to A: or C:, regardless of the drive number being passed in the Dl register II to the DOS boot sector routine.

II Programmers Note: II This version of boot checks for a particular signature in the last two (2) bytes of the boot II sector. This seems to be an IBM or Microsoft convention on their boot records. Boot records of II operating systems other than IBM or MS may not have this signature. If you wish to modify the II boot module to accept any value for the slgnature, you may delete the slgnature comparison logic /I accordingly.

1* l 0 CAL 0 E FIN I T ION S *1

#define boot retrys 2 #define reset flag Ox72 #define switcn_byte Ox10

/* PRO G RAM *1

unsigned boot setup(void) ( -

}

link interrupt(Ox19,boot); return(ok);

11----------- The boot routine ------------------variables end_variables bootregs;

void interrupt cdecl far boot(interrupt registers) ( -unsigned i,break flag,boot_drive,boot_index; bootregs *myblocK; myblock = acquire block(800T); snapshot_in(BOOT,les);

//write_string("----------- Booting ------------\n\r");

II clear the boot area for (i = Ox7cOO; i < Ox7eOO; pokeb(OxOOOO,i++,O»;

for(boot index = 0; peekcs(&boot list[boot index]) 1= -1; boot_index++) {- --

for (i=O;i < boot retrys; i++) ( -boot_drive = peekcs(&boot_list[boot_index]);

watch string(BOOT ,"\n\rBooting from Drive II II); watch:hYte(BOOT boot drive); watch-string(BOOT!"\n\rAtt8q)t II II); watchJbyte(800T,iJ;

myblock -> ax = OxOOOO; /1 try a reset myblock -> dx = boot drive; SYS int(Ox13,myblockJ; IW 1f no carry returned on reset then try booting *1 if«myblock -> flags & carry bit) == 0) ( -myblock -> ax = Ox0201; 1* try to read boot sector *1 myblock -> bx = Ox7cOO; myblock -> es = OxOOOO; myblock -> dx = boot drive; myblock -> cx = OXOOa1i sys int(Ox13,myblock)· if«myblock -> flags 1 carry bit) == 0) 1* no carry returned on readi*1 ( 1* check for boot sector signature *1

1* See programmers note above *1 if (peek(OxOOOO,Ox7dfe) == Oxaa55) {

A-Type BiosKit

Page 188: Atbios Kit Nov89

}

}

RESET FLAG = 0; /* clear reset flag */ enabli()" release ~lock(myblock); watch string(BOOT,"\n\rJlJ'I1ling to boot sector\n\r"); /* go-and don't return */ boot_jlJ'l1l(OxOOOO,Ox7cOO,boot_drive);

else ( watch string(BOOT,"\n\rSignature was II); watch-word(BOOT,peek(OxOOOO,Ox7dfe»;

} -else (

// check for a timeout on the disk controller if«myblock->ax & Ox8000) 1= 0) i = boot retrys + 1;

watch string(BOOT,"\n\rCarry returneC! on Read"); } -

} }

} else ( watch string(BOOT ,"\n\rCarry returned on Reset");

} -

watch string(BOOT,"\n\rRetrys exhaustedll );

snapsnot out(BOOT(&eS); release 6lock(myb ock);

} -/*=======================================================*/

The Boot File E·I0·3

Section E: The C ProK1"ams

Page 189: Atbios Kit Nov89
Page 190: Atbios Kit Nov89

The Cassette Driver E-ll-l

ELEVEN

The Cassette Driver

Although an AT Type machine does not have a cassette interface, a driver is provided in the event a program makes a cassette function call. The function call returns a cassette error condition to the caller. The A-Type machines use an extended set of functions codes for AT specific functions for joystick input, virtual mode control, multi-tasking hooks, sys-request functions, etc.

/**********************************************************************************~****************

* : Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

* Module Name: AT Bios cassette function * * Version: 1.01 * * Author: FOSCO * * Date: 10-20-89 * * Filename: atcass.c * * Functional Description: * This module returns an error condition in AX in the event a user program calls this function. * * Version History: * 1.01 : Replaced peeks and pokes with casts

***************************************************************************************************/

/* INC L U D E F I L E S */

#include lIatldt.h"

void interrupt cdecl far cassette_io(interrupt_registers);

/* G LOB A L S */

extern unsigned char config table; extern _cassette_io; -

/* L 0 CAL D E FIN T ION S */

#define OPEN DEVICE Ox80 #define CLOS£ DEVICE Ox81 #define PROGRXM TERMINATE Ox82 #define EVENT WXIT Ox83 #define JOYSTTCK SUPPORT Ox84 #define SYS REQ fEY Ox8S #define WAIT Ox!6 #define MOVE BLOCK Ox87 #define GET EXTENDED MEMORY SIZE Ox88 #define SWITcH TO PROTECTED-MODE Ox89 #define DEVICE-BU!Y Ox90 -#define INTERRUPT COMPLETE Ox91 #define RETURN_SY!TEM_CONFIG_PARAMETERS OxCO

#define rtc_wait_flag OxaO

/* PRO G RAM */

//-------------------------------------------------------unsigned cassette setup() ( -

link interrupt(Ox1S,& cassette io); return(ok); } - --//-------------------------------------------------------void interrupt cdecl far cassette io(interrupt registers) { --enable(); setds_system_segment();

Page 191: Atbios Kit Nov89

E·ll·2 The Cassette Driver

snapshot_in(CASSETTE,&es);

swi tch (ax » 8) ( case OPEN DEVICE: watch strTng(CASSETTE,tlOpen Devicetl ); break;

case CLOSE DEVICE: watch_string(CASSETTE,tlClose Device"); break;

case PROGRAM TERMINATE: watch_stri ng1'CASSETTE, "Program Terminate"); break;

case EVENT WAIT: watch striiig(CASSETTE,"Event Waittl); if«RTC WAIT FLAG & Ox01) 1= 0) ( --flags /= carry_bit;

) else ( outportb(Oxa1,inportb(Oxa1) & Oxfe); USER FLAG SEG = es; USER-FLAG-= bx; RTC row = cx; RTC-HIGH = dx; RTCIWAIT FLAG = 1; II enabli PIE in cmos chip outcmos(OxOb,(incmos(OxOb) & Ox7f) / Ox40);

} break;

case JOYSTICK SUPPORT: watch string(~ASSETTE,IIJoystick"); break;

case SYS REQ KEY: watch_string1'CASSETTE,"Sys Req Key"); break;

case WAIT: watch string(CASSETTE,"Wait")-if«RTC WAIT FLAG & Ox01) 1= 6) flags /= carry_bit; else - -( disableO­outportb(6xa1,inportb(Oxa1) & Oxfe); USER FLAG SEG = ds( USER-FLAG-= rtc_walt_flag; RTC RIGH = cx; RTC-LOW = dx; RTC-WAIT FLAG = 1; II enable PIE in cmos chip outcmos(OxOb,(incmos(OxOb) & Ox7f) / Ox40); enable();

do ( ) while«RTC WAIT FLAG & OxSO) == 0); RTC WAIT FLAG = 0; -

} - -break;

case MOVE BLOCK: watch strTng(CASSETTE,"Move Block"); II format = virtual move(word count,global segment,global offset) ax = virtual move(ci,es,si); - - -if (ax 1= O)-flags 1= carry_bit; break;

case GET EXTENDED MEMORY SIZE: watch string(CASSlTTE,"Get Ext Mem Size"); ax = Tncmos(0x31); ax :I ax « 8; ax 1= incmos(0x30); break;

case SWITCH TO PROTECTED MODE: watch stri"g(CXSSETTE,"Switch to Virtual tl ); II format = virtual mOde(index,global segment,global offset); ax = virtual_mode(bi,es,si); - -break;

case DEVICE_BUSY:

A-Type BiosKit

Page 192: Atbios Kit Nov89

}

watch string(CASSETTE,"Device Busyll); flags-&= -Ox0001; break;

case INTERRUPT COMPLETE: watch_string(C~SSETTE,IIInterrupt CCIq)lete"); break;

case RETURN SYSTEM CONFIG PARAMETERS: watch string(CASSETTE,"Opin Devicell ); es = 6ios cs(); bx = &conlig table; flags &= -carry bit; ax &= OxOOff; -break;

default: watch string(CASSETTE6"Defaultl); ax = fax & OxOOff) 1 x8600; flags 1= carry bit; break; -

snapshot out(CASSETTE,&es); ) -

The Cassette Driver E·ll·3

Section E: The C ProlUams

Page 193: Atbios Kit Nov89
Page 194: Atbios Kit Nov89

The Parallel Printer Driver E-12-1

TWELVE The Parallel Printer Driver

The Parallel Printer Driver is an Interrupt (Ox17) function call that is used to communicate with the printer. A parallel printer is one which has a "Centronics" interface and is referred to as LPTl, 2, or 3. The printer driver provides simple commands to initialize the printer or send a character to the printer.

Although a hardware interrupt line (IRQ7) is normally assigned for the parallel printer port, interrupt operation is not supported by the standard Bios driver. The typical printer adapter has logic to support the use of the interrupt, but it is not clear how the interrupt would be used if there is more than one printer port installed. Some print spooling programs may possibly use the interrupt, but we are not aware of it. There may also be logic in some printer adapters to disable the output data latch, thereby allowing a bi-directional data capability. The control logic to use such a feature is not a standard Bios function.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * * Module Name: AT Bios LPT driver * * Version: 1.02 * * Author: FOSCO * * Date: 2-25-89 * : Filename: atlpt.c

* Language: MS C 5.1 * : Functional Description:

: Int Ox17 - parallel printer driver

: Input:

* AH = 0 print the character in AL * on return, ah = 1 if character could not be printed * (t i me out). ' * Other bits set as on normal status call * * AH = 1 initialize the printer port : returns with AH set with printer status

* AH = 2 read the printer status into (ah) * 76543210 * I I I +-- time out * +------ unused * +---------- unused * +-------------- 1 = i/o error * +------------------ 1 = selected * +---------------------- 1 = out of paper * +-------------------------- 1 = acknowledge : +------------------------------ 1 = not busy : OX = printer to be used (0,1,2)

* * Argunents: * * Return: * * Version History: * 1.01 * Chnaged the time out loop and pre-cleared (AH) to insure returning status was clean. * 1.02 : Pre-cleared the port list before scanning to prevent phamtoms LPT's being assumed.

***************************************************************************************************/

Page 195: Atbios Kit Nov89

E·12·2 The Parallel Printer Driver

/* INC L U D E F I L E S */

#include "atkit.h"

/* FUN C T ION PRO TOT Y PES *1

unsigned lpt setup(void); void scan lpt(unsigned); void interrupt cdecl far printer_io(interrupt_registers):

1* G LOB A L V A R I A B L E S *1

extern unsigned lpt list[41: extern unsigned char lpt_timeout_list[41;

/* G LOB ALe 0 N S TAN T S *1

extern -printer_io;

1* L 0 C AL D E FIN I T ION S *1

#define print the character 0 #define init the-Port 1 #define re~the status 2 #define equipment Ox10

1* PRO G RAM *1

unsigned lpt setup() ( -

}

unsigned i; link interr~t(Ox17,&-printer io): for Ti=0;i<3ii++) poki40(&lpt:list[il,0): 1/ pre-clear the list scan lpt(Ox3oc); scan-lpt(0x37S): scan-lpt(Ox27S); for Ti=Oii<3;i++) pokeb40(&lpt_timeout_list[il,Ox14): return(oK):

void scan lpt(unsigned port) ( -l.I'Isigned i: outPQrtb(port,Ox55): if (inportb(port) == Ox55) {

EQUIP FLAG += Ox4000: for (1 = 0: «i < 3) && (peek40(&lpt list[il) 1= 0»; i++)i poke40(&lpt list[i],port); -

.} -}

/1=======================================================================

void interrupt cdecl far printer io(interrupt registers) ( --unsigned port,i,j:

setds system segment(): snapsnot_in([PT,&es);

if (dx <= 2) 1* valid lpt number ? *1 ( port = peek40(&lpt list[dx]); 1* get port number */ switch (ax » S ) t 1* test.for valid commands *1

case print the character: ax = ax & UxOOrf; watch string(LPT,"Print Char"): outportb (port,ax); 1* output character to port *1

II see if the printer is busy

for (j = (peekb40(&lpt timeout list[dxl) & Oxff): > 0: j--{ --for (i= 1000; i > 0; i--) ( if «inportb(port+1) & OxSO) 1= 0) break: 1* if not busy *1

} if «inportb(port+1) & OxSO) 1= 0) break: 1* if not busy *1

} .

if «inportb(port+1) & OxSO) 1= 0) 1* if not busy *1 { outportb (port+2, OxOd): 1* set strobe high *1 outportb (port+2, OxOc); 1* set strobe low *1

A· Type BiosKit

Page 196: Atbios Kit Nov89

}

The Parallel Printer Driver E·12·3

ax = «(inportb(port+1) & Oxf8) A Ox48) «8) I (ax & Oxff); } .

else II port was busy, so device not available { ax = «(ax I Ox0100 ) & Oxf9ff) A Ox48); 1* printer timed-out *1

} break;

case init the~rt: ax = ax &-OxOOff; watch_string(LPT,lIlnit Port");

outportb (port+2, Ox08); 1* set init line low *1 1* delay for reset to take place *1 for (;=0; i <= 4000; i++);

outportb (port+2, OxOc); 1* set init line high *1 goto read_status;

case read the status : ax = ax &-OxOOff; watch_string(LPT,IIRead Status");

read status: ax =-«(inportb(port+1) & Oxf8) A Ox48) «8) I ax;

}

snapshot out(LPT,&es)i } -1*==============================================================================================*1

Section E: The C Pro&rams

Page 197: Atbios Kit Nov89
Page 198: Atbios Kit Nov89

The Comm Driver E-13-1

THIRTEEN

The Comm Driver

The Comm Driver is an Interrupt (Ox14) Function Call that is used to communicate with the serial port adapters.

Note - The most common problem involved with serial devices on the Com ports is the incorrect use of the control signals, CTS, R TS, DTR, and DSR. If you experience problems in communication, try jumpering CTS to RTS, and DSR to DTR. This may help to localize and correct the problem.

The extended function calls available on some PS/2 machines are not included in this standard driver. These are relatively simple to add if you wish to enhance your Com Driver.

Note - The standard serial port Bios driver does not support interrupt driven operation. Most tele-communication software packages will replace the Bios driver with their own driver.

/*************************************************************************************************** * : Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

: Module Name: AT Bios com port driver

* Version: 1.02 * * Author: FOSCO * * Date: 2-25-89 * * Filename: atcomm.c * * Language: MS C 5.1 * * Functional Description: : Interrupt Ox14 -- Serial Port Driver

* Provides a function call for initializing, sending data, receiving data, and reading the status : of an asynchronous adapter.

: Upon Entry:

: OX = Logical Async device' (0,1,2,3) for COM1,2,3,4

* Initialize the port: * AH = OOh : AL = initialization parameters:

* Bit Meaning * ----- -----------* Bits 7,6,5 * 000 110 Baud * 001 150 * 010 300 * 011 600 * 100 1200 * 101 2400 * 1 1 0 4800 * 1 1 1 9600 * * Bits 4,3 * o 0 No parity * o 1 Odd parity * 1 0 No parity * 1 1 Even parlty * * Bit 2

Page 199: Atbios Kit Nov89

E·13·2 The Comm Driver

* * * * Bits * * * * * * Send * AH * AL *

0 One stop bit 1 Two stop bi ts

1,0 o 0 5 bits/char o 1 6 bits/char 1 0 7 bits/char 1 1 8 bits/char

a character: = 01h = the character to send

* Receive a character: * AH = 02h * * Read the port status: * AH = 03h * : Upon Exit:

* For * AH * Bit * ---* 7 * 6 * 5 * 4 * 3 * 2 * 1 * 0 * * AL * Bit * ---* 7 * 6 * 5 * 4 * 3 * 2 * 1 * 0 *

'Initialize the port' (AH=O): = Line status Meaning if = 1

Time out Tx ElJ1)ty (TEMT) Tx Holdlng Register ElJ1)ty (THRE) Break Interrupt (BI) . Framing Error (FE) Parity Error (PE) OVerr"" Error (OE) Data Ready (DR)

= Modem status Meaning if = 1

Data Carrier Detect (DCD) Ring Indicator (RI) Data Set Ready (DSR) Clear To Send (CTS) Delta Data Carrier Detect (DDCO) Trailing Edge Ring Indicator (TERI) Delta Data Set Ready (DOSR) Delta Clear To Send (OCTS)

* For 'Send a character (AH = 1): * AL = unchanged (character that was sent) * AH = Completion code * 1XXX XXXX - Time out, char not sent * OYYY YYYY - Tx Successful, Bits 6 - 0 = Line status * * For 'Receive a character (AH = 2): * AL = The received char, if successful * AH = Completion code * 1XXX XXXX - Time out, no char received * OOOY YYYO - Data received, but error detected * See Line status Bit Definitions * * For 'Get port status' (AH=3): * AH = Line status (see above) * AL = Modem status (see above) * * Global Variables: * : Asyne_adapter-PQrt_list (word * 4):

* Word 0 = adapter address of COM1 * Word 1 = adapter address of COM2 * Word 2 = adapter address of C0M3 : Word 3 = adapter address of C0M4

* These four words contain the hardware port addresses of the asyne adapters. Four asyne : adapters can be supported al though the operating system may only recognize COM 1,2.

: Async_time_out_ccx.nt (byte * 4):

* Byte 0 = time out count value for COM1 * Byte 1 = time out ccx.nt value for COM2 * Byte 2 = time out count value for COM3 : Byte 3 = time out count value for C0M4

: The time outs for no response use the contents of these cells for a COU1t.

* Registers Modified: * AX is modified

A· Type BiosKit

Page 200: Atbios Kit Nov89

The Comm Driver E·13·3

* * Argunents: * * Return: * * Version History: * 1.01 * Get divisor corrected by using a peek to reference the baud rate table * - 1.02 : Pre-cleared comm list before scanning to insure no phantoms present.

***************************************************************************************************1

1* INC L U D E F I L E S *1

#include "atkit.h"

1* FUN C T ION PRO TOT Y PES *1

unsigned comm setup(void); void scan comm(unsigned); void interrupt cdecl far comm_io(interrupt_registers);

1* G LOB A L V A R I A B L E S *1

extern unsigned comm list [41; extern unsigned char-comm_timeout_list [41;

1* G LOB A L CON S TAN T S *1

const unsigned baud table[81=<1047,768,384,192,96,48,24,12}; extern _comm_io; -

1* L 0 CAL D E FIN I T ION S *1

1* 8250/16450 register offsets from base address *1

#def i ne tx data reg OxOO #define rx-data-reg OxOO #define div lsb-reg OxOO #define div-msb-reg Ox01 #define int-enb-reg Ox01 #define int-id reg Ox02 #define line ctrl reg Ox03 #define modeiii ctrT reg Ox04 #define line itat reg Ox05 #define modeiii_staf_reg Ox06

1* 8250/16450 register bit definitions *1

#def i ne txrdy Ox60 #define rxrdy Ox01 #define dsr bit Ox20 #define dtr~it Ox01 #define cts~it Ox10 #define rts:bit Ox02

1* opcode definitions *1

#define initialize OxOO #define send character Ox01 #define rx cnaracter Ox02 #define reid_status Ox03

#define equipment Ox10 #define tlmeout_bit Ox8000

1* PRO G RAM *1

II SCAN Com Ports -II This routine is called to detenmine how many serial ports are in the system

unsigned comm setup(void) { -unsigned i; link interrupt(Ox14,& comm io); for Ti=0;i<4ii++) poki40(&comm_list[i1,0); II insure list is clear before scanning scan comm(0~f8); scan:comm(Ox2f8);

}

scan comm(Ox3e8); scan-comm(Ox2e8); for Ti=0;i<4ii++) pokeb40(&comm_timeout_list[i1,Ox01); return(oK);

void scan_comm(unsigned port)

Section E: The C ProlUams

Page 201: Atbios Kit Nov89

(

}

E·13·4 The Comm Driver

unsigned i; outportb(port+3,Ox55); if (inportb(port+3) == Ox55) {

EQUIP FLAG += Ox0200· for (1 = O;«i < 4) 1& (peek40(&comm list[i]) 1= O»;i++); poke40(&comm list[i],port); -

} -

void interrupt cdecl far comm_io(interrupt_registers) ( unsigned port address,divisor; unsigned time-out; unsigned long-timeout counter; setds_sys t em_segment (1;

snapshot_in(COM,&es);

if (dx > 3) '* check for OX out of range */ ( watch string(COM,"Bad Port");

} -else ( /* get the time out parameter *' time_out = peekb40(&comm_timeout_list[dx]);

/* scale to use as a major loop counter */ time_out *= 10; '* figure 1 count = 500 millisec = 10 clock ticks

/* get the port address for the (OX) specified device *' port_address = peek40(&comm_list[dxl);

'* if no serial port for this logical device •••• *' if (port address == 0) { -/* return with a time-out error */ ax 1= timeout bit;

} -else { switch (ax » 8) ( case initialize: /* INITIALIZE THE PORT *' ax &= OxOOff; watch string(COM,"lnit Port"); /* set divisor latch enable */ outportb(port address+line ctrl reg,Ox80)i /* ~et the divisor */ - -divlsor = peekcs(&baud table[(ax » 5) &·OxOOO7]); /* load the baud rate aivisor into the 8250 */ outportb(port address+div lsb reg,divisor); outportb(port-address+div-msb-reg,(divisor » 8»; /* set length;parity,st~~iti */ outportb(port address+line ctrl reg,(ax & Ox1f»; /* set OTR ana RTS lines *7 -outportb(port address+modem ctrl reg,(OxOS 1 dtr bit rts_bit»; ax = inportb(port address+l1ne stat reg); -ax = (ax « 8) 1 1nportb(port_iddreis+moaem_stat_reg)i break;

case send character: /* SEND A CHARACTER */ watch_strTng(COM,"Send Char");

/* start with clean return status */ ax &= OxOOff;

/* set dtr and rts */ outportb(port address+modem ctrl reg, inportb(port address+modem ctrl reg) dtr_bit 1 rts_bit)i /* check dsr ind cts */ - - - --

timeout_counter = set_timeout_count(time_out);

("ile«(inportb(port_address+modem_stat_reg) & (dsr_bit 1 cts_bit» 1= (dsr_bit cts_bit»)

if (TIMER LONG >= timeout counter) {ax 1= timeout bit; break;} } - - -if «ax & OxffOO) == 0) /* OK - no timeout */ ( timeout_counter = set_timeout_count(time_out)i

while«inportb(port address+line stat reg) & txrdy) 1= txrdy) { - --

A· Type BiosKit

Page 202: Atbios Kit Nov89

The Comm Driver E·13·5

if (TIMER_LONG >= timeout_counter) {ax 1= timeout_bit; break;} } if «ax & OxffOO) == 0) /* OK - no timeout */ ( /* send the character */ outportb(port address+tx data reg, ax); /* return the-status in XH */-ax = (ax & OxOOff) 1 (inportb(port address+line stat reg) « 8);

} - --} break;

case rx character: /* RECEIVE A CHARACTER */ watch_striiig(COM,"Rx Char"):

/* start with clean return status */ ax &= OxOOff;

/* set OTR out */ outportb(port_address+modem_ctrl_reg, inportb(port_address+modem_ctrl_reg) I dtr_bit)i

/* check OSR */ timeout counter = set timeout count(time out)· ~ile«finportb(port_iddreSS+modem_stat_reg) 1 dsr_bit) 1= dsr_bit»

} }

}

if (TIMER LONG >= timeout counter) {ax 1= timeout bit,· break;} } - - -if «ax & OxffOO) == 0) /* OK - no timeout */ (

/* check for data ready */ timeout counter = set timeout count(time out): while«finportb(port address+Tine stat reg) & rxrdy) 1= rxrdy» { - --if (TIMER LONG >= timeout counter) {ax 1= timeout bit: break:}

} - - -if «ax & OxffOO) == 0) /* OK - no timeout */ (

} ax = «inportb(port_address+line_stat_reg) & Ox1e) « 8) 1 inportb(port_address+rx_data_reg);

} break;

case read status: 1* READ THE STATUS */ watch_strTng(COM,"Read Status"):

ax = inportb(port address+line stat reg): ax = (ax « 8) 1 Tnportb(port_address+modem_stat_reg)i break;

default: watch string(COM,"Bad Comnandll)i ax I=-timeout_bit:

snapshot out(COM,&es); } -/*======================================================*/

Section E: The C Pro&rams

Page 203: Atbios Kit Nov89
Page 204: Atbios Kit Nov89

The Timer Interrupt E·14·1

FOURTEEN

The Timer Interrupt

The Timer Interrupt is called by the hardware real-time clock every 53 milliseconds to increment the time count. This count is used by DOS to calculate the time of day.

Note - A user supplied routine may be linked to the timer interrupt routine, using interrupt IC. This user routine should be of minimal execution time, since other interrupts are disabled while it is running. If it retains control too long, other interrupts may be missed.

/*************************************************************************************************** * : Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

* Module Name: AT Bios real time clock service routine * * Version: 1.01 * * Author: FOSCO * * Date: 10-20-89 * * Filename: attmr.c * * Language: MS C 5.1 * : Functional Description:

* Interrupt Ox08 : This routine services the real time clock interrupt.

* Arguments: * * Return: * * Version History: * 1.01 : Replaced peeks and pokes with casts

***************************************************************************************************/

/* INC L U D E F I L E S */

#include "atkit.h"

/* FUN C T ION PRO TOT Y PES */

void interrupt cdecl far timer_int(interrupt_registers);

/* G LOB A L S */

extern _timer_inti

/* CON S TAN T S */

/* D E FIN E S */

/* PRO G RAM */

unsigned timer setup() { -

link interrupt(Ox08,& timer int); return(ok); } - --//=============================================== void interrupt cdecl far timer int(interrupt registers) { --/* increment timer COU'lt check for 24 hour value */

if(++TIMER_LONG >= TIMER_LONG_MAX) { TIMER_LONG = 0; TIMER_OFL = 1; }

if(--MOTOR_COUNT == 0)

Page 205: Atbios Kit Nov89

(

}

E·14· 2 The Timer Interrupt

MOTOR STATUS &= OxfO; /* turn off motor running bits */ outportb(0x3f2,OxOc); /* turn off any FD motors */

timer chain(); eoi siquence()i

} -

A-Type BiosKit

Page 206: Atbios Kit Nov89

The Time of Day Function E-15-1

FIFTEEN

The Time of Day Function

The Time of Day Function is used to read and set the timer counter, which IS incremented by the timer interrupt.

1*************************************************************************************************** * * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * * Module Name: AT Bios time of day function * * Version: 1.03 * * Author: FOSCO * * Date: 10-20-89 * * Filename: attod.c * * Language: MS C 5.1 * : Functional Description:

* Interrupt Ox1A - Time of Day function call -* readlset the clock * * * I n.terrupt 1AH - Time of Day funct i on ca II * readlset the internal clock or the 6818 clock chip * * AH = 0 • read the clock. * returns: * CX = high word of count * OX = low word of count * AL = 0 if no 24 hour rollover since last read * * AH = 1 • set the clock * CX = high word of count * OX = low word of count * * AH = 2 • read the time from the 6818 clock * returns: * CH = BCD hours * CL = BCD minutes * DH = BCD seconds * CY flag if 6818 not running * * AH = 3 • set the time to the 6818 clock * CH = BCD hours * CL = BCD mi nutes * DH = BCD seconds * DL = 0/1 = normal/daylight time * * AH = 4 • read the date from the 6818 clock * returns: * CH = BCD century * CL = BCD year * DH = BCD month * DL = BCD day * CY flag if 6818 not ruming * * AH = 5 • set the date to the 6818 clock * CH = BCD century * CL = BCD year * DH = BCD month : DL = BCD day

* AH = 6 • set the 6818 alarm * CH = BCD hours f rom set time * CL = BCD minutes from set time * DH = BCD seconds from set time * returns: * CY flag if alarm already set * NOTE: function 6 is hooked through Int. 4ah, user replaceable. * * * AH = 7 • reset the 6818 alarm off

Page 207: Atbios Kit Nov89

E·15·2 The Time of Day Function

* * Version History * 1.01 * Added enable(): coming into ISR. Fixed Proconm Exiting hangup problem * 1.02 * Changed outcmos(32 ••• to outcmos(0x32 ••• for setting century byte * 1.03 : Replaced peeks and pokes w.ith casts

***************************************************************************************************/

/* INC l U 0 E F I L E S */

#include "atkit.h"

/* FUN C T ION PRO TOT Y PES */

unsigned time of day setup(): void interrupt caecl-far time of day(interrupt registers): unsigned ~te in-progress(voidl: -unsigned initiaTize_status(void):

/* G LOB A L S */

extern _time_of_day:

/* L 0 CAL 0 E FIN I T ION S */

#define READ CURRENT CLOCK OxOO #define SET ~RRENT ~LOCK Ox01 #define REAa RTC OxU2 #define SET JTC Ox03 #define REAa OATE Ox04 #define SET ~ATE OxOS #define SET-ALARM Ox06 #define RESrT_ALARM Ox07

/* PRO G RAM */

uns i gned time of day setup() ( - - -

}

link_interrupt(Ox1a,&_time_of_day): return(ok):

void interrupt cdecl far time_of_day(interrupt_registers) ( enable(): setds system segment(): snapsnot in(TOO,&es): switch(ai » 8) ( case READ CURRENT CLOCK: watch strTngCTOIl.c.1fRead Current Clock"): ax = fax & oxffuu) 1 TIMER OFL: dx = TIMER_LOW: -ex = TIMER HIGH: TIMER OFL = 0: break;

case SET CURRENT CLOCK: watch stringCTOO;"Set Current Clockll ):

TIMER:LOW = dx: TIMER HIGH :II ex: TIMER:OFL = 0: break:

case READ RTC: watch strTng(TOO/'Read Time"): flags-&:II -carry Dit: if (update in nrogress() == error) { - ...,.. flags 1= carry bit:

} -else ( dx = incmos(O): dx = dx « 8· ex = incmos(~); cx = (ex « 8) 1 incmos(2):

} break:

case SET RTC: watch stri",(TOO,"Set Timell ):

if (update_,n-progress() == error)

A· Type BiosKit

Page 208: Atbios Kit Nov89

The Time of Day Function E·15·3

( initialize status();

} -outcmos(OxOO,dx » 8); outcmos(Ox02,cx); outcmos(Ox04,cx » 8)" outcmos(OxOb,(incmos(6xOb) & Ox30) 1 (dx & Ox0001) 1 2); break;

case READ DATE: watch strTng(TOO,"Read Date"); flags-&= -carry bit; if (update in nrogress() == error) { _ .or

flags 1= carry bit; } -else { cx = incmos(Ox32)i cx = (cx « 8) 1 1ncmos(9); dx = incmos(8); dx = (dx « 8) 1 incmos(7);

} break;

case SET DATE: watch stri"Q(TOO,"Set Date"); if (update 1n nrogress() == error) ( _ .or

initialize status(); } -outcmos(6,0) " out cmos (7 ,dx); outcmos(8,dx » 8); outcmos(9,cx); outcmos(0x32,cx » 8)" outcmos(OxOb,(incmos(6xOb) & Ox7f»; break;

case SET ALARM:

}

watch string(TOO,"Set Alarmll); flags-&= -carry Dit" if«incmos(OxObJ & 6x20) 1= 0) { ax = 0" flags 1= carry bit;

} -else (

}

if(update in nrogress() == error) ( _ .or

initialize status(); } -outcmos(1,dx » 8); outcmos(3,cx); outcmos(S cx » 8); outportb(6xa1,inportb(Oxa1) I OXfe)l" outcmos(OxOb,(incmos(OxOb) & Ox7f) Ox20);

break;

case RESET ALARM: watchstriiig(TOO,"Reset Alarm");" outcmOs(OxOb,incmos(OxOb) & OxSr); break;

default: watch_string(TOOc"Bad Conmand"); flags 1= carry_b1t; break;

snapshot out(TOO,&es); } -

//--------------------------------------------------unsigned update in nrogress(void) ( _ .or

unsiined j; for(J = 0; j < 600; j++) ( if «incmos(OxOa) & Ox80) == 0) return(ok);

} return(error);

Section E: The C Pro&rams

Page 209: Atbios Kit Nov89

E·15·4 The Time of Day Function

)

unsigned initialize status(void) ( -.

)

outcmos(OxOa,26); outcmos(OxOb,82); incmos(OxOC)i i ncmos (OxOel) ;

A-Type BiosKit

Page 210: Atbios Kit Nov89

The Print Screen Function E-16-1

SIXTEEN

The Print Screen Function

The Print Screen Function is used to print the screen contents to LPTl.

Some additions and enhancements could be: * Creating an "active_printer" flag (in system ram) which could be used to direct screen prints to LPT2 or LPT3. * Providing a screen print function to output on a serial channel. . * Using this module as a guideline for creating a print-screen to disk-file applications program.

There are various public-domain print-screen functions which support video adapters other than MDA and CGA. An EGA print-screen routine for instance, has been circulated on various Bulletin Board Systems. The logic of one of these could be adapted to replace the standard print screen function, if desired.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * : Module Name: AT Bios print screen function

* Version: 1.01 * * Author: FOSCO * * Date: 10-20-89 * : Filename: atprsc.c

* Language: MSC 5.1 * : Functional Description:

* Interrupt OxOS . : This module copies the contents of the screen buffer to the printer.

* Argunents: * None * * Return: * None * * Version History: * 1.01 : replaced peeks and pokes with casts

***************************************************************************************************/

/* INC L U D E F I L E S */

#include "atkit.h"

/* FUN C T ION PRO TOT Y PES */

void interrupt cdecl far print screen(interrupt registers); void print_screen_service(struet prscregs *); -

/* G LOB A L S *./

extern -print_screen;

/* PRO G RAM */

void print screen setup() { --

link_interrupt(Ox05,&-print_screen)i }

variables

Page 211: Atbios Kit Nov89

E·16· 2 The Print Screen Function

unsigned columns~r line,old cursor, current c~rsor; unsigned char row, coT, current-char; -end_variables prscregs; -

void interrupt cdecl far print_screen(interrupt_registers) ( prscregs *myblock; unsigned prlnt error = false! myblock = acquTre block(PRSC); if (PRSC BUSY 1= T) 1* check status byte *1 ( -

}

PRSC BUSY = 1; 1* set status = busy *1 myblock->ax = OxOfOOi SYS int(Ox10,myblock); I W get current screen mode *1 myblock->columns~r_line = myblock->ax » 8;

myblock->ax = OxOOOd; myblock->dx = O· sys int(Ox17,~lock); mybTock->ax =""OxOOOa; myblock->dx = O· sys_int(Ox17,mYblock);

myblock->ax = Ox0300; SYS int(Ox10,myblock); I W read and save old cursor position *1 myblock->old cursor = myblock->dx; myblock->row-= myblock->col = 0;

for (myblock->row = 0; (myblock->row < 25) & Iprint error;

myblock->row++) -( for (myblock->col = 0;

(myblock->col < ~lock->columns-P8r line) & Iprint_error;

{ myblock->col++) -

II set cursor position myblock->ax = Ox0200; myblock->dx = (mvblock->row «8) myblock->col; sys_int(Ox10,myblock);

II read character at cursor myblock->ax = Ox0800; myblock->bx = o· sys_int(Ox10,mYblock);

II print character myblock->current char = myblock->ax; if (myblock->current_char==O) myblock->current_char = Ox20; myblock->dx = 0; myblock->ax = myblock->current char & OxOOff; sys int(Ox17,myblock)' -ifamyblock->ax & OxO~OO) 1= 0) print error = true;

} -II do the cr-lf at end of columns myblock->ax = OxOOOd; myblock->dx = o· sys int(Ox17,~lOCk); mybTock->ax =""OxOOOa; myblock->dx = o· sys int(Ox17,mYblock); if(rmyblock->ax & Ox0100) 1= 0) print_error = true;

} myblock->ax = Ox0200; II reset cursor to original position myblock->dx = myblOCK->old cursor; sys int(Ox10 myblock); -PRSC BUSY = 6; 1* clear status = not busy *1

} -

A-Type BiosKit

Page 212: Atbios Kit Nov89

The Vue File E·17·1

SEVENTEEN

The Vue File

The Vue.c file is the source code for Sys Vue, the resident monitor/debugger program. SysVue allows the user to gain access to the system features from any program. If the bootstrap operation is unsuccessful, program control is automatically transferred to Sys Vue.

SysVue has some Watch features built-in to assist in development/debugging. The "select" command is used to set and clear specific bits in the watch_selection variable. These bits are checked when "watch" is "on" and display commands imbedded in the various function routines ~re enabled. These display commands are:

"watch_string( device, "string"); "watch_ word( device, word_value); "watch_ byte ( device,byte_ value);

These watch commands check to see if the corresponding "device" bit is set in the watch_flag variable. H so, the command is executed. When developing and debugging code, this feature is extremely handy. For a final version, one may wish to delete the "watch_xxxxO" calls to save space and increase speed.

The SysVue "SI" command is used to display pertinent data about the Bios and the system. It is especially handy for tech support communications, allowing the user to use the "SI" command to display and convey commonly requested information to the technically oriented person. Since it also shows configuration information, it permits a quick peek at the current system configuration.

The system Setup is accomplished by the use of the: "Time" and "Date" commands to s.et the clock\calendar "Drive" to set the number and type of floppy and hard drives "Video" to set the type of video adapter "Mem" to set the size of system and extended memory "Npx" to declare the presence of the numeric processor "Types" to display the hard disk types in the resident type table "Cmos" to display the checksum value of the CMOS RAM

The redirection command "> ","> con"," > lpt" are used to copy the screen output to a printing device. This allows generating audit trails when involved in debugging, and with "watch" enabled, can provide a wealth of data concerning internal Bios operation. Since one can re-compile the Bios with additional "watch_xxxO" commands, debugging aids can easily be placed where desired.

The "Trace" and "e" (for execute) commands allow a detailed single-step trail to be generated when required. Once a problem area is located with "watch" features, this single stepping can provide lowest level tracing of system action. Single stepping does NOT sense when the stack-segment or stack-pointers are changed, so unpredictable results may occur when these registers are changed.

Page 213: Atbios Kit Nov89

E·17·2 The Vue File

The "Int" command allows the execution of an interrupt, using the register values set with the "Rxx" commands. This permits specialized execution of bios functions from within sysvue. With the watch function enabled, this is a handy debugging aid.

SysVue may also be expanded with new commands as desired.

An easy way for you to generate documentation of your version of Sys Vue is to use the" > LPT" command to provide hard copy of the various screens and menus. These printouts may then be integrated into the user documentation you create.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988 - All Rights Reserved * * Module Name: AT Bios SysVue * * Version: 1.00 * * Author: FOSCO * * Date: 12-01-88 * * Filename: atvue.c * * Functional Description: * * This is the SysVue module which is a Bios-resident debug/monitor program. * * NOTE: : Entry to SysVue is by CTRL-ALT-BREAK.

* Argunents: * * Return: * * Version History: * ***************************************************************************************************/

/* INC L U D E F I L E S */

#include lIatkit .h"

/* FUN C T ION PRO TOT Y PES */

unsigned sysvue setup(); void interrupt cdecl far sysvue(void); void interr~t cdecl far sysbreak(voia); char ci (void); void co(char); unsigned ishex(char); unsigned islower(char)i unsigned isalDha(char)i unsigned isdelim(char); void lword(unsigned)i void pword(unsigned); void lbyte(char)i void pbyte(char), char get byte(vold); unsignedrget word(void), void poked(liisigned,unslgned long int); void set system segment (void); void syntax error(void)i void write itring(unsigned); unsigned get token(void); unsigned get-token number(unsigned *)i void find next list item(void); void get Tine T~trchar)S· /* erg is line. terminator char */ unsig~get token velue( ; unsigned loni get Timits(); void set vector(cnar,unsigned,unsigned)i unsignedilong get vector(char); unsigned console Dreak(void)i void far call(uniigned,unsigned); unsignedivalue-present(char); void display regs(unsi9ned)i void display:flags(unslgned)i

/* G lOB A L V A R I A B L E S */

A· Type BiosKit

Page 214: Atbios Kit Nov89

1*------ external data (variables) declarations ~--------*I

extern reset: extern unsigned comm list[]: extern l.I1signed lpt_Tist[]:

/* variables are in system scratch segment of RAM *1

extern char sysvue busy; 1* 0/1 = not busy/busy *1 extern unsigned long break chain: extern l.I1signed long trace-chain: extern unsigned long tra~ Chain: extern char ~_type,modi_size,sum,char_count: extern char eXlt flag· extern char buffer[SOi: extern unsigned buffer index,token index: extern list index, token number; -extern unsigned comma~index· extern unsigned token value[Si: extern unsigned cc; -extern char present: extern unsigned last ~ start seg: extern unsigned last-dumP-start-off: extern l.I1signed enter seg;enter-off: extern char inchar; - -extern unsigned int seg,int off: extern unsigned reg-index: -extern unsigned reg-saves[15]· extern unsigned inreg saves[1~]i· extern unsigned outreg saves[15 ; extern unsigned trace count: extern char break flag: extern char token~ffer[]: extern char last aelim: extern char record type" extern l.I1signed watch flag: extern unsigned watch-selection: extern unsigned u found: extern unsigned jj; extern unsigned redirect flag: extern char dec_array[61;

1* G LOB ALe 0 N S TAN T S *1

1*------ external data (constants) declarations ---------*1 1* constants are in Bios ROM *1

extern bios id: extern ver Td; extern bioi name: extern owner_id: extern date_stamp:

1* L 0 CAL 0 E FIN I T ION S *1

#define byte 1 #def i ne word 2 #define dword 4

#define ascii 1 #def i ne hex 2

#def i ne data record 0 #define end of file record 1 #define extended adaress record 2 #define start_adaress_reeord 3

1* this are the delimiters for biosvue command strings *1

#def i ne space 32 #def i ne comma 44 #define colon 5S #def i ne semi co l on 59 #define leftparen 40 #define rightparen 41 #def i ne per i od 46 #def i ne ~s 63 #def i ne tab 9 #define quote 34 #define slash 47

1*------------ enumeration lists ------------*1

1* This list MUST be in the same order as the command token list. ** The enumerated values for the commands are assigned by this list. ** These values are used by the case operator in the main body of SysVue.

The Vue File E·17·3

Section E: The C ProlUams

Page 215: Atbios Kit Nov89

E·17·4 The Vue File

** For each entry in this list, there rust be a corresponding entry in the Comnand Token List. ** The token list is searched and the number of the find is used as the comnand switch value. */

enllll cOllEnd { cOIIEnd NUL, /* Nul value = no find */ cOllEnc:f'C /* c~re * / COIIEnc:f'CA, /* c~re ascii */ COIIEndrCB, /* c~re byte */ cOIIEndrCW, /* c~re word */ COIIEnc:f'CD, /* compare double */ cOIIEndrCHK, /* checksllll */ commandrCLS /* clear screen */ cOIIEndrCOL6 BOOT, /* cold boot */ cOIIEndrCMOS-; /* display cmos contents and checksl.tll */ cOIIEndrDATE, /* set date */ cOIIEndrD /* ~ */ COIIEndrDA, /* dump ascii */ commanc:f'DB, /* ~ byte */ cOIIEndrDW, /* ~ word * / cOIIEndrDD /* dumP double word */ COIIEndrDRfVE, /* set number and type of drives */ COllEnc:f'E, /* enter or execute */ cOIIEndrEA, /* enter ascii */ cOIIEndrEB, /* enter byte * / commandrEW, /* enter word */ commandrED /* enter double */ commandrExh, /* exit from SysVue */ commandrF /* fill */ . cOllEndrFA, /* fill ascii */ commanc:f'FB, /* fill byte */ cOllEndrFW, /* fill word * / commandrFD, /* fill double */ commandrH, /* hex add and subtract */ commandrHARD BOOT, /* hard boot */ commandrHELP; cOllEndrl /* i ~t port * / cOllEndrl6, /* input byte */ commanc:f'IW /* i~t word */ cOllEndrlNt, /* interrupt */ cOllEndiM /* move */ cOIIEndiMEM, /* set/display mem sizes */ cOIIEnc:f'NPX, /* select NPX present or not */ cOIIEndr~L /* output port * / cOIIEndrUII, /* output byte */ cOIIEndrOW, /* output word * / COIIEnc:f'QUIT, /* exit from SysVue */ cOllEndr~, .. /* display registers */ comnanc:f'KAA, /* register ax */ cOIIEndrRBX, /* register bx */ commandrRCX, /* register cx */ cOllEndrRDX, /* register dx */ cOIIEndrRSP, /* register sp */ cOllEndrRBP, /* register bP */ COIIEnc:f'RSI, /* register si */ cOIIEndrRDI, /* register di */ cOIIEncf"RDS, /* register ds */ cOIIEndrRES, /* register es */ cOIIEnc:f'RSS, /* register ss */ cOIIEndrRCS, /* register cs */ commandrRIP, /* revister ip */ cOIIEndrRF, /* reglster flags */ cOllEnc:f'RHEX, /* read Intel hex */ cOllEndrSI, /* display info */ cOIIEndrSELECT, /* select watch parameters */ cOIIEndrS, /* search */ cOllEnc:f'SA, /* search ascii */ cOIIEnc:f'SB, /* search byte */ cOllEnciSW, /* search word */ cOIIEndrSO, /* search double */ cOIIEnc:f'TIME, /* set time */ cOllEndrT /* single step */ commandrTRACE, /* single step */ commandrTYPES, /* list hard drive types on table */ commanc:f'VIDEO, /* set/display video adapters */ commandrWATCHL_L* watch bios */ commandrWARM ~T, /* warm boot */ commandrWHEX-; /* write Intel hex */ commanciTO LPT, /* di rect output to lpt * / commandrTO-CON /* di rect output to conso l e * / commandrBAeK TO CON, /* defaul t back to console */ >; - --

/* this enumeration list is used for the register ** display cOllEnds.

A· Type BiosKit

Page 216: Atbios Kit Nov89

*/

enun order { nulreg, axsave,bxsave,cxsave,dxsave,spsave, bpsave,sisave,disave,dssave,essave, sssave,cssave,ipsave,pswsave,

}i

1* l 0 CAL CON S TAN T S */

The Vue File E·17·5

II this is a list of the command tokens for biosvue, it MUST agree with the enumeration list

const command_token_list[]= ( "C", 1* cOfl1)8re */ "CA", 1* cOfl1)8re ascii *1 "CB" , /* cOfl1)8re byte * / "CW", /* cOfl1)8re word */ "CD" , /* cCJl11l8re doubl e * / "CHK" , /* checksun *1 "ClS", 1* clear screen */ "COLO" /* cold boot */ "CMOS"; /* display cmos contnets and checksun */ "DATE", /* set date */ "Oil 1* ~ */ "DAI" /* dUJ1) asci i * / "DB", /* dUJ1) byte * / "DW", /* dUJ1) word */ "00", 1* dll'l1? double */ "DRIVE" /* d1splay or set drives *1 liE II /' enter */ ilEAl, , 1* enter asc ii * / "EB", 1* enter byte */ "EW", /* enter word */ "EO" /* enter double */ "ExItI, /* exi t from SysVue * / "F", 1* fill */ "FA", /* fill ascii */ "FB" /* fi II byte */ "FWII; 1* f ill word * / "FO", /* fill double *1 "H" /* hex add and subtract * / II HARD II /* hard boot */ IIHELP"; /~ display help */ "I", /* 1I)PUt port *1 II I B" /* lnput byte */ "IW"' /* input word */ II INTI, , /* interrupt */ "M'I 1* move * / IIMENU, 1* set/display meory sizes */ "NPX", /* select NPX present or not */ "0", 1* output port */ "OB", /* output byte * / "OW" /* output word * / IlQUIf" /* exit form SysVue */ "R" i* display registers */ II RAX II /* register ax */ "RBX'" /* register bx */ "RCX"' /* register cx */ "ROX'" 1* register dx */ "RSP'" /* register sp */ "RBP" , /* register b{) */ "RSI'" /* register Sl */ "ROI'" /* register di */ "ROS'" /* register ds */ "RES'" /* register es */ "RSS'" /* register ss */ "RCS'" /* register cs */ "RIP"; /* re~ister ip */ "RF", /* reg1ster flags */ "RHEX" /* read Intel hex */ "SI", '1* display id */ "SELECT", /* select watch parameters */ "S" /* search */ "SAl" /* search ascii */ "SB", /* search byte */ "SW", 1* search word */ "SO" 1* search double */ "TIME", /* set time */ "Til, "TRACE", "TYPES", /* list hard drive types on table *1 "VIDEO" /* set/display video adpaters */ "WATCHII; /* watch bios */

Section E: The C ProlUams

Page 217: Atbios Kit Nov89

E·17·6 The Vue File

"WARM", /* warm boot */ "WHEX", /* write Intel hex */ ">LPT", ">CON", ">" 8-1: /* list terminator */

};

// the register token list is searched to determine the switch value for the register commands.

const register_token_list[]= {

II AX II , "BX" , "CX" , "DX" , "Spil , "BP" , liS I II, liD I ", "DSII , liES" , "55" , "CS" , II I P" , -1 , };

// the flag token list is used for the flag register command

const flag token list[]= { --

"NC" , "Cyll, 11 __ 11," __ " , II PO " ,"PEII," .. II ," .. 11 ,"NA" , "AC" ,11 •• 11 ,11 •• 11 , "NZ" ,"ZR" ,11 •• 11,11 •• 11,

"PLII, "NG", liD I II, liE I II ,"UP", "DN", "NV", "OV", 11 •• 11,11 •• 11,11 •• 11,11 •• 11, II .• 11,11 •• 11, II .. ", 11 •• 11,·1, };

// the flag display token list is used for the flag register command

const flag display token list[16] [2]= { - - -"NC", "Cyll, 11 .. 11, .1 •• 11, IlPO", IIPE", 11 •• 11, II. _I', II NAil , "AC" ," .. 11, 11 •• 11, "NZ", "ZR", 1' •• 11, 11 •• 11,

"PL II, "NG", "0 I", liE I", "UP", "DNII, "NV", "OV", I •• _I', 11 •• 11, 11 •• 11, 1' •• 11, 11 •• 11, 11 •• 11, 11 •• 11 , II .. 11 ,

};

// This is a list of the delimiter characters to be accepted when parsing command lines. // A zero value marks the end of the list.

const char delim list[]= { -space,comma,colon,semicolon,leftparen,rightparen,period,ques,tab,quote,slash,D

};

/* PRO G RAM */

/*========= SysVue Setup Routine ==========*/

// This routine is called by the POD to effect the installation of SysVue by patching Interrupt 18.

unsigned sysvue setup() ( -

}

link_interrupt(Ox18,sysvue): return(ok);

/*==============================================*/ /*==============================================*/ /*======= SysVue Main Routine ==================*/ /*==============================================*/ /*==============================================*/

variables end_variables vueregs;

// these are arbitrary identifiers so the main routine will know how it was entered

#define trap oriein 5 #define trace orlein 6 #define boot origln 7 #define diviae origin 8 #define syserr:origin 9

void sysmain():

void interrupt cdecl far Divide(interrupt_registers) ( sysmain(divide origin);

} -void interrupt cdecl far SysError(interrupt_registers) ( sysmain(syserr origin):

} -

void interrupt cdecl far Sysvue(interrupt registers) ( -sysmain(boot origin):

} -

A-Type BiosKit

Page 218: Atbios Kit Nov89

void interrupt cdecl far Systrap(interrupt_registers) ( sysmain(trap origin);

} -. void interrupt cdecl far Systrace(interrupt_registers) ( sysmain(trace origin);

} -

void sysmain(unsigned origin, interrupt registers) ( -vue regs *myblock; enableO; mvblock = acquire block(VUE); j'-variables will~ referenced in sys seg *1

exit_flag = 0;

if«origin == boot origin) && (sysvue_busy 1= 0» ( -write string("\n\rSysVue Busyll);

} -else ( sysYUe_busyz1;

The Vue File E·17·7

II chain the break vector through sysvue logic: if the break flag is set by the sysbreak isr, II return a true from the csts routine to abort the op in progress. when exiting sysvue: II de-chain the vector back to the original state for normal operation.

break chain = get vector(Ox1b); link_Tnterrupt(Oxlb,sysbreak);

II move the stacked registers into the saves so we know where we came from reg saves[axsave] = ax; reg-saves[bxsave] = bXi reg-saves[cxsave] = cx; reg-saves[dxsave] = dx; reg-saves[sisave] = si; reg:saves[disave] = di; reg saves[essave] = es; reg:saves[dssave] = dsi reg_saves[spsavel = SPi reg saves[sssave] = get sse); reg:saves[eswsave] =.fligs; reg_saves[lpsave] = lp; reg_saves[cssave] = CSi

if(origin == trace_origin) II de-chain trace vector ( set_vector(Ox1,trace_chain » 16,trace_chain)i

II if(peek(Ox26a,Ox316) == OxObeb) II{ II place for option of silent trace until condition II trace_count = 1i display regs(&reg saves); wdte sfring("\n\;: II). lwordfcs);write string(":II)ilword(ip)iWrite string(" II); lbyte(peeKb(cs,Tp»i -wrlte string(" II). lwordfpeek(cs,iP+~»;

II} if(--trace count 1= 0) ( -

if(console break(» { -exit flag=Oi trace cOl.l'lt=1;

} -else { I I check for any key if (kbhitO) { exit flag=O; trace count=1;

} -else

Section E: The C Pro&rams

Page 219: Atbios Kit Nov89

E·17·8 The Vue File

}

( exit flag=1; reg savesCpswsave] /= Ox0100; // set trace bit // chain-in the trace vector trace chain = get vector(Ox1); link Tnterrupt(Oxl,Systrace);

} -}

}

if(origin == trap origin) // de-chain trap vector { -

}

// restore the trapped locations and decrement the pc value // clear the trap saves and stuff

if(origin == boot origin) { -trace COU'lt = 1; // restore the trapped locations and decrement the // pc value // clear the trap saves and stuff

}

mode size = byte: /* default to byte presentation mode */ mode-type = hex: /* default to hex (not ascii) */ if(origin == boot origin) ( -write string("\nVSysVue Copyright (c) FOSCO 1988, 1989 - All Rights Reserved."):

} -if(origin == divide origin) ( -write string("\n\roivide Overflow at location - II): lwordfcs): write string(":");lword(ip);

} -if(origin == syserr origin) ( -write string("\n\rSystem Error, Type - II): lword(ax):

} -

while Cexit flag ==0) ( -wrhe string(lI\n\rSysVue>II); get_lTne_inputCcr):

/* move pas t lead i ng spaces * / while(buffer[buffer_index] == , I) buffer_index++:

ifCget tokenC) == true) /* if there is a command */ ( -/* get the token number for the ** command from the token list */ command_index = get_token_numberC&command_token_list):

/* get the rest of the arguments on the command line */ get_valuesC):

/* execute the command */ switch Ccommand index) ( . -defaul t: /* conmand not fOU"ld */ syntax errorC): break:-

/*============ COMPARE COMMAND =======*/

case command CA: mode_type = ascii; mode_size = byte: goto compare_case;

case command CB: mode_type = "ex; mode_size = byte; goto compare_case:

case command CW: mode_type = "ex; mode_size = word; goto compare_case;

case command CD: mode_type = "ex: mode_size = dword; goto compare_case:

case command_C:

A-Type BiosKit

Page 220: Atbios Kit Nov89

The Vue File E·17·9

cClq)Sre case: do -( if (peekb(token_vaLueCO],token_vaLueC1]) 1= peekb(token_vaLueC4],token_vaLueCS]»

co(13): co(10)-Lword(token vatueCO])i CO(':')i lword(token-vaLue[1])i co(' '): cof'>'): co(' ')­Lbyte(peekb(token_vaLueCOi,token_vaLueC1]»: co(' '): co(' '): Lbyte(peekb(token_vaLueC4],token_vaLueCS]»: co(' '): cO('<'): co(' '): Lword(token value[4])i co(':'): Lword(token-valueCS])i

} -if(consoLe break(» breaki token vaLueC1]++: token vaLue[S]++;

} - -whiLe «token vaLueC1] < token_vaLueC3]) && (token_va lue [T] != 0»:

break:

/*======= CLear Screen Command ===========*/

case command CLS: /I read current video mode mybLock->ax = OxOfOO; sys int(Ox10,mybLock); // reset video mode (cLears screen) mybLock->ax = myblock->ax & OxOOffi sys_int(Ox10,mybLock)i break:

/*=========== CMOS Command ================*/

case command_CMOS:

// this wouLd be a great pLace to have a dump of the CMOS contents_

write string("CaLcuLated CMOS checksun: II); token-vaLueC1]=0-foretoken vaLuec6] = Ox10: token value[O] < Ox2e: token vaLue[O]++) -( -token vaLue[1] += incmos(token vaLue[O]);

} - -lword(token_value[1]);

write string("\nV ActuaL CMOS checksun: II); lword(incmos(Ox2e)« 8) I incmos(Ox2f»i

break;

/*============ 0 Commands =================*/

case command OA: mode_size = 6yte; mode_type = ascii; goto dump_case:

case command OB: mode_size = 6ytei mode_type = hex; goto dump_case;

case command OW: mode_size = word; mode_type = hex; goto dump_case;

case command 00: mode_size = aword; mode_type = hex; goto dump_case;

case command 0: dump_case: -

cc = 2S6; /* defauLt ~ Length in characters */ if (mode_type == ascii) cc = 1024;

if «present & OxSO) == 0) ( token value[1] = last dump start off + CCi

}token:value[O] = last:dump:start:seg;

if (token_value[3] == 0) ( token vaLue[3] = token vaLue[1] + cC;

) - -last_dump_start_seg = token_value[O];

Section E: The C Pro&rams

Page 221: Atbios Kit Nov89

E·17·10 The Vue File

last_dump_start_off = token_value[1];

do ( co(cr); co(lf); lword(token value[O]); co(':');lword(token_value[1T); co(' ');

if (mode type == ascii) { -do (

}

cc = peekb(token value[0]6token value[1]++) & Ox7f; if «cc < Ox20) TI (cc> x7e»-cc = '.'; co(cc);

while «token value[1] X 64) 1= 0); } -~f «mode_type == hex) II (mode_type == 0»

if «mode size == byte) II (mode size == 0» {- -do ( co(' '); lbyte(peekb(token value[O],token value[1]++»; /* print extra spice every four Characters */ if «token value[1] X 4) == 0) co(' ');

} - .

while «token value[1] X 16) 1= 0); } -if (mode size == word) { -do { co(' '); lword(peek(token value[O],token value[1]»; token value[1] += 2; -if «ftoken value[1] & Oxfffe) X 4) == 0) co(' ');

} -while «(token value[1] & Oxfffe) X 16) 1= 0);

} -if (mode size == dword) { -do ( co(' '); lword(peek(token_value[0],token_value[1]+2»; co(':'); . lword(peek(token value[O],token value[1]»; token value[1] += 4· -if «ftoken value[1i & Oxfffc) X 4) == 0) co(' ');

} -while «(token value[1] & Oxfffc) X 16) != 0);

} -/* print the ascii char for the hex dump */ co(' '); token value[1] -= 16; do -(

}

cc = peekb(token value[0]6token value[1]++) & Ox7f; if «cc < Ox20) TI (cc> x7e»-cc = '.'; co(cc);

while «token value[1] X 16) 1= 0); } -if (console break(» break;

} -while «token value[1] < token value[3]) && (token value[1] 1= 0»; break; - - -

/*=========== Exit Commands ============*/

case command EXIT: case comma~QUIT: exit flag=1;­breaK;

/*=========== Enter Commands ============*/

case command EA: mode_size = 5yte; mode_type = ascii; goto enter_case;

A· Type BiosKit

Page 222: Atbios Kit Nov89

case command EB: mode_size = 6yte; mode_type = hex; goto enter_case;

case command EW: mode_size = word; mode_type = hex; goto enter_case;

case command ED: mode_size = aword; mode_type = hex; goto enter_case;

case command_E:

II if e<enter> then it is execute else it is enter

if (value-present(1) == 0) 1/ e<enter> is execute <

}

exi t flag=1; trace count = -1; reg sives[pswsavel 1= Ox0100; II set trace bit II Chain-in the trace vector trace chain = get vector(Ox1); link Tnterrupt(Oxl,Systrace); breaK;

enter_case:

1* if there is a command line input, just store it *1 if(value-present(3) == true)' <

The Vue File E·17·11

if(mode size == byte) pokeb(token value[O],token value[1],token value[3]); if(mode-size == word) poke(token value[O],token value[1],token value[3]); if(mode-size == dword) - - -

< -poke(token value[O],token value[1],token value[3])· poke(token-value[0],token-value[1]+2,tokin value[2i);

} - - -} else <

lword(token_value[O]); co(':'); lword(token_value[1]);

1* solicit input *1

enter seg = token value [0] ; enter:off = token:value[1];

inchar = , ,. while (inchar == , ') < co(' '). if(mode'size==byte) lbyte(peekb(enter seg,enter off»; if(mode-size==word) lword(peek(enter seg,enter off»; if(mode-size==dword) --< -

lword(peek(enter_seg,enter_off+2»; co(':'); lword(peek(enter seg,enter off»;

} --co('-')· get line input(' '). 1* terminate this on a space or a cr *1 vet valuesC); If(value-present(1)) <

if(mode size==byte) pokeb(enter seg,enter off,token value[1]); if(mode-size==word) poke(enter seg,enter off,token value[1]);

}

}

if(mode-size==dword) - - -< -poke(enter_seg,enter_off,token_value[1]); poke(enter seg,enter off+2,token value[O]);

} - - -enter off = enter off + mode size; if (Center off X 8) == 0) -< -co(cr); co(lf); lword(enter seg); co(':'); lword(enter_off);

} -} break;

1*========== Fill Commands ============*1

Section E: The C ProlUams

Page 223: Atbios Kit Nov89

E·17·12 The Vue File

case comnand FB: mode_size = 6yte; mode_type = hex; goto fill_case;

case comnand FW: mode_size = word; mode_type = hex; goto fill_case;

case comnand FO: mode_size = award; mode_type = hex; goto fill_case;

case conmand F: fill case: -do -( if(mode size == byte) pokeb(token value[O],token value[1],token valuerS]); if(mode-size == word) poke(token value[O],token value[1],token value[S]): if(mode-size == dword) - - -( -poke(token value[O],token value[1],token valuerS])· poke(token:value[0],token:value[1]+2,token_value[4i);

) if(console break(» break; token value[1] += mode size;

) - -while (Ctoken value[1] < token value[3]) && (token value[T] 1= 0»; -break;-

1*======= Int Conmand =================*1

II This command invokes the interrupt selected. It uses the sys int registers and the II sys_int conmand. The user has to confirm the command with an-X to eXecute it.

II this command should use a separate set of registers 1111

case command_I NT:

1* get the interrupt runber from the conmand line */

1* print the vector value *1

if Ctoken value[1] < 256) ( -write_stringC"lnterrupt is at II);

int off = peek(OxOO,token value[1] * 4)· int:seg = peekCOxOO,ctoken_value[1] * 4) +2);

lwordCint_seg); co(':'); lword(int_off); co(' ');

write_stringC"Press X to confirm eXecution");

1* wait for confirmation *1 cc = ciO;

if CCcc == 'X') II Ccc == 'x'» (

)

write stringC"\n\r"); /1 do a cr If for a clean line mybloek ->ax = reg saves[axsave]; myblock ->bx = reg:saves [bxsave] ; myblock ->cx = reg saves[cxsave]; myblock ->dx = reg-saves [dxsave]; myblock ->si = reg-saves[sisave]; myblock ->di = reg-saves[disave]; myblock ->ds = reg-saves [dssave] ; myblock ->es = reg:saves[essave];

sys_intCtoken_value[1J,myblock);

outreg saves[axsave] = myblock ->ax; outreg-saves[bxsavel = mYblock ->bx; outreg-saves[cxsavel = mYblock ->cx; out reg-saves [dxsavel = mYblock ->dx· outreg-saves[sisave] = mYblock ->si; outreg-saves[disave] = mYblock ->di; outreg-saves[essave] = myblock ->es; outreg-saves[dssave] = myblock ->ds· outreg:saves[pswsavel = myblock ->f{ags;

1* display the register upon return */ display regsC&outreg saves);

) - -else write_stringC"Value Out of Range II);

break;

A-Type BiosKit

Page 224: Atbios Kit Nov89

/*============= HELP =============*/ case command HELP: write string("C <range> <address> - c~re\nV"); write-string("CLS - Clear Screen\n\rll );

write-string("CHIC <range> - checksun\n\r")· write-string("COLD - cold boot to cwrent Bios\nv"); wr!te:str!ng("CMOS - display the CMOS checksun\nV"); wrlte strlng("D[type] [<ra~e>] -~ memory\n\rll); wr!te:str!ng("DRIVE [0-3 I A:-F:] [type] • dlsplay/set drives\n\r"); wrlte strlng("DATE [xx/xxlxxxx] • Display or Set Date\nV"); write-string("E - execute single st~ until any key hit\n\r"); write-string(IIE[type] <address> [<list>] - enter\n\r"); write-string("EXIT - exit from SysVue\n\r"); write-string("F[type] <range> <llst> - fi II \n\rll );

write-stringCIIH <value> <value> - hex add/sub\n\r")i wr!te:str!ng("HARD - re-boot to primary Bios\nV")i wr!te_stqngC"HELP - help screen\n\r")i wr!te_str!ngC"I[type] <address> - In port\n\r")i wr! te_stqng(IIINT <value> - Interrupt\n\r")i wrlte strlngC"M <range> <address> - move\nV"); write-stringCIIMEM [sys,ext] - display/set memory sizes\nV"); pause'f); wr i te s t r i ngC "NPX [0111 - No NPX/Yes NPX\n\r"); wr!te:str!ngC"O[typel <~ress> <value> • OUt port\n\r"); wrlte strlngC"QUIT - eXlt from SysVue\n\r"); write-stringC"R[<reg>] <value> - register\n\r"); write-string("RHEX <range> - read Intel hex\nV"); write-stringC"S[type] <range> <key> <mask> - search\n\r"); write-stringC"SELECT - Select Watch Parameters\n\rll );

The Vue File E·17 ·13

write-stringC"SI - Display System Information\n\r")i write-string("TIME [xx:xx:xx] - Display or Set Time\n\r"); write-stringC"TRACE [ccx.nt] - Trace ccx.nt steps or untH anykey hit\nV")i write-string(IITYPES - Display hard disk t~ parameters\n\r"); write-string("VIDEO [type] - display/set vldeO type\n\r"); write-stringC"WARM - warm boot to current Bios\n\r")i write-string("WATCH - Toggle watch on/off\nV"); write-string("WHEX <range> - write Intel hex\nV")i write:stringC">[CON I LPT] - redirect console output\n\r");

breaki

/*========== Calculator Command =========*/ case command H: write string{"Sun is: II); lwordctoken value[1]+token value[3])i write:stringc" Difference is: II); lwardCtoken_valuelll-token_value[3]); break;

/*===== Sys Info Command ===========*/ case command_SI:

wdte string("\n\r Current Time: II); <:iisplay timeO; write:stringc"\n\r Current Date: ");dlsplayjlateO;

write_stringC"\n\r Bios Name: II); write_string(&bios_id);

write_stringC"\nV Bios Version: II); write_string(&ver_id);

write_string("\n\r Bios Date: II); write_string(&date_st8ll1l);

write_stringc"\nV Copyright: II); write_string(&owner_id);

write_stdng("\n\r Bios Size: 64k At Segment: II); lword(bios_csO);

write string("\n\r CPU: II). I! a cpu type sensing routine could ~ added here wr!te_str!ng(I80286"); wrl te_strlng("\n\r NPX: II); display_npxO;

write string("\n\r Com Ports: II); for (cc = 0-CCcc < 4) i1 Cpeek40C&comm list[cc]) != O»;cc++) ( -

lwordCpeek40(&comm list[cc]»; co(' '); } -write string("\n\r LPT Ports: II); for (cc = O· «cc < 3) i1 (peek40C&lpt list(cc]) != O»;cc++) ( -

lword(peek40(&lpt list[cc]»; co(' '); } -// display the disk drives in the system

Section E: The C Pro&rams

Page 225: Atbios Kit Nov89

E·17·14 The Vue File

display_drives();

display_video();

write string(lI\n\rMemory Size write-string("\n\r Expected: di~pliy sys_mem(); wrl te sirlllg(" display ext mem();

II);

System II) ;

Extended");

write sirini("\n\r Fot.nd: II). bin2dic(peek40(Ox13) + (sys seg size/10~4),&dec array); co(dec array[O]); - - -co(dec-array[1]); co(dec-array[2]); co(dec-array[3]); co(dec:array[4]);

write string(" II). bin2dic(cmos ext found(),&dec array): co(dec arrayTO]); -co(dec:array[1]): co(dec_array[2]); co(dec array[3]); co(dec:array[4]):

#if(O==1) write string(lt\n\rCMOS Values are: It ); write-string(lt\n\rOiagnostic 'I): lbYte( ncmos(OxOe» wri te-string(lt\n\rRestart 'I): lbYte( ncmos(OxOf» write-string(lt\n\rFloppy Disks 'I); lbYte( ncmos(Ox10» write-string('I\n\rHard Disks II): lbyte( ncmos(Ox12» write-string("\n\rEquipnent 'I): lbYte( ncmos(Ox14» #endi'

break;

/*------- set time -------------*/ case command TIME: i f (va l ue..,preient (0» /I i f anyth i ng entered { myblock->cx = token_value[O]: myblock->cx = (mvblock->cx « 8) I token_value[1]: myblock->dx = token valueD]; myblock->dx = ~loCk->dx « 8; myblock->ax = Ox0300; sys int(Ox1a,mvblock); if(!myblock->flags & carry bit) 1= 0) write string("Error settini time"):

} - .

write_string("Current Time is - It);display_time(): break: . .

/*------- set date -------------*/ case conmand DATE: if(value..,preient(O» /I if anything entered { myblock->dx = token value[O]: myblock->dx = (mvblOck->dx « 8) I token value[1]: myblock->cx = token value[3]: -myblock->ax = Ox0500; sys int(Ox1a,mvblock): if(!myblock->flags & carry bit) 1= 0) write string("Error settini date'I):

} -write_string("Current Date is- 'I):display_date()i break;

/*------- set drives -----------*/ case command_DRIVE:

// if value - a-f, then set type of drive in system if«token value[O] >= OxOa) && (token value[O] <= OxOf» (- -// a and b are easy, c,d,e,f have to count drives

/I A: is floppy if(nuttler of floppiesO > 0) ( - -

if(token value[O] == OxOa) ( -outcmos(Ox10,(incmos(Ox10) & OxOf) I «token_value[1] & Ox0007) « 4»:

}

A-Type BiosKit

Page 226: Atbios Kit Nov89

) II B: is floppr if(number_of_f oppies() > 1) (

if(token value[O] == OxOb) ( -

The Vue File E·17·15

outcmos(Ox10,(incmos(Ox10) & OxfO) (token_value[1] & Ox0007»i )

) II C: is flOppr if(number_of_f oppies() > 2) (

if(token value[O] == OxOc) ( -)

)

outcmos(Ox11,(incmos(Ox11) & OxOf) I «token_value[1] & Ox0007) « 4»;

II 0: is floppr if(number_of_f oppies() > 3) (

if(token value[O] == OxOd) ( -outcmos(Ox11,(incmos(Ox11) & OxfO) I (token_value[1] & Ox0007»;

) ) 11------- these are for hard disks --------­if(number of floppies() <= 2) II C: ana-O:-are hard drives (

if(token value[O] == OxOc) { -if (token value[1] < 14) II use primary cell ( -outcmos(Ox12,(incmos(Ox12) & OxOf) I «token value[1] & OxOOOf) « 4»;

) -

}

else II use secondary cell ( outcmos(Ox12,incmos(Ox12) 1 OxfO); outcmos(Ox19,token value[1 )i

) -if(token value[O] == OxOd) { -

if (token value[1] < 14) II use primary cell ( -outcmos(Ox12,(incmos(Ox12) & OxfO) I (token value[1] & OxOOOf»;

) -

) }

else II use secondary cell ( outcmos(Ox12,incmos(Ox12) 1 OxOf); outcmos(Ox1a,token value[1 )i

} -

if(number of floppies() == 3) II 0: ana-E:-are hard drives (

if(token value[O] == OxOd) { -if (token value[1] < 14) II use primary cell ( -outcmos(Ox12,(incmos(Ox12) & OxOf) I «token value[1] & OxOOOf) « 4»;

) -

}

else II use secondary cell ( outcmos(Ox12,incmos(Ox12) I OxfO); outcmos(Ox19,token value[11);

} -if(token value[O] == OxOe) { -if (token value[1] < 14) II use primary cell ( -outcmos(Ox12,(incmos(Ox12) & OxfO) I (token value[1] & OxOOOf»i

) -

} )

else II use secondary cell ( outcmos(Ox12,incmos(Ox12) I OxOf); outcmos(Ox1a,token value[11);

) -

if(number of floppies() == 4) II E: ana-F:-are hard drives (

if(token_value[O] == OxOe)

Section E: The C ProlP"ams

Page 227: Atbios Kit Nov89

E·17·16 The Vue File

}

{ if (token value[1] < 14) // use primary cell ( -outcmos(Ox12,(incmos(Ox12) & OxOf) I «token_value[1] & OxOOOf) « 4»;

} . else // use secondary cell ( outcmos(Ox12,incmos(Ox12) 1 OxfO); outcmos(Ox19,token value[1 )i

} -} . if(token value[O] == OxOf) { -

}

if (token value[1] < 14) // use primary cell ( -}outcmoS(Ox12,(incmoS(OX12) & OxfO) I (token_value[1] & OxOOOf»;

else // use secondary cell { outcmos(Ox12,incmos(Ox12) 1 OxOf); outcmos(Ox1a,token value[1 );

} -

calc cmos(); // recalc checksum } -else (

if(value-present(1» // if anything entered { // if value = 0-4, then' of drives in system if(token value[1] <= 4) ( -

)

if(token value[1] == 0) // set no-drives in system ( -outcmos(Ox14,incmos(Ox14) & -Ox01); calc cmosC);

} -else // there are drives in system ( outcmos(Ox14,incmos(Ox14) I Ox01)! outcmos(Ox14,(incmos(Ox14) & Ox3f} I \ «token value[1]-1) « 6»; calc cmOSC)i

} -}

} write string("Qptions are\n\r"); write-string("0-4 = , of floppy drives\n\r"); write-string("A:n - F:n = set drive type\n\rll). write-string("For Floppy drives:\n\r"); , write-string(" 0 = no drive\n\r"); write-string(" 1 = 360k drive\n\r"); wri te-string(" 2 = 102M drive\n\r"); write-string(" 3 = nOk drive\n\r"); write-string(" 4 = 1.44M drive\n\r"); write-string("For Hard drives:"); write-string(" n = drive type\n\r"); write-string("For list of hard drive types, enter IIiITypesllllll); display_drives(); break;

/*------ list drive types fro. hdisk table ----*/

case command TYPES: display_hdisK_typeS(); break;

/*------- set memory sizes ----------*/ case command_MEM:

if(value-present(1» /1 if anything entered { set sys mem(dec2bin(token value[1]»;

} - - -if(value-present(3» // if anything entered { set ext mem(dec2bin(token value[3]»;

} - - -wr!te_str!ng(" System Memory Size !S - .");displ!y_sys_mem(); wr1te_str1ng("\n\rExtended Memory S1Ze lS - 1I);d1splay_ext_mem();

break;

A· Type BiosKit

Page 228: Atbios Kit Nov89

1*--- select NPX present/not present ----*1 case command NPX: if(value"present(1» ( .

if«token value[1] & Ox01) == 0) ( -outcmos(Ox14,incmos(Ox14) & -Ox02);

} else ( outcmos(Ox14,incmos(Ox14) I Ox02);

} calc cmos();

} -write_string("Options are: 0 = No, 1 = Yes\n\r"); wrl te strlng("NPX II). displiy npx(); , break; -

1*------- set video type ----------*1 case command VIDEO:

The Vue File E·17·17

write string'f"Options are\n\rO=EGA\n\r1=CGA 40x2S\n\r2=CGA 8Ox2S\n\r3=Monochrome"); if(vaTue"present(1» II if anything entered ( II chekc for argument rang~ validity if«token value[1] >= 0) && (token value[1] <= 3» (- -II this is where we set the video bits outcmos(Ox14,(incmos(Ox14) & Oxcf) I «token value[1] & Ox0003) « 4»; calc cmos(); -

} -else ( write string("\n\rVideo type argunent IIlJst be between 0-311

);

beip(); }

} else ( write string("\n\rTo change Expected Video, type IIIIVIDEO n <enter>"II\n\r");

) -display video(); break; -

1*======== Input from port Command ======*/

case command_IB: mode_size = byte; lbyte( inportb(token_value[1]»; break;

case command_IW: mode_size = word; lword(inport(token_value[1]»; break;

case command I: switch (mode-size) ( -case byte: lbyte(inportb(token value[1]»; break; case word: lword(inport(token value[1]»; break;

} -break;

1*========= OUtput from Port Commands =========*/

case command_OS: mode_size = byte; outportb(token_value[1],token_value[3]); break;

case command_OW: mode_size = word; outport(token_value[1],token_value[3]); break;

case command 0: switch (mode-size) ( -case byte: outportb(token value[1],token value[3]); break; case word: outport(token-value[1],token-value[3]); break;

} --break;

1*=== Move Command ===*1 case command_M:

do ( pokeb(token value[4],token value[S)++, ~ekb(token-value[0]/token-value[1]++»; if(console 6reak(» Dreak;-

} -

Section E: The C ProlUams

Page 229: Atbios Kit Nov89

E·17·18 The Vue File

while «token value[1] < token value[3]) && (token value[T] 1= 0»; -break;-

/*=== Register Display Command ===*/ case command R: /* display all the registers */ display_regs(&reg_saves); break;

/*=== Register Display and Change Commands ===*/ case command_RAX: reg_index = axsave; goto r_display;

case command_RBX: reg_index = bxsave; goto r_display;

case command_RCX: reg_index = cxsave; goto r_display;

case command_RDX: reg_index = dxsave; goto r_display;

case command_RSP: reg_index = spsavei goto r_displaYi

case command_RBP: reg_index = bpsavei goto r_display;

case command_RSI: reg_index = sisavei goto r_displaYi

case command_RDI: reg_index = disavei goto r_displaYi

case command_RDS: reg_index = dssavei goto r_display;

case command_RES: reg_index = essave; goto r_displaYi

case command_RSS: reg_index = sssave; goto r_displaYi

case command_RCS: reg_index = cssavei goto r_displaYi

case command_RIP: reg_index = i psave; goto r_displaYi

r_display:

/* if there is a commend line input, just store it */

if(value-present(1) == true) < reg saves[reg index] = token value[1]; } - - -else <

}

write string(peek(bios cs(),&register token list[reg index-1]»; co( I T). - - - -lword(res saves[reg index])i co(cr)i co(lf)i cO(T:')i

/* solicit input for register */

get_line_input(cr); ~et values()i If(value-present(1)) < reg saves[reg index] = token_value[1]i

} - -breaki

/*-------- Flag Register Command ---------*/ case command_RF:

/* we have to look at comnand line for flag alpha1s */ /* if there is a comnand line input, just store it */

command_index = get_token_number(&flag_token_list)i

if(commend index == 0) // solicit input < -display flags(); write sYring(" • II). get_lTne_input(Cr)i' get token(); command index = get token number(&flag token list);

} - - - --if (commend index 1=.0) < -

commend index--i // rebase to zero lword(cOmmand_index)i

A· Type BiosKit

Page 230: Atbios Kit Nov89

if «command index & 1) == 0) { -1* even number - clear bit */ reg saves[pswsave] &= -(1 « (command index/2»;

} - -else { /* odd number - set bit *1

} reg_saves [pswsave] 1= (1 « (command_index/2»;

) break;

/*========= Read Intel Hex =================*/

case command_RHEX:

/* start looking for record marker */

do ( while(inchar = ci() 1= ':') {} Sllll = 0; char count = get byte(); token value[1] =-get word(); recora_type = get_byle();

switch (record type) { -case data record: if (char count == 0) { -record type = end of file record; break;- - - -

} while (char count> 0) { -pokeb(token value[O],token value[1],get byte(»i

} - - -get byte()i 1f {Sllll 1= 0) record type = end of file record; break; - - - -

case end of file record: /* return to sysYue main *1 break;

case extended address record: /* set load aadress sigment *1 token value[O] = get word(); get cyte()i -if {Sllll 1= 0) record type = end of file record; break; - - - -

case start address record: /* set cs:Tp of reg set */ reg saves[cssave] = get word(); reg-saves[ipsave] = get-word(); getlbyte()i -if {Sllll 1= 0) record type = end of file record," break" - - - -

} , } while (record type 1= end_of_file_record); break; -

/*========= Write Intel Hex =================*/

case command_WHEX:

/* disregard if range = nul */ if «token value[1] II token value[3]) != 0) (- -

/* write extended address record for segment *1 write_string(lI\r\n: II );

Sllll = 0i pbyte(2)ipword(O);pbyte(2); pword(toKen_value[O])i PbYte( Sllll) ; do { write string(lI\r\n: lI )i if «token value[3] - token value[1]) > 16) {- -char count = 16;

} -

The Vue File E·17·19

Section E: The C Prolaams

Page 231: Atbios Kit Nov89

E-17-20 The Vue File

else ( char count = token value[3] - token_value[1];

) - -sum = o· . pbyte(Char count); /* record count */ pword(token value[1]); /* address */ pbyte(O); /- data mode_type record */ whlle (cnar count> 0) ( -pbyte(peekb(token_value[0],token_vaLue[1]»; token vaLue[1]++; char_count--;

}-PbYte(sun); if (console break(» break;

} -while «token value[1] < token value[3]) && (token_value[T] 1= 0»; -

/* write start address record */ if «token value[4] II token value[5]) 1= 0) (- -

}

write string(II\r\n:II); sun =-0-pbyte(4);pword(0);pbyte(4); pword(toKen vaLue[4]); pword(token-vaLue[S]); pbyte(sun);-

write string("\r\n:00000001FF"); } -break;

/*========= Search Commands =================*/

case command_SA: mode_size = byte; mode_type = ascii; goto search_case;

case command_S8: mode_size = byte; mode_type = hex; goto search_case;

case command_SW: mode_size = word; mode_type = hex; goto search_case;

case command_SO: mode_size = dword; mode_type = hex; goto search_case;

case command_S:

search_case:

/* if no mask entered, then aLL bits significant */ if«token vaLue[6] I token value[7] ) == 0) (- -

token value[6] = -token value[6]; token-value[7] = -token-value [7] ;

) - -if (mode size == byte) /* clear-un-needed bits from mask */ ( token value[6] = 0-token-value[7] &= 6xOOff;

) -if (mode size == word) /* cLear-un-needed bits from mask */ ( token value[6] = 0;

) -do ( if««peek(token value[O],token value[1]) & token value[7]) ==

(token value[5] ,; token value [7] »I && «(peek(token value[Or,token value[1]+2) & token value[6]) ==

- (toien_value[4] & token:value[6]»» ( co(13); co(10)· /* cr-lf */ l word( token_va {ue [0.] ) ; co(':'); lword(token_vaLue[1])i co(' ');

if (mode size == byte) ( -

Lbyte(peekb(token value[O],token value[1]»; } - -

A· Type BiosKit

Page 232: Atbios Kit Nov89

if (mode size == word) { -

lword(peek(token value[O],token value[1]»i } - -if (mode size == dword) ( -

lword(peek(token_value[0],token_value[1]+2»i cO('-')i lword(peek(token value[O],token value[1]»;

} - -} if(console break(» break; token value[1] ++;

} -while «token value[1] < token value[3) && (token value[l] 1= 0»; - . breaki-

1*========= Checksum Command ===========*1 case command CHK: sum = 0; -do {

sum += peekb(token value[O],token value[1]++)i if (console break(J) break; -

} -while «token value[1] < token value[3]) && (token value[l] 1= 0»; . -1* ~in the last byte *1 sum += peekb(token value[O],token value[1])i write string("ChecKsum = II); -lbytefsum); break;

1*========== Re-Boot Commands ===========*1 case command COLD BOOT: RESET FLAG =-0; IW reset the wanm boot flag *1 disabTeO" incmos(OxOO); II set NMI mask far call(bios cs(),&reset)i breik; -

case command WARM BOOT: 1* reset the-warm~t flag *1 RESET FLAG = Ox1234; disabTe()" incmos(OxOO); far call(bios cs(),&reset); breik; -

II set NMI mask

case command HARD BOOT: 1* forces cs: to fOOO *1 RESET FLAG =-0; IW reset the warm boot flag *1 . diSabTe()6" incmos(OxOO)i II set NMI mask far_call( xfOOO,OxfffO); breaki

1*========== Trace Commands ===========*1 case command T: case comma~TRACE: trace count = token value[1]; if(trice count == OJ trace count = 1; exit flag=1; -reg iaves[pswsave] 1= Ox0100; II set trace bit II Chain-in the trace vector trace chain = get vector(Ox1); link Tnterrupt(Oxl,Systrace); breaK;

1*======= Select Watch parms command =======*1 case command SELECT: if (value-present(1» { II modi fr parms watch se ection = token value[1];

} - -write string(1I0ptions are (the OR) as follows:\n\r"); lworC«VIDEO); write string(1I = Video\n\rll); lword(VUE)i write itring(1I = SysVue\n\r"); lword(CASSETTE); wrTte string(1I = Cassette\n\r"); lword(EQUIPMENT); write string(" = Equip\n\r"); lword(MEMORY); write stringCII = Mem\n\r")i lword(LPT); write stringC" = Lpt\n\r"); lword(COM); write:string(" = Com\n\rll)i

The Vue File E·17·21

Section E: The C ProlUams

Page 233: Atbios Kit Nov89

} };

E·,17· 22 The Vue File

lword(FLOPPY); write string(1I = Floppy\n\r"); lword(HARD); write string(" = Hard\n\r"); lword(TOO); write itring(1I = Tod\n\r"); lword(BOOT); write_string(1I = Boot\n\r");

write string("Current Watch Selections are: II); watcn selection &= WATCH MASK;

if(watCh selection == 0) write string("None"); if«watcn selection & VIDEO) 1= 0) write string("Vic::leo II); if«watch-selection & VUE) 1= 0) write string("SysVue II); if«watch-selection & CASSETTE) 1= 0) write string("Cass II); if«watch-selection & EQUIPMENT)I= 0) write-string("Equip II); if«watch-selection & MEMORY) 1= 0) write string("MeII II); if«watch-selection & LPT) 1= 0) write string("Lpt II); if«watch-selection & COM) 1= 0) write-string("Com II); if«watch-selection & FLOPPy) 1= 0) wrTte string("Floppy II); if«watch-selection & HARD) 1= 0) write string("Hard II); if«watch-selection & TOO) 1= 0) write itring("Tod II). i f«watch-selection & BOOT) ! = 0) wrf.ti string("Boot II); if«watch-selection & TIMER) 1= 0) write string("Tmr II). i f«watch:selection & KEYBOARD) 1 = 0) wrTte_string(IIKb II);

write string("\n\rWatch is currently II); if(watch flag == 0) . ( -write_string("Off");

} else ( write string(IOn")·

} - , break;

/*=========== Watch command ==============*/

case command WATCH: 1/ toggle watch flag if (watch flag 1= 0) ( -watch flaV = 0; Write:Strlng(" Off");

} else ( Write String(" 0n")· watch-flag = watch selection; if(reairect flag 1= 0) watch flag &= -LPT;

} - -break;

/*=========== Re-direction commands ==============*/

case command TO CON: case commandrBACK TO CON: redirect flag = 0; -break; -

}

case command TO LPT: redirect flag =-1; // If you are watching the printer driver, it must not be copying screen output to the printer. // An lnsidious recursion results, blowing the system away if«watch_flag & LPT) 1= 0) watch_flag &= -LPT; break:

ax = reg_saves[axsave]; bx = reg_saves[bxsave]; cx = reg saves[cxsave]; dx = reg-saves[dxsave]; si = reg-saves[sisave]; di = reg:saves[disave]; ds = reg saves[dssave]; es = reg-saves[essave]; flags = reg_saves[pswsave]: cs = reg saves[cssave]i ip = reg:saves[ipsave];

// If tracing, we should link the trace vector here // If trapping (breakpointing), we should link the trap vector here.

set_vector(Ox1b,break_chain » 16,break_chain):

A· Type BiosKit

Page 234: Atbios Kit Nov89

The Vue File E·17·23

sysvue busy = 0; /* release Sysvue */ ) -release block(myblock);

) -/******************************************************/

1*=========== Console Status Routines ============*/

unsigned console break() 1* returns true Tor abort operation */ {

)

if (break flag == 0) return(false); break_ fl a9 = 0; return(true);

1*-------------------------------------------------*/ 1* dump byte and word functions *1 void pword(w) /* print word, accumulate checksum */ ( pbyte(w » 8); pbyte(w);

)

void pbyte(outchar) /* print byte, accumulate checksum */ (

}

sum -= outchar; /* build checksum ·for whex conmand */ lbyte(outchar);

1* dunny rvni interrupt rout i ne * /

void rvni intO { -}'

1*--------- supporting functions -------------*/

/I This fooction displays the register set. It is used by the 'R' Conmand and the' INT' Conmand.

void display regs(unsigned *reg saves) (- -

co(cr); co( If); for (token index = O;token index < 13;token index++) (- - -

write string(peek(bios cs(),&register token list[token index]»; CO(,=T). - - - -lword(reg saves[token index+1]);· co(' '). co(' '); -if (token index == 7) ( co(cr); co(lf); )

) -co(' '); co(' '); display flags(reg saves);

) - -void display flags(unsigned *reg saves) {- -

)

unsigned even odd; int scan index; /* displiy the flag conditions */

for (scan index = 15; scan index> -1; scan_index--) {- -

)

even_odd = (reg_saves[pswsave] » scan_index) & 1;

~f (peekb(bios_cs(),peek(bios_cs(),&flag_display_token_list[scan_index] [even_odd]»

write string(peek(bios cs(),&flag display token list[scan index] [even odd]»; co(' T); - - - - - -

)

1*------- get a byte for rhex ---------*/

char get_byte() ( char cc,d; cc = ci() - '0'· if (cc > 9) cc ~= 7· g = ci() - '0'; , 1f Cd > 9) d -= 7; cc = CC « 4 I d;

1= '-')

Section E: The C ProlUams

Page 235: Atbios Kit Nov89

E·17·24 The Vue File

sun += cc· return (d);

)

1*------- get a word for rhex ---------*1

unsigned get warde) ( -)return «get_byte() « 8) I get_byte(»;

unsigned isdelim(char c) 1* returns true or false *1 (

)

int q=O; char cc; 1* write string("\n\rIsdelim II). l~te(c)·co(' ')·*1 for (;(cc-= peekb(bios cs(),&deltm l1st[q++]» 1= 6;) { --(* lbyte(cc)·cO(' ');*1 1f (cc == (c & 6xff» return(true);

}i return(false);

uns i gned get tokenC) { -

)

II this gets the next token from the line input buffer and puts it into the token buffer

I I It uses the buffer index and advances until end of data. /I It returns true iTa token was found and false if no token found

if «buffer[buffer index] == 0) II (bufter[buffer index] == cr» return(false); 1* move from butfer to token buffer *1 -for (token index=O; (isdelim(buffer[buffer index]) == false) && (buffer[buffer index] 1= 0) token buffer[token index++]=buffer[buffer index++]); -token~ffer[token-index] = 0; -1* put in end of string marker *1 last delim = buffer[buffer index]; buffer_index++; 1* advance~ffer index over delimiter *1 return (true);

1* ••••••••••••••••••••••••••••••••••••••••••••• *1

void syntax error(void) ( -write string(lI\n\rSyntax Error");

} -II Get Line Input is the normal i~t·tunction. It always terminates on a cr OR on the char II specified on the callers argo If the caller wants only a CR termi~tion, then he calls with CR 1/ as the argo

void get line input(term) /*---- get the input line ----*/ { --bufter index = 0; do -( it«inchar = ci(» == bspace) (

)

it (buffer index 1= 0) ( -buffer index--· co(bspice); I

co(' '); co(bspace) ; buffer[buffer index] = 0;

) -else 1* not a backspace *1 { 1* lower to upper case *1 if «inchar >= 'a') && (inchar <= 'z'» inchar A= Ox20; co(inchar); 1* echo character */ if«inchar 1= term) && (inchar 1= cr» 1* if a regular character */ ( buffer[buffer index] = inchar; buffer index++;

) -else 1* a cr or a term char *1 ( butfer[buffer index] = 0; buffer[bufter-index+1] = 0; it (inchar ==-cr) co(lf);

A-Ifpe BiosKit

Page 236: Atbios Kit Nov89

} )

}

while «inchar != term) && (inchar != cr»; buffer index = 0;

} -1*--- get the value specified by this token ---*1

unsigned get token value() ( --

}

char cc; unsigned token value; token value = 0; 1* pre-clear token value cell *1 token-index = 0; token-number = get token number(&register token list); if (token number == 0) I" it is a value, not a token -I ( 1* determine value *1 token index = 0; while-(token buffer[token index] != 0) ( - -cc = token buffer[token index]; if (ishex(cc) == true) -( if (isalpha(cc) == true) cc += 9; cc &= OxOf; 1* now it is a nibble *1 1* merge it into token *1 token value = (token value «4) Icc;

} - -token index++;

) -return(token value);

} -else

II if there is a token I, then get the value of that token

( return(reg saves[token number-1]);

) - -

1*---------------------------------------------------*I

The Vue File E·17 ·25

II search the specified token list against the token buffer and return the token number if a find -II no find - return token_number = 0

unsigned get_token_number(unsigned *token_listJltr) { unsigned token index,list index=O,token number=1; 1* points to current string being checkid *1 unsigned list item; unsigned item:index=Oi

while «list item = peek(bios cs(), &token list ntr[list index++]» != -1) {- - - ~ -for (token index = O,item index = O· «token buTfer[token index] 1= 0) i1 (peekb(bios cs(),list item+item index) != 0) && (token 6uffer[token Tndex] == peekb(bios cs(), lTst item+item index)}); 1* co(peekb(bios cs(),list item+list indix»,-I - -token_index++,item_index++}; -

II If they are both at the end of string, then they matched.

~f «token_buffer[token_index] == 0) && (peekb(bios_cs(),list_item+item_index) == 0»

1* ** write string("\n\rToken is II); lword(token_number); *1 -return(token number);

} -1* count the tokens *1 token number++; 1* -** write_string("\n\rToken I II); ** lword(token number), ** write strinij("\n\rLlst index II); ** lword(list lndeX); ** write string("\n\rList pointer II); ** lword(list_item); *1

). I~ co(peekb(bios cs(),list item+list index»; *1 - - -return(O);

Section E: The C ProlUams

Page 237: Atbios Kit Nov89

E·17·26 The Vue File

}

1*--------------------------------------------------*1

1* The sysbreak. routine is invoked by the CTRL-BREAK or CTRL-C keys and sets the break flag. ** This 1S checked by the CSTS routine to see if an operation should be aborted. It is linked ** upon entry to SysVue and de-linked upon exit. *1

void interrupt cdecl far sysbreakCinterrupt registers) ( -cstodsC); II do this because it is assumed that cs = ds setds system segmentC)· 1* alT varia5les will be referenced in sys seg *1 break flag = 1;

} -1* This function evaluates the arguments on the command line and gets the values associated with ** the args and places their values into the token_value array. ** The values are arranged: ** seg:off - seg:off - seg:off - seg:off ** The corresponding present bit is set in the 'present' char to indicate if a an arg was ** present for that value. -*1

get valuesO ( -unsigned i; 1* i is a local variable used for the index *1 1* clear tne token value array *1 for (i=O; i< 8;token value[i++] = 0)(· present = 0; i = 0; 1* write stringc"\n\rEntering get va ues II); *1 - -do (

}

ifCget tokenC) == true) /* there is a token - *1 ( -token value[i+1] = get token valueC); present 1= COx80 » (i+1»); -if (Clast delim == ':') II (last delim == 'I'» 1* the tOKen is a register token-*I (

} }

token value[i] = token value[i+1]; present 1= COx80 » i)l present &= -(Ox80 » (1+1»;; token value[i+1] = 0; ifCget token() == true) 1* there is a token - *1 ( -

}

token value[i+1] = get token valueC); present 1= COx80 » (i+1»; -

i += 2; } while (i < 8); 1* **wri te stringC"\n\rExi ting get values"); *1 - -

1* Value present looks at the present bit for token_values 0-7 and returns a true if the bit is ** set, indicating a value was entered *1

unsigned value-presentCindex) (

}

if «(present « index) & Ox80) 1= 0) return(true); return(false);

A-Type BiosKit

Page 238: Atbios Kit Nov89

SECTIONF

Odds and Ends

This section includes tips on loading a Test Bios into Static Ram by using Debug Batch files, and other assorted subjects.

Page 239: Atbios Kit Nov89
Page 240: Atbios Kit Nov89

Loading Test Ram F·l·l

ONE

Loading Bios Test Ram

The following example shows how a Static Ram Adapter card installed in a target system can be loaded with the Bios image to test the Bios without programming Eproms. This example assumes the target machine has 64 Kbytes of static Ram at segment 0000. Note that the Adapter uses static rather than dynamic Ram and that the Ram is located in the high memory map area, rather than in the System Ram area (0 - 640 K). The low Ram area is cleared when a Bios starts, so the Bios image must be outside the 0-640 K range. Dynamic Ram Refresh is re-initialized during the Bios Power-up, so Static Ram is required for the Test-Bios to remain intact.

Create a file named loadat.inp file (as shown below) to provide input to the debug program. It will be used to automate the copying of the Bios image from the DOS transient area to the static Ram location. Note that the transfer is done in 4000 byte portions, as the debug program treats the length argument (4000) as a signed integer. A value of 8000 would be unreliable. Following the copying commands, a Go command starts executing the Bios at its reset label. By inspecting the Bios.map file, the offset for the label reset may be verified.

nbios.bin I m cs:OOOO I 4000 dOOO:OOOO m cs:4000 I 4000 dOOO:4000 m cs:8000 I 4000 dOOO:8000 m cs:cOOO 14000 dOOO:cOOO g = dOOO:e05b

To perform this loading procedure, enter debug < loadat.inp

N ext, to avoid typing the full command debug < loadat.inp every time you want to load the Ram, create a file such as load.bat which contains the one line as shown below:

debug < loadat.inp

Now all that is required to perform the complete copy, load, and go procedure is to enter load and allow the batch file to invoke the process.

A sample schematic is included for a static ram adapter which you may wish to use as a design guideline in case you decide to construct your own adapter. This schematic shows the general philosophy you can use in your design. Fosco and Annabooks have not constructed an adapter from this schematic, but have used the same design approach in the past. The functions shown in the programmable logic device (16L8) can be duplicated with discrete logic, but a PAL approach is the

Page 241: Atbios Kit Nov89

F ·1·2 Loading Test Ram

simplest. PAL's are a specific family of programmable devices by MMI, and PAL is a registered trademark of MMI. An adapter of this type will also accommodate the Dallas Semiconducterbattery backed ram modules, so a non-volatile ram board can be configured.

A· Type BiosKit

Page 242: Atbios Kit Nov89

+ v

'({RITE PROTECT SWITCH

EQUATIONS. BWRI = WRI ... 511

1 OJ< RES.

RAMO / = ~ 1 C3 / ... A T 8/ * X ... 'of • A f 5/ ... A f 4 / RAM T I = A T C3 I * A f 8 I ... X * 'of .. A t 5 I ... At 4 R AM21 = At C31 ... At 81 ... X ... Y ... A t 5 ... At 41 R AM3 I = At 9 I ... A t a I ... X ... Y • A 15 • A 14

, c

R( I 'w'U

WRITE PROTECT RAM SELECTS

f6L8

8\tf~J

DENB/ = ROI ... RAMOI DATA ENABLE FOR DATA BUFFER ~ ROI ... RAMt I + ROI ... RAM21 + ROI ... RAM31 DEN U

I RAM31

RAM21 20 I

NOTES. QAMtL 20 I I

FOR SEGMENT 0000: X=A171 Y = At6

I_ ,..-....... __ ~~M~n""/~·~~(c '-I ~f ~~I~~~ 06

FOR S£GMENT £000 . X=A17 Y = A16/

28-P IN SOCKETS 'vi ILL ACCEPT 62256 RAM's DALLAS T 235 RAM's

o AT A LINES SHOULD 8E BUFFERED THROUGH A 245 IN ORDER TO DRIVE THE BUS.

ADORESS LINE BUFFER INO IS OPT ION AL

DECODER IS MMI t 6L8 PAL.

TH IS SCHEM AT IC IS FOR EX AMPLE ONLY.

:. 245 '-~~~:o+-I 05 .-~e-~~ 04 .-~~--:!~I -I 03 I--~~-O!~' -I 02 .-~!-:-~~~..... 0 t 1--....IoIUIQ~---' .... 1-1 DO

~ OE/' ~~:---~a-t AOO

~~:---"""'!--I AO t ~~!'--~-I A02 ~~_~ ..... AO! ~~~~~!--I A04 ~~i....-_.~ AOS -!!o'Q ~t._~4~ A06 -!!o'~_-!"3~ A07

~t; A08 ~4 ACC3

FOSCO &. ANN A80CJ<SM AJ<E NO REPRESENT AT ION AS TO THE CORRECTNESS OF THE EXAMPLE.

AtO ~~:---~~ ..... A IT ~~'!'--~..... At 2 ~~i....-~~ti..... At 3 __ ....... 4 ----41 A 14

B\YRJ II 'WEI

I

20 I I

-

BiosKit Static Ram Board FOSCO 28035 MOUNT A IN ME ACC'H' RC .AD ESCONO 100. CA. 92026 619+144-8086

Page 243: Atbios Kit Nov89
Page 244: Atbios Kit Nov89

The Indent Program F· 2·1

TWO

The Indent Program

The Indent program is used to indent the lines of a source file according to the nesting of the left and right bracket characters ({ and }) to ease the readability of the code. Some editors have built-in features to do this automatically for you, so this Indent program may not be needed. Hyou are using an ordinary editor, you will find this program useful.

/************************************************************************************************** * : Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

* Module Name: Indent * * Version: 1.01 * * Author:FOSCO * * Date: 10-10-89 * * Filename: Indent.c * * Functional Description: * This program is a utility which is used to indent C source code lines according to the nesting * level of the left and right bracket characters ( { } ). It improves readability of the souce * file, but does not affect the logic flow. It is useful when a general purpose editor is being : used to prepare source files.

* Ar~unents: * Flle name * Return: * * Version History: * 1.01 * Updated under QuickC 2 for convenience. * General clean-up and simplification. ***************************************************************************************************/

/* INC L U D E F I L E S */

#include <stdio.h>

/* G LOB A L V A R I A B L E S */

FILE *instream; FILE *outstream; unsi~ned int length,i,numread,numwritten, tab = 0; #deflne blen 512 unsi~ned char instring[blen],outstring[blen],buffer[16384l; #deflne true -1 #define false 0 unsigned write_ok = true;

/* L 0 CAL D E FIN I T ION S */

#define tabchar 9 #define rt brace 125 #def i ne l fcrace 123 #define inCIent_level 1 /* # of colums to indent */

/* PRO G RAM */

/* indent c programs according to {} characters */

main(int argc, char *argv[]) ( printf("FOSCO/Annabooks Indent Source Util ity V1.01\n\r"); if (argc <2) ( printf("Not enough argunents on COlllll8nd line\n"); exit(O); }

if «instream = fopen(argv[ll,lr"» == NULL) printf("Could not open file for reading\n");

else (

length = filelength(fileno(instream»;

Page 245: Atbios Kit Nov89

}

F • 2· 2 The Indent Program

if (length == -1) printf(1I8ad Length on input file\n"); else { if «outstream = fopen("Sid.SSS" "W"» == NULL)

printf("Could not open file for writing\n"); else (

}

tab=O· while'Cfgets(instring,blen,instream) f= 0) {

}

II skip over leading spaces i =0 • wh it e (i ns t ring [ i ++] == , ') • i - - • II check for right brace here so We de!indent the current line if «instrinv[i] == rt brace) && (tab >= indent level»

tab -= lndent_levil; -

/I pad front of output string with required # of spaces strnset(outstring,' ',tab);outstring[tab] = 0;

II now copy instring[i] to outstring[tab] strcat(&oUtstring[tab],&instring[i]);

II write to the temp file and mark any errors if(fputs(outstring,outstream) 1= 0) write ok = false;, /I check for left craces here so we indent the follOWIng line if (instring[i] == lf brace) ( -

}

tab += indent level; II check for closing brace on same line fore; i<strlen(instring)ii++) . { if «instring[i] == rt brace) && (tab >= indent_level» ( -tab -= indent level: break; -

) }

} fclose(instream)· fclose(outstream):

if(lwrite ok) ( -

}

printf(lI\n\rError in writing t~rary fi le, processing aborted. II); printfC"Original file Xs remains unchanged.\n\rU,argv[1]);

else { II now copy the Sid.SSS to the original file if «Cinstream = fopenC"Sid.SSS",lIr+bll» 1= NULL) && «outstream=fopenCargv[ll ,1Iw+bll » f= NULL» { do (

}

numread = freadCCchar *)buffer sizeofCchar) 16384,instream): numwritten = fwrite«char *)buJfer, sizeofCc~ar),numread,outstream); if (numwritten 1= numread) ( printf("Transfer error on fi le Xs. Use SID.SSS as recovery fi le./n",argv[1]); write ok = false;

} -whi le (nunread > 0); fclose(instream); fclose(outstream)i if(write ok)

iT«nunread = remove (IISid.SSS"» f= 0)

} }

}

printf("\n\rError deleting temp file SID.SSS\n\r"):

A· Type BiosKit

Page 246: Atbios Kit Nov89

The Uilite Program F ·3·1

THREE

The Hilite Program

The Hilite program is used to display program comments in intensified video on the display. It scans the source file and looks for pairs of comment delimiters ( /* and * / ), and intensifies the video between these marks. It is useful for detecting incorrect comment delimiter pairs, which may comment out wanted source code statements. When strange errors show up in the compilation of a 'slightly' edited program, comment delimiter errors may cause drastic errors. If a program compiles properly but pro~ram operation changes radically, a comment check with Hilite may help in determirung the cause(s).

/************************************************************************************************** * : Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

* Module Name: Hilite * * Version: 1.00 * * Author: FOSCO * * Date: 1-1-89 * * Filename: hilite.c * * Functional Description: * This program is used to hilite the comments in a C source program as it is displayed on * the screen. * * Arglnents: * Fi le name * Return: * * Version History: * ***************************************************************************************************/

/* INC L U D E F I L E S */

/* FUN C T ION PRO TOT Y PES */

/* G LOB A L V A R I A B L E S */

/* G LOB A L CON S TAN T S */

/* L 0 CAL D E FIN I T ION S */

/* L 0 CAL CON S TAN T S */

/* PRO G RAM */

/* highlight c programs according to / * * / characters */

#include <stdio.h> #include <dos.h> #include <ctype.h> #define cr 13 #define lf 10 #def i ne space 32 #define on 1 #def i ne off 0 #define star ,*, #define slash 47 #def i ne bspace 8;

FILE *instream; unsigned int length; unsigned int i; unsigned char commentlch~~ast char; unsigned char buffer[16304]; -union REGS regs;

main(argc,argv) int argc;

Page 247: Atbios Kit Nov89

F·3·2 The HiIite Program

char *argv [] ; {

)

if (argc <2) (

)

printf("Not enough parameters on conmand l ine\n"); exi t(O):

if «instream = fopen(argv[1] ,lIr+b"» == NULL) printf("Could not open file for reading\nll );

else (

length = filelength(fileno(instream»;

for (i=O; i<length && «ch = getc(instream» 1= EOF); i++) { if «last_char == slash) && (ch == star » ( comment = on; /* backspace and turn on last slash */

regs.h.ah = OxOe: regs.h.al = bspace: regs.h.bh = 0: int86(Ox10,&regs,&regs); regs.h.bl = OxOfi

regs.h.ah = Ox09i /* write attribute at cursor */ regs.h.al = Ox20: /* display without highlight */ regs.h.bh = OxOO· regs.x.cx = Ox0061: int86(Ox10,&regs,&regs):

regs.h.ah = OxOe· regs.h.al = slash: regs.h.bh = 0: int86(Ox10,&regs,&regs): regs.h.bl = OxOf:

} .

if (comment == on) { regs.h.bl = OxOf;

} else { regs.h.bl = Ox07:

} regs.h.ah = Ox09: /* write attribute at cursor */ regs.h.al = Ox20: /* display without highlight */ regs.h.bh = OxOO' regs.x.cx = Ox0061: if (isprint(ch» int86(Ox10,&regs,&regs):

regs.h.ah = OxOe: /* write tty */ regs.h.al = ch' regs.h.bh = Ox6o: int86(Ox10,&regs,&regs): if «last char == star) && (ch == slash » comment = off: last char-= chi

} -fclose(instream)i

}

A· Type BiosKit

Page 248: Atbios Kit Nov89

The Parens Program F ·4·1

FOUR

The Parens Program

The Parens program is used to display parenthesized text in intensified video on the display. It scans the source file and looks for parentheses characters and intensifies the video between these marks. It is useful for detecting incorrect parenthesizing.

/*************************************************************************************************** * * Copyright (c) FOSCO 1988, 1989 - All Rights Reserved * * Module Name: Parens * * Version: 1.00 * * Author: FOSCO * * Oate: 1-5-89 * : Fi lename: parens.c

* Functional Description: : This progam is used to display parenthesized text on the screen in itensified video.

* Ar~unents: * Flle name * * Return: * : Version History:

***************************************************************************************************/

/* INC L U D E F I L E S */

/* FUN C T ION PRO TOT Y PES */

/* G LOB A L V A R I A B L E S */

/* G LOB A L CON S TAN T S */

/* LaC A L D E FIN I T ION S */

/* LaC A L CON S TAN T S */

/* PRO G RAM */

/* highlight c programs according to () characters */

#include <stdio.h> #include <dos.h> #include <ctype.h> #define cr 13 #define l f 10 #def i ne space 32 #define on 1 #define off 0 #def i ne l paren 40 #def i ne rparen 41

FILE *instream; unsigned int length; uns i gned i nt i; unsigned char ch,depth: unsigned char buffer[163841; union REGS regs;

main(argc,argv) int argc; char *argv [] ; { if (argc <2) ( printf("Not enough parameters on conmand l ine\n"); exit(O);

) if «instream = fopen(argv[ll ,"r+b"» == NULL) printf("Could not open file for reading\n"); else .

Page 249: Atbios Kit Nov89

}

(

F ·4· 2 The Parens Program

length = filelength(fileno(instream»; depth = 0; for (i=O; i<length && «ch = getc(instream» 1= EOF); i++) { .

if (ch == lparen) depth++; if (depth 1= 0) { regs.h.bl = OxOf;

} else { regs.h.bl = Ox07;

} regs.h.ah = Ox09; /* write attribute at cursor */ regs.h.al = Ox20; /* display without highlight */ regs.h.bh = OxOO· . regs.x.ex = Ox0061; if (isprint(eh» int86(Ox10,&regs,&regs);

regs.h.ah = OxOe: /* write tty */ regs.h.al = eh

6•

regs.h.bh = Ox 0; int86(Ox10,&regs,&regs);

if (eh == rparen) depth--;

} fclose(instream);

}

A-Type BiosKit

Page 250: Atbios Kit Nov89

The Bin2Hex Filter F·5·1

FIVE

The Bin2Hex Filter

The Bin2Hex filter is used to convert a binary image file into Intel Hexadecimal Format. This is a common format used by many prom programmers such as Data I/O, etc. Since this is a filter, the output may be directed to a file, an output port, or the screen .

. *************************************************************************************************** , Copyright (c) FOSCO 1988, 1989 - All Rights Reserved

Module Name: Binary to Intel hexadecimal filter

Version: 1.00

Author: FOSCO

Date: 1-5-89

Filename: bin2hex.asm

Functional Description:

This program converts the contents of a file to Intel hexadecimal format. Since many Prom Progranmers wi II accept an Intel Hex download format( .BIN fi les may be converted. Fil ter outputs can be di rected as shown in the ex..., es below.

Argunents: bin2hex <infile.bin >outfile.hex bin2hex <infile.bin >COM1 bin2hex <infile.bin >CON

Return:

Version History: 1-5-89 - font revision

!*************************************************************************************************** , PRO G RAM

.model CQq)8ct

stack stack

segment word stack 'stack' ends

stdin stdout

equ equ

.data ibuff db obuff db line count dw char-count db checKsun db ochar db eof db

• code assl.llle

bin2hex proc mov mov mov

$$001 : mov mov mov mov int

JC $$EN1

o 1

16 dup(O) 32 dup(O) o o o o 13,10,':00000001FF'

ax,_data ds,ax l ine_count,O

bx,stdin cx,16 dx,offset ibuff ah,3fh 21n

get stdin

Page 251: Atbios Kit Nov89

F ·5·2 The Bin2hex Filter

or ax,ax JZ SSEN1

mov char count,al call write line

JMP SHORT SS001 .-$$EN1 :

call mov int

bin2hex endp

wri te_l ine proc mov mov xor mov call mov call mov call mov sub call mov mov sub call mov sub call mov sub call add mov

$$005: lodsb

write eof ax, 4cOOh 21"

checksl.ln,O cl,char count ch,ch -al,13 ~tc al,10 ~tc al,":" ~tc al,char cOUtt checksl.iii,al convert ax, line cOUtt al,ah -checksl.lll,al convert ax, line cOUtt checksl.iii,al convert al,OO checksl.lll,al convert line COU'1t ( 16 Si,offset 1buff

sub checksum,al call convert

LOOP $$OOS mov al , checksl.lll call convert ret

wri te_line endp

convert proc push ax push ax shr al, 1 shr al,1 shr al,1 shr al,1 and al,Ofh add al '0' clJ1) al: '9' JNA SSlF7

SSIF7: add al,7

call putc pop ax ana al,Ofh add al,'O' clJ1) al,'9' JNA SSIf9

S$IF9: add al,7

call putc pop ax ret

convert endp

putc proc push ax push bx push cx push dx mov ochar,al mov bx,stdout mov cx,1 mov dx,offset ochar mov ah~40h int 21 pop dx pop cx pop bx

A-JYpe BiosKit

done

write eof

return to dos

; carriage return

l fne feed

Page 252: Atbios Kit Nov89

The Bin2Hex Filter F ·5·3

pop ax ret

pute endp

write eof proc - push ax

push bx push ex push dx moy bx,stdout moy ex,13 moy dx,offset eof moy ah(,40h int 21 pop dx pop ex pop bx pop ax ret

wri te_eof endp

end bin2hex

Section F: Odds and Ends

Page 253: Atbios Kit Nov89
Page 254: Atbios Kit Nov89

The Split bin Program F ·6·1

SIX

The Splitbin Program

The Splitbin Program is used to Split the at.bin file into an at.evn and at.odd file for programming the two Proms normally needed for an AT Bios.

Some of the newer Chipsets used in AT clones may allow you to use a 64k x 8 prom for the complete Bios. These Chipsets are based on the idea that the Bios would be moved to Shadow Ram which usually operates with fewer wait states than Prom, allowing higher performance operation. This may provide you with a design advantage if you are designing your own CPU board. Check with the VISI chipset vendor for more information on this possible feature, and what additional software that might be required. IT your AT motherboard has this feature, then the Splitbin won't be needed.

The Splitbin command line argument is the filename without the extension ("at" not "at.bin"). Splitbin adds the ".bin" to the input filename argument and the ".evn" and ".odd" extensions to the output files.

/********.****.***.***** •• * •• *.* •••• * •••••••• * •••••• * •••••••••••••••••• • : Copyright (c) FOSCO 1989 - All Rights Reserved

: Module Name: Bin file splitter to even/odd

• Version: 1.00 * * Author: FOSCO • • Date: 10-1-89 * : Filename: Splitbin.c

* Language: MS C 5.1 * * Functional Description: * This program reads the .bin file specified by the argument, : and splits it into an .evn and a .odd file.

* * Version History: * ** ••••••• ** •••• * •••••• * ••••••••••••••••••••••••••••••••••••••••••••••• /

/. INC L U D E F I L E S ./

#include <stdio.h>

/. G LOB A L V A R I A B L E S ./

#define blen 8192 FILE ·instreamc*evenstream ·Oddstreami unsigned char lnbuffer[2·bten], evenbuffer[blen]J oddbuffer[blen]i unsigned char inname[16], oddn8me[16],evenname[1o]i unsigned numread,i,ji

/* PRO G RAM ./

unsigned main(int argc, char ·argv[]) ( printf("\n\rFOSCO/Amabooks Spl it xx.bin to xx.evn and xx.odd files Uti lity\n\r")i i f(argc == 2) ( strcpy(inname,argv[ll)i strcat(inname,".bin")i strcpy(evemame,argv[1])i strcat(evemame,".evn")i strcpy(oddname,argv[1])i strcat(oddname,".odd")i i f« instream = fopen( imame, "rb"» I = NULL)

Page 255: Atbios Kit Nov89

}

F·6·2 The Split bin Program

i f «evenst ream = fopenCevenname, "wb"» I = NULL) i f C ( odds t ream = fopenC oddname, "wb"» ! = NULL) {

whi leC

(

(numread = freadCCchar *)inbuffer,sizeof(char),2*blen,instream» != NULL)

for(i=O,j=Oi j < numread; i++,j+=2) ( evenbuffer[il = inbuffer[j1i oddbuffer[il = inbuffer[j+lli

) fwrite«char *)evenbuffer,sizeofCchar),numread/2,evenstream)i

, fwriteC(char *)oddbuffer,sizeofCchar),numread/2,Oddstream)i }

) } else { printfC"No .bin fi Le specified in conmand l ine\n\r")i

} returnCO)i

A-Type BiosKit

Page 256: Atbios Kit Nov89

The Mergebin Program F· 7·1

SEVEN

The Mergebin Program

The Mergebin Program is the companion to the Splitbin Program and may be ;used to combine ".evn" and ".odd" files to a ".bin" file. The command line argument,is the filename (without extension). Mergebin looks for the ".evn" and ".odd" files" ,and creates a ".bin" file. Mergebin is handy if you want to read existin~ Bios proms alld create a complete image, as well as providing a means to venfy the evenl99d conversion process (Splitbin) by merging a split and comparing results. , ';;, .. ' -.

. -: '~

1********************************************************************** * * Copyright (c) FOSCO 1989 - All Rights Reserved * * Module Name: Merge evn/odd files to a bin file * * Version: 1.00 * * Author: FOSCO * * Date: 10-1-89 * * Filename: Mergebin.c * * Language: MS C 5.1 * * Functional Description: : This program merges the .evn and .odd file into a combined .bin file.

* Version History: * **********************************************************************/

/* INC L U D E F I L E S */

#include <stdio.h>

1* G LOB A L V A R I A B L E S *1

#define blen 8192 FILE *outstream,*evenstream *Oddstreami unsigned char outbuffer[2*btenl, evenbuffer[blenl, oddbuffer[blenli unsigned char outname[16], oddname[161,evenname[161i unsigned numread,i,ji

1* PRO G RAM */

unsigned main(int argc, char *argv[]) ( printf("\n\rFOSCO/Annabooks Merge xx.evn and xx.odd to xx.bin fi les Uti l ity\n\rll)i if(argc == 2) (

}

st rcpy(outname, argv [1] ) ( strcat(outname, II. bi nil) i st rcpy(evemame, argv [1] J i strcat( evemame, ". evn") i strcpy(oddname,argv[1])i strcat(oddname,".odd")i if«outstream = f~(outname,lIwb"» 1= NULL) if«evenstream = fopen(evemame,"rb"» 1= NULL) if«Oddstream = fopen(oddname,llrb"» 1= NULL) (

}

whi lee «numread = fread«char *)evenbuffer,sizeof(char),blen,evenstream» 1= NULL) && «numread = fread«char *)oddbuffer,sizeof(char),Dlen,Oddstream» 1= NULL) ) ( for(i=O,j=Oi i < numreadi i++,j+=2) ( outbuffer[il = evenbuffer[i]i outbuffer[J+1] = oddbuffer[i]i

) fwrite«char *)out~ffer,sizeof(char),numread*2,outstream);

}

. ~' ~ . .

Page 257: Atbios Kit Nov89

}

F·'·2 The Mergebin Program

else { printf("No .bin file specified in conmand line\n\r")i

} return(O)i

A-Type BiosKit

Page 258: Atbios Kit Nov89

The Patch.asm File F ·8·1

EIGHT

The Patch.asm File

If you have a problem with the initial installation of the generic version of the AT BiosKit, this chapter may be of interest to you. Normally the generic Bios image "at.bin" that is supplied on the distribution diskette will run on almost all AT system boards, so that is where most readers start. If you are planning to make modifications of the BiosKit, read this chapter anyway, as it will give you some ideas on how to speed up checkout (also refer to the Chapter on "Loading Static Ram") by eliminating the Prom Erase/Program cycle for your Bios Under Test. The contents of the patch.asm program are a normal feature of the BiosKit, so the material in this Chapter may help you to appreciate the BiosKit methodology.

This patch procedure may be useful to you if you are modifying the standard AT Bioskit to you particular hardware configuration and you have access to a previously configured Bios from another source. Its purpose is to provide a method to sense the existence of a "test" copy of Bios in Ram, and transfer control to the "test" copy. This patch will permit control to the transferred before any significant checks or initialization is done by the other Bios.

This patch program was created during the early days of testing the AT Bios in static ram. We were using a system with "another" Bios chip, and loading and running the development Bios in Ram as described in Chapter F-l. The typical AT Bios has the restart routines locked into the se$ment at FOOO, because they do not check for rom­scan or secondary Bios until well Into the Bios. In order to wrest control away from the primary Bios residing at segment FOOO immediately upon a hardware reset signal, it was necessary to intercept the control flow at the very beginning of the code. To provide for this, the patch sequence in this file was created. It is intended to be loaded into a modified "other" Bios.

The typical Bios will have a reset control flow similar to the example shown below:

FOOO:FFFO Jmp Far FOOO:E05B

FOOO:E05B Jmp Near - reset_code

FOOO:reset_code Cll mov Out xxx xxx

al,8F 70,al

; disable interrupts ; disable NMI's ; write to CMOS ; and so on

The patch is intended to be patched in between the jump at FOOO:E05B and the reset_code, so it looks like the example shown below:

FOOO:FFFO Jmp Far FOOO:E05B

FOOO:E05B Jmp Near - patch

FOOO:patch ; patch program in this file ; checks for test Bios and

" ~~. . . f

Page 259: Atbios Kit Nov89

F ·8·2 The Patch.asm File

; transfers control if valid

Jmp reset_code

FOQQ:r~~t .. code CU mov Out xxx xxx

al,8F 70,al

; disable interrupts ; disable NMI's ; write to CMOS ; and so on

To install the patch, make a binary image copy of the "other" Bios using Debug. This can ;be done by the :following sequence:

Debug <enter> nother.bin <enter> rcs <enter> xxxx rcs xxyx < enter>

(call up debug) (name the file to be created) (examine the CS register) (displays current value) (xxyx = xxxx + 10)

m fOOO:OOOO I 4000 cs:OOOO < enter> m fOOO:4000 I 4000 cs:4000 < enter> m fOOO:8000 I 4000 cs:8000 < enter> m fOOO:.cOOO I 4000 cs:cOOO < enter>

rbx 1 < enter> rex 0 < enter> w cs:O < enter> q <enter>

(this copies the bios to ram) (this sets the length of the file)

(this writes the file on disk) (this exits debug)

Now that you have an image of the "other" bios on disk, you may reload it (using Debug), and find an unused area large enough to accommodate the patch program. When a space has been found, the patch program may be inserted by using the "asm" command and loadin~ the code. Replace the old jump at EOSB with a jump to the patch, and use that origtnal destination for the jump out of the patch.

After carefully checking that the patch is entered and linked correctly, use the "w" command to rewrite the file to disk.

The modified file will need its checksum corrected. The Biossum program may be used to calculate a new checksum. First though, you need to check the size of the bios. Remember, we wrote a full 64k file for the binary file. Reload it using debug and determine where code starts. If it is a typical assembly language version Bios, the code will start at location 8000. Fill the area from 0000 to 7FFF' with "FF" using the debug "fill" command. The Biossum program will skip over "fr bytes, until it finds a non-"fr byte and assume that checksumming should then begin. After you have performed this fill (if required), then calculate a new checksum with the following command:

Biossum other. bin < enter>

Finally, if two proms are required (even and odd bytes), run "Evenodd other" to produce the two binary images required. Program a set of modified proms (we

A· Type BiosKit : .. ,;.;.,,.;.,<>, .. >.:,-~' ~~~.:: ,"

Page 260: Atbios Kit Nov89

The Patch.asm File F ·8·3

strongly recommend you retain the original unaltered proms) and install and test them in you machine.

This modified bios will then adhere to the standard Annabooks conventions for secondary and test Bios', and you may proceed with developing arid testiof' yoUr personalized version of the AT BiosKit. ,

The patch file below is intended to provide you with' a guide to creating the patching code you will' need, not necessarily an executable .EXE file. By assembling file with a "MASM patch,,; <enter> " command, the listing file generated will illustrate the _, object cod~ required. The actual pat~hing is most easily don~ by usin~ ~e rt.~~1 ~}J, command In the DOS Debug as descnbed above. Therefore this module 'IS prov.tdedrI'~" for reference only. ' : ,.', "J:":'i}P~k

.******************************************************** , ~ Copyright (c) FOSCO 1988 - All Rights Reserved , ~ Module Name: Patch for "other" bios' for system checkout

; Version: 1.00 i ; Author: FOSCO i ; Date: 12-01-88

, Fi lename: patch.asm

Language MS MASM S. 1

Functional Description:

Th i s patch is intended to be patched into a non AnnabOoks Bios to allow the secondary bios feature to be used. The Annabooks Bios U'lder deve l ~t may then be loaded into and executed from High-Ram in the 0000 segment. The order of priority for selection is: 1. 0000 segment - test (usually Ram, may be Prom) 2. FOOO segment - primary (Prom)

; . . ; Verslon Hlstory:

~********************************************************** , .model • code

small

i----------- check for bios' patched in ----------If we find a Bios patch (by checking its signature), then we go to it.

patch a j~ at FOOO:EOSB to j~ to "patch"

patch: aX,OdOOOh i check seg dOOO ds ax si;si ; check for bios signature word ptr ds:[si],OSb1h

mov mov xor cJl1) jne check2 ; jumps if bad signature

_ithen check for length count byte ptr ds: [si+2] ~h .~,

check1:

Cq) jne xor xor

add inc loop or jne db dw dw

check2 ; j~ iJ bad length count cx, cx ; set 64k count al,al ; clear checksum register

al ,ds: [si] ; bui ld checksum for 641C bytes si check1 al,al check2 Oeah OfffOh OdOOOh

i zero = good i jumps i f bad checksum

; j~ to bios at dOOO , ... '.,;;., ....• " .. ~ .. r~' ..

'.

4 ":' • ~ .~'.: ~ ~> . ", " . i~ :'-

. ~ f':~'~ ~> ~~ }·:c,. . " ~-l: i rf~';"> 0 1,::;-!

.;" 'l ~. ;, t'~Y~, · .. ·f~

i"'k ",,' f' .. i. ~. L ' ; : \:~: .~": :.; ~~~f.!':' .' .f5·~J(i .~\~

.]) "..' • ~Jh-:;" ,~ "'}:)!Ib01Cc

,', ,','I; ;.' ;,.; Pf. ,,;:'(~':-'T' A Section F: Odds ;'alid'EndS

Page 261: Atbios Kit Nov89

F ·8·4 The. Patch.asm File

check2: 1234h jump to EOSB's original destination

; you RUSt determine this location I

end

p 'A-llJe BiosKit