CS444 Wed., Sept. 11

                Our Google group is set up, based on .forward email addresses

Thus after boot-up, the SAPC’s x86 CPU is running in 32-bit protected mode and in kernel mode.  32-bit protected mode means that we can use 32-bit addresses, addressing up to 4G locations.  16-bit mode would only allow 64K different addresses in one sequence, a terrible handicap for today’s programs.  Even our measly 3M user memory would constitute 0x30 = 48 different sequences of 64K (or 0x10000).  In 32-bit mode, an address of 0x300000 (3M) is just an ordinary address, in fact seen to be on the small side if you write all 32 bits out like this: 0x00300000.

 

Warning: many texts on Pentium architecture treat only the real mode architecture.  To tell, look at the register names in use.  AX = 16-bit register, whereas EAX = 32-bit register.  Similarly SP vs. ESP.  We can use AX in 32-bit mode, but we wouldn’t use it a lot (it’s just the lower 16 bits of EAX.)

 

 

Building and downloading programs for the SAPC

 

See www.cs.umb.edu/ulab for first steps--get the ulab module load into your .cshrc and build and run test.c.  Note that the ulab module adds environment variables to your UNIX process to make SAPC work easier.  $pcex is the examples directory path.  Try “echo $pcex” to check, “env | grep pc” to see more.

 

Note that we use a cross-compiler i386-gcc and other cross-tools—they run on Sparc but generate or work with x86 machine code.  The makefile in $pcex can build from any single C source xyz.c by “make C=xyc”.  This will make xyz.lnx, an SAPC executable stored in a UNIX file.

 

We can download a .lnx file by using mtip, a Sparc UNIX program usable on ulab.cs.umb.edu.  The reason it has to be ulab is that the serial lines to the 14 SAPCs are connected to ulab.  mtip finds a SAPC not in use already and assigns it to you, and then provides a conduit between your keyboard and monitor and the console of your SAPC.  It watches the characters as they go by, and if you type “~r”, it springs into action and arranges a reboot for you, or if you type “~d”, a download.

 

If you are logged in to ulab using ssh, the ~ character is used as a command escape for ssh, so you need to double up tildas to get them through, that is, type ~~r to reset the SAPC and ~~d to download.  Alternatively, use the <esc> character (new feature).

 

With the help of mtip, you will see the Tutor prompt “Tutor>” coming from your SAPC.  Tutor was listed above as SAPC software—it is running on the SAPC.

 

 

System setup for SAPCs

 

Each SAPC is (effectively) connected to the UNIX host “ulab” by a serial line from COM2 on the SAPC to (effectively) a serial port on ulab.  We call this the console line.  (Actually, there is a terminal concentrator involved.) When Tutor prints a prompt, those bytes are going out COM2 and are handled by the UNIX program “mtip” that we run on ulab.

 

mtip shuttles bytes back and forth between your stdin/stdout user i/o setup and the console line.  When you type a character during an mtip session, it goes via stdin to the mtip program, and from there out to COM2 of the connected SAPC.  If you type “~” or <esc>, the mtip escape character, mtip takes notice and then waits for the next character to see what to do, for example ~d (or <esc>d) for download.

 

Each SAPC numbered 5 or more has its COM1 separately connected to another serial port on ulab.  This connection is used by remote gdb to provide debugging.

 

When you type “~r” (or <esc>r) in mtip, the connected SAPC gets rebooted.  This works by first being interpreted by mtip, and then mtip runs another program that sends a command via a serial port on ulab to the “reset server”, a little machine that John Lentz built for this purpose.  It interprets the command and then generates a signal on a wire into the reset circuitry of the right SAPC, that is, a signal equivalent to pressing the reset button on the SAPC box.

 

 

Intro to hw1—

Problem 1—warmup for 2.  Just duplicate a given remgdb session –due Sun, Sept.  22

Rest due following Oct 1--

Problem 2--finishing an i/o library for the SAPC.

Problem 3—designing an extension of the i/o library to handle LPT1

 

 

Main part of hw1--finishing an i/o library for the SAPC.

 

As a library, it implements certain useful functions for apps.  Its API is in io_public.h:

void ioinit(void);

int read(int dev, char *buf, int nchar);

int write(int dev, char *buf, int nchar);

also “control”

 

Read and write look very much like the same-named UNIX system calls, except for “dev” instead of “fd”.  The dev parameter is the device number, for the io library. Here dev can be TTY0 (value 0, standing for COM1) or TTY1 (value 1, standing for COM2).  See tty_public.h for the following:

 

#define TTY0 0

#define TTY1 1

 

Look at the API again.  This can be called a “device-independent” i/o library because the interface is generic, not specific to any particular device.  The actual device in use can be determined at runtime, for example, by asking the user for a device number.

 

Recall from CS341 that the SAPC device numbers COM1 (value 1) and COM2 (value 2) are in a system of numbers set up in $pcinc/sysapi.h, which is included from $pcinc/stdio.h, and thus is in effect in any program with “#include <stdio.h>” or equivalent.  In hw1, we’ll use TTY0 and TTY1 instead, following the UNIX convention to number devices from 0.

 

