CS444 Introduction to hw3: Multitasking Tiny UNIX Kernel

Oct 19, 2006, due Nov. 6

From hw3.txt:

Expand the Tiny-Unix kernel to provide multitasking for three tiny-Unix programs, programs which use only the system calls write (to TTY0/1 only) and exit.  Here, the console output port (COM2) is a shared device, shared between the three processes.  As in hw1 and hw2, use a small output buffer (6 char capacity) accessed via the queue package.  As in hw1 and hw2, allow writers to proceed when all of their string is at least in the buffer.  When the output buffer is full, make processes block in write, giving up the CPU for other processes to use.  No more spin loops in the kernel!

This is a producer-consumer situation, with 3 producers filling the output buffer and one consumer, the output interrupt handler, consuming the characters.  As in hw2, the output is interrupt-driven.

 

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

*

*       file:        proc.h

*                    Process structure info

*

*/

#ifndef PROC_H

#define PROC_H

 

/* number of processes: 3 user processes, 1 proc0 */

#define  NPROC 4

 

#define  N_SAVED_REGS 7

/* 7 non-scratch CPU registers, saved in this order: 

   here SAVED_ESP=0, SAVED_EBX=1, etc. */

enum cpu_regs {SAVED_ESP, SAVED_EBX, SAVED_ESI, SAVED_EDI,

               SAVED_EBP, SAVED_EFLAGS, SAVED_PC};

 

/* for p_status ( RUN=1, BLOCKED=2, ZOMBIE=3) */

typedef enum proc_status {RUN = 1, BLOCKED, ZOMBIE} ProcStatus;

 

/* for p_waitcode, what the process is waiting for */

typedef enum proc_wait {TTY0_OUTPUT = 1, TTY1_OUTPUT} WaitCode;

 

/* Process Entry */

typedef struct {

   int p_savedregs[N_SAVED_REGS]; /* saved non-scratch registers */

   ProcStatus p_status;   /* RUN, BLOCKED, or ZOMBIE */

   WaitCode p_waitcode;   /* valid only if status==BLOCKED: TTY0_OUT, etc. */

   int p_exitval;         /* valid only if status==ZOMBIE */

} PEntry;

 

/* extern these globals here, define them in tunix.c */

extern PEntry proctab[], *curproc;

 

#endif /*PROC_H */

 

 

# asmswtch.s:    switch CPU context for multitasking

# the job to do here:

# --save CPU registers in previous-process's PEntry

# --restore CPU registers from next-process's PEntry

# all this while running using the CPU to do it's own reconfiguration

 

.globl _asmswtch

 

# asmswtch--process switch

#  (but we don't need to save C scratch reg's, since they are assumed

#  to be smashed by calling this anyway)

#  Call from C: two arguments, pointers to old and new PEntry's:

#

#       asmswtch(oldpentryp, newpentryp)

 

#  Stack when reach here:

#  %esp-->  return pc

#  4(%esp)  oldpentryp

#  8(%esp)  newpentryp

 

#  PEntry:      saved esp

#               saved ebx

#               saved esi

#               saved edi

#               saved ebp

#               saved eflags

#               saved pc -- i.e., saved eip (where this was called from)

 

_asmswtch:

        movl 4(%esp),%eax     # oldpentryp

        movl %esp, (%eax)     # save %esp at start of PEntry

        movl %ebx, 4(%eax)    # followed by other non-scratch regs

        movl %esi, 8(%eax)

        movl %edi, 12(%eax)

        movl %ebp, 16(%eax)

        movl (%esp), %ecx

        movl %ecx, 24(%eax)   # save ret addr=top of stack

        pushfl                # push eflags on stack

        popl 20(%eax)         # pop into saved eflags

        movl 8(%esp), %eax    # newpentryp

        movl (%eax), %esp     # new stack pointer

        movl 4(%eax), %ebx    # restore from saved regs

        movl 8(%eax), %esi

        movl 12(%eax), %edi

        movl 16(%eax), %ebp

        pushl 20(%eax)        # new eflags--push on stack

        popfl                 # restore eflags

        movl 24(%eax), %ecx

        movl %ecx,(%esp)      # restore top of stack=saved pc

        ret                   # return on newly reinstated stack