Serial lines for SAPC

 

SAPC library name                       cs444 i/o library name           use

COM1 = 1 in $pcinc/stdio.h

TTY0 = 0 in tty_public.h

Remote gdb protocol

COM2 = 2 in $pcinc/stdio.h

TTY1 = 1 in tty_public.h

Console i/o via mtip

 

 

Note: you should have the environment variable pcinc defined for you by the ulab module, so if you can run mtip, you can also use $pcinc, for example by doing "cd $pcinc"  or "ls $pcinc" or "more $pcinc/stdio.h".  To see what it stands for, do "echo $pcinc".  It's just a directory in the UNIX filesystem.  Similarly $pcex stands for the file path to the SAPC examples directory.

 

In our programs, we put “#include <stdio.h>” and somehow end up using $pcinc/stdio.h. How does this work? 

Answer: gcc is given a flag –Idirectory that tells it where to look for header files.  See the makefile.

 

 

 

Here is part of the provided test program testio.c, to show that it calls into the library using the API quoted above.

 

    testio.c:

                     /* make ldev = TTY1 */

        ioinit();  /* Initialize devices */

 

        kprintf("\nTrying simple write...\n");

        got = write(ldev,"hi!\n",4);   /* here ldev = TTY1, i.e. COM2, the console line for an SAPC */

       

 

testio.c is the test program calling through the API.  After making sure it’s talking to the user over a serial line, device ldev, it does ioinit() and then write(ldev, “hi!\n”, 4) as a first test.  As delivered, output works but without using interrupts.  Your job is to reimplement it with interrupts.

 

In "write(ldev, buf, nchar)", seen in testio.c, ldev is TTY0 or TTY1. These numbers are defined in the header file tty_public.h provided with the hw1 project files.  These device numbers are special to hw1, hw2, etc.

 

kprintf. Note the use of kprintf instead of printf in testio.c and elsewhere. kprintf (for kernel printf, currently called printk in Linux sources) first turns off all interrupts then executes printf with the same arguments as it was called with, and then restores interrupts to their previous state.  This means that if execution reaches the kprintf code it will definitely print out the message, even if interrupts are enabled in the program.  That is a great help for debugging, since it’s important to know where execution is in the code. So be sure to use kprintf instead of printf for debugging hw1 code.

 

 

The edits you need to make for hw1 are all in tty.c, in ttyread and ttywrite and the interrupt handler.  A call to read ends up at ttyread and a call to write at ttywrite.  I’ll let you trace out how this happens.  Look at io.c and ioconf.c.  This shows how device independent i/o systems work—the device number specifies which device-specific function to actually execute.  Here the device-specific functions are ttyread and ttywrite, and the bundle of tty-functions in tty.c is called the tty driver, or serial port driver.

 

SAPC Support Library

Uses device numbers: COM1, COM2, CONSOLE, etc., #define’d via stdio.h for SAPC

#include <stdio.h>    includes special stdio.h for SAPC, in $pcinc.  

 

In the SAPC library, also arranged for access in the makefile:

  1. Standard C library calls, also available on UNIX, Windows, no modification:  printf, scanf, getchar, putchar, strcpy, strcmp, …
  2. C library calls, with device numbers instead of FILE *’s:  fprintf, fgets, …
  3. Special SAPC functions: sys_get_console_dev(), other sys_ functions, kprintf for debugging

 

Note that kprintf and some other functions in the SAPC library are utilizing the fact that our SAPC code is running in kernel mode, not user mode as is normal for C applications.  In user mode, we cannot turn off the interrupt system, as is done in kprintf!

 

C “Objects”, a quick intro/review.

 

Here the Queue ADT in C is provided in the queue subdirectory, along with a unit test testqueue.c.  queue.h defines the Queue API and the Queue type.

 

You know how to do objects in Java, what about in C?  Recall the Chip object in CS341.  Also the Cmd object for tutor.

 

Example: Rectangle objects

 

struct rect {

     int x1, y1, x2, y2;

};

struct rect *recp;

 

recp->x1 = 10;

 

Watch out!, there’s no (validly-allocated) memory pointed to by recp!  This is a garbage pointer, a pointer that points nowhere good.  Using it usually causes segmentation violations on UNIX and similar exceptions on Windows.  But on SAPC, all user memory is writable, so it may quietly work to damage some memory.

 

Normally under UNIX or Windows, we could malloc space for the Rectangle, but we have no malloc in the SAPC library.  Anyway, malloc is quite expensive in CPU, and we can easily avoid using it.  Just set up whole objects like this:

 

struct rect rect;

 

Now we can put

 

rect.x1 = 10;

 

      As a Java programmer, you’re used to “Rectangle rect;” meaning rect is a ref to a Rectangle, but in C, rect is the whole object, more like int x; in C or Java.

            To make a rectangle pointer, we have to use * in the type: “struct rect *rp;” defines rp to be a struct rect pointer.