Jump to content

SMPV211 - Appendix A: Difference between revisions

From EDM2
Created page with "The following is the source code for an actual PSD."
 
No edit summary
Line 1: Line 1:
The following is the source code for an actual PSD.
The following is the source code for an actual PSD.
==Main program==
<PRE>
#define INCL_ERROR_H
#include <os2.h>
#include <psd.h>
#include <alr.h>
extern ulong_t RMP2Available(void);
/*
*  Global Variables
*/
P_F_2  router = 0;
char  *pParmString = 0;
int    IODelayCount = 30;
PLMA  *pPSDPLMA = 0;
ulong_t sizePLMA = 0;
/***  Disable - Disable interrupts
*
*    This function disables interrupts, and returns
*    the original state of eflags
*
*    ENTRY  None
*
*    EXIT    EFLAGS
*
*/
ulong_t Disable(void) {
  ulong_t eflags;
  _asm {
      pushfd
      pop  eax
      mov  eflags,eax
      cli
  };
  return (eflags);
}
/***  Enable - Restore the state of eflags
*
*    This function restores the state of eflags
*
*    ENTRY  eflags - state of eflags to restore
*
*    EXIT    None
*
*/
void Enable(ulong_t eflags) {
  _asm {
      push  eflags
      popfd
  };
  return;
}
/***  InByte - Read a byte from a port
  *
  *    This function reads a byte from a specified port
  *
  *    ENTRY  port - port number to read from
  *
  *    EXIT    data read
  *
  */
ulong_t InByte(ulong_t port) {
    ulong_t data;
    _asm {
      mov  dx,port
      in    al,dx
      movzx eax,al
      mov  data,eax
    };
    return (data);
}
/***  OutByte - Writes a byte to a port
*
*    This function writes a byte to a specified port
*
*    ENTRY  port - port number to read from
*            data - data to write
*
*    EXIT    None
*
*/
void OutByte(ulong_t port, ulong_t data) {
  _asm {
      mov  dx,port
      mov  al,byte ptr data
      out  dx,al
  };
  return;
}
/***  SendEOI - Send an end of interrupt
*
*    This function sends an end of interrupt.
*
*    ENTRY  irq - irq level to end
*
*    EXIT    None
*
*/
ulong_t SendEOI(ulong_t irq) {
  ulong_t flags;
  flags = Disable();
  if (irq < NUM_IRQ_PER_PIC)
      OutByte(PIC1_PORT0, OCW2_NON_SPECIFIC_EOI);
  else {
      OutByte(PIC2_PORT0, OCW2_NON_SPECIFIC_EOI);
      IODelay;
      OutByte(PIC1_PORT0, OCW2_NON_SPECIFIC_EOI);
  }
  Enable(flags);
}
/***  WHO_AM_I - Returns the current processor number
*
*    This function returns the current processor number
*
*    ENTRY  NONE
*
*    EXIT    Current processor number (P1 or P2)
*
*/
ulong_t WHO_AM_I (void) {
  return(InByte(WHO_AM_I_PORT));
}
/***  IPIPresent - Detects the presence of an IPI
*
*    This function detects the presence of an IPI on the current
*    processor
*
*    ENTRY  None
*
*    EXIT    NO_ERROR - IPI present
*            -1      - IPI not present
*
*/
ulong_t IPIPresent (void) {
  ulong_t rc = 0;
  struct control_s ctrl;
  ulong_t port;
  port = pPSDPLMA->controlport;
  ctrl.b_all = InByte(port);
  if (ctrl.b_387err)
  {
      OutByte (0xf0, 0); // The busy latch for NPX must be cleared.
                        // When we call the interrupt handler
                        // (w/ Call16bitDD int.asm), ints. are 1st enabled.
                        // If the busy latch is not cleared, then we
                        // will take this interrupt in again and will
                        // eventually nest until the interrupt stack is
                        // overrun.
      rc = -1;
  }
  return (rc);
}
/***  Install - Install PSD
*
*    This function checks to see if this PSD is installable on the
*    current platform.
*
*    ENTRY  pinstall - pointer to an INSTALL structure
*
*    EXIT    NO_ERROR - PSD Installed
*            -1      - PSD not valid for this platform
*
*/
ulong_t Install(INSTALL *pinstall) {
  VMALLOC vmac;
  int i;
  char *p;
  ulong_t rc = 0;
  char ALR_String =  "PROVEISA";
// _asm int 3;
  /* Setup Global variables */
  router = pinstall->pPSDHlpRouter;
  pParmString = pinstall->pParmString;
  pPSDPLMA = (void *)pinstall->pPSDPLMA;
  sizePLMA = pinstall->sizePLMA;
  vmac.addr = BIOS_SEG << 4;
  vmac.cbsize = _64K;
  vmac.flags = VMALLOC_PHYS;
  /* Map BIOS area */
  if ((rc = PSDHelp(router, PSDHLP_VMALLOC, &vmac)) == NO_ERROR) {
      /* Check for ALR string */
      p = (char *)vmac.addr + ALR_STRING_OFFSET;
      for (i = 0; ALR_String i != '\0'; i++)
        if (p i  != ALR_String i) {
            rc = -1;
            break;
        }
      /* Free BIOS mapping */
      PSDHelp(router, PSDHLP_VMFREE, vmac.addr);
  }
  return (rc);
}
/***  DeInstall - DeInstall PSD
*
*    This function deinstalls the PSD.
*
*    ENTRY  None
*
*    EXIT    NO_ERROR
*
*/
ulong_t DeInstall(void) {
  return (NO_ERROR);
}
/***  Init - Initialize the PSD
*
*    This function initializes the PSD.
*
*    ENTRY  None
*
*    EXIT    NO_ERROR - PSD initialized
*            -1      - PSD not initialized
*
*/
ulong_t Init(INIT *pinit) {
  struct control_s ctrl;
  SET_IRQ set_irq;
  /* Initialize P1 control port */
  ctrl.b_all = 0;
  ctrl.b_cacheon = 1;
  OutByte(P1_PROCESSOR_CONTROL_PORT, ctrl.b_all);
  /* Setup P2 interrupt vector */
  OutByte(P2_INTERRUPT_VECTOR_CONTROL_PORT, IPI_VECTOR);
  /* Setup IPI info */
  set_irq.irq = 13;
  set_irq.flags = IRQf_IPI;
  set_irq.vector = 0;
  set_irq.handler = (P_F_2)IPIPresent;
  PSDHelp(router, PSDHLP_SET_IRQ, &set_irq);
  /* Fill init structure */
  pinit->flags = INIT_EOI_IRQ13_ON_CPU0;          //76422
  pinit->version = VERSION;
  return (NO_ERROR);
}
/***  ProcInit - Processor initialization
*
*    This function initializes per processor items.
*
*    NOTE: This function is called once on each processor
*          in the system.
*
*    ENTRY  None
*
*    EXIT    NO_ERROR - Processor initialized
*            -1      - Processor not initialized
*
*/
ulong_t ProcInit(void) {
  if (WHO_AM_I() == P1) {
      pPSDPLMA->procnum = 0;
      pPSDPLMA->controlport = P1_PROCESSOR_CONTROL_PORT;
  }
  else {
      pPSDPLMA->procnum = 1;
      pPSDPLMA->controlport = P2_PROCESSOR_CONTROL_PORT;
  }
  return (NO_ERROR);
}
/***  StartProcessor - Start a processor
*
*    This function starts a processor.
*
*    ENTRY  procnum - processor number to start (0-based)
*
*    EXIT    Return Code
*
*/
ulong_t StartProcessor(ulong_t procnum) {
  CALL_REAL_MODE rm;
  struct control_s ctrl;
  ulong_t rc = -1;
  if (procnum == 1) {
      rm.function = (ulong_t)&RMP2Available;
      rm.pdata = 0;
      rc = PSDHelp(router, PSDHLP_CALL_REAL_MODE, &rm);
      if (rc & P2_AVAILABLE) {
        /* Dispatch P2 */
        ctrl.b_all = 0;
        ctrl.b_cacheon = 1;
        OutByte(P2_PROCESSOR_CONTROL_PORT, ctrl.b_all);
        rc = NO_ERROR;
      }
      else
        rc = -1;
  }
  return (rc);
}
/***  GetNumOfProcs - Get number of processors
*
*    This function gets the number of processors which exist on this
*    platform.
*
*    ENTRY  None
*
*    EXIT    Number of processors
*
*/
ulong_t GetNumOfProcs(void) {
  ulong_t cprocs = 2;
  return (cprocs);
}
/***  GenIPI - Generate an inter-processor interrupt
*
*    This function generates an IPI.
*
*    ENTRY  procnum - processor number to interrupt (0-based)
*
*    EXIT    NO_ERROR
*
*/
ulong_t GenIPI(ulong_t procnum) {
  struct control_s ctrl;
  ulong_t port;
  if (procnum == 0)
      port = P1_PROCESSOR_CONTROL_PORT;
  else
      port = P2_PROCESSOR_CONTROL_PORT;
  ctrl.b_all = InByte(port);
  ctrl.b_pint = 1;
  OutByte(port, ctrl.b_all);
  return (NO_ERROR);
}
/***  EndIPI - End an inter-processor interrupt
*
*    This function ends an IPI.
*
*    ENTRY  procnum - processor number to end interrupt on (0-based)
*
*    EXIT    NO_ERROR
*
*/
ulong_t EndIPI(ulong_t procnum) {
  struct control_s ctrl;
  ulong_t port;
  if (procnum == 0)
      port = P1_PROCESSOR_CONTROL_PORT;
  else
      port = P2_PROCESSOR_CONTROL_PORT;
  ctrl.b_all = InByte(port);
  ctrl.b_pint = 0;
  OutByte(port, ctrl.b_all);
  if (procnum == 0)
      SendEOI(IPI_IRQ);
  return (NO_ERROR);
}
</PRE>
==Entry stub==
<PRE>
.386
_TEXT SEGMENT
ASSUME CS:_TEXT,DS:NOTHING
      PUBLIC  _RMP2Available
_RMP2Available PROC
      mov  ah,0E2h
      mov  al,0
      int  15h
      movzx eax,ax
      retf
_RMP2Available ENDP
_TEXT ENDS
END
</PRE>
==PSD.H==
<PRE>
/*static char *SCCSID = "@(#)psd.h 1.0 93/18/08";*/
// XLATOFF
#ifndef ulong_t
typedef unsigned long  ulong_t;
typedef unsigned short  ushort_t;
typedef unsigned char  uchar_t;
#endif
typedef int (*P_F_1)(ulong_t arg);
typedef int (*P_F_2)(ulong_t arg1, ulong_t arg2);
#define PSDHelp(router, function, arg) \
  ((*router)((function), (ulong_t)(arg)))
// XLATON
/* ASM
P_F_1 struc
dd ?
P_F_1 ends
P_F_2 struc
dd ?
P_F_2 ends
*/
#define WARM_REBOOT_VECTOR_SEG  0x40
#define WARM_REBOOT_VECTOR_OFF  0x67
/* PSD Info structure */
typedef struct info_s {                    /* psd */
  ulong_t  flags;                          /* PSD flags */
  ulong_t  version;                        /* PSD version */
  ulong_t  hmte;                          /* MTE handle of PSD */
  uchar_t *pParmString;                    /* Pointer to ASCIIZ PSD parameter*/
  ulong_t  IRQ_IPI;                        /* IRQ for IPI */
  ulong_t  IRQ_LSI;                        /* IRQ for LSI */
  ulong_t  IRQ_SPI;                        /* IRQ for SPI */
} PSDINFO;
/* PSD flags definition */
#define PSD_ADV_INT_MODE        0x20000000  /* PSD is in adv int mode #81531 */
#define PSD_INSTALLED          0x40000000  /* PSD has been installed */
#define PSD_INITIALIZED        0x80000000  /* PSD has been initialized */
/* PSD function numbers-structures */
#define PSD_INSTALL            0x00000000  /* Install PSD */
typedef struct install_s {                  /* install */
  P_F_2  pPSDHlpRouter;                  /* Address of PSDHlpRouter */
  char  *pParmString;                    /* Pointer to parameter string */
  void  *pPSDPLMA;                        /* Pointer to PSD's PLMA */
  ulong_t sizePLMA;                        /* Size of PLMA in bytes */
} INSTALL;
#define PSD_DEINSTALL          0x00000001  /* DeInstall PSD */
#define PSD_INIT                0x00000002  /* Initialize PSD */
typedef struct init_s {                    /* init */
  ulong_t flags;                          /* Init flags */
  ulong_t version;                        /* PSD Version number */
} INIT;
#define INIT_GLOBAL_IRQ_ACCESS  0x00000001  /* Platform has global IRQ access */
#define INIT_USE_FPERR_TRAP    0x00000002  /* Use Trap 16 to report FP err's */
#define INIT_EOI_IRQ13_ON_CPU0  0x00000004  /* eoi IRQ 13 only if on cpu 0    */
#define INIT_TIMER_CPU0        0x00000008  /* system timer is on CPU 0      */
#define PSD_PROC_INIT          0x00000003  /* Initialize processor */
#define PSD_START_PROC          0x00000004  /* Start processor */
#define PSD_GET_NUM_OF_PROCS    0x00000005  /* Get number of processors */
#define PSD_GEN_IPI            0x00000006  /* Generate an IPI */
#define PSD_END_IPI            0x00000007  /* End an IPI */
#define PSD_PORT_IO            0x00000008  /* Port I/O */
typedef struct port_io_s {                  /* port_io */
  ulong_t port;                            /* Port number to access */
  ulong_t data;                            /* Data read, or data to write */
  ulong_t flags;                          /* IO Flags */
} PORT_IO;
#define IO_READ_BYTE    0x0000              /* Read a byte from the port */
#define IO_READ_WORD    0x0001              /* Read a word from the port */
#define IO_READ_DWORD  0x0002              /* Read a dword from the port */
#define IO_WRITE_BYTE  0x0003              /* Write a byte to the port */
#define IO_WRITE_WORD  0x0004              /* Write a word to the port */
#define IO_WRITE_DWORD  0x0005              /* Write a dword to the port */
#define IO_FLAGMASK    0x0007              /* Flag mask */
#define PSD_IRQ_MASK            0x00000009  /* Mask/Unmask IRQ levels */
typedef struct psd_irq_s {                  /* psd_irq */
  ulong_t flags;                          /* IRQ flags */
  ulong_t data;                            /* IRQ data */
                                            /*  depending on type of irq */
                                            /*  operation, the data field */
                                            /*  can contain any of the */
                                            /*  following info: */
                                            /*  1) Mask or UNMasking data */
                                            /*  2) IRR or ISR reg values */
                                            /*  3) IRQ # for EOI operations */
  ulong_t procnum;                        /* Processor number */
} PSD_IRQ;
#define PSD_IRQ_REG            0x0000000A  /* Access IRQ related regs */
#define PSD_IRQ_EOI            0x0000000B  /* Issue an EOI */
#define IRQ_MASK                0x00000001  /* Turn on IRQ mask bits */
#define IRQ_UNMASK              0x00000002  /* Turn off IRQ mask bits */
#define IRQ_GETMASK            0x00000004  /* Get IRQ mask bits */
#define IRQ_NEWMASK            0x00000010  /* Set and/or Reset all masks */
#define IRQ_READ_IRR            0x00000100  /* Read the IRR reg */
#define IRQ_READ_ISR            0x00000200  /* Read the ISR reg */
#define PSD_APP_COMM            0x0000000C  /* PSD/APP Communication */
#define PSD_SET_ADV_INT_MODE    0x0000000D  /* Set advanced int mode */
#define PSD_SET_PROC_STATE      0x0000000E  /* Set proc state; idle, or busy */
#define PROC_STATE_IDLE        0x00000000  /* Processor is idle */
#define PROC_STATE_BUSY        0x00000001  /* Processor is busy */
#define PSD_QUERY_SYSTEM_TIMER  0x0000000F  /* Query Value of System Timer 0 */
typedef struct psd_qrytmr_s {              /* psd_qrytmr */
  ulong_t qw_ulLo_psd;                    /* Timer count */
  ulong_t qw_ulHi_psd;                    /* Timer count */
  ulong_t pqwTmr;                          /* 16:16 ptr to qwTmr */
} PSD_QRYTMR;
#define PSD_SET_SYSTEM_TIMER    0x00000010  /* Set System Timer 0 counter    */
typedef struct psd_settmr_s {              /* psd_settmr */
  ulong_t NewRollOver;                    /* NewRollover*/
  ulong_t pqwTmrRollover;                  /* 16:16 ptr to qwTmrRollover */
} PSD_SETTMR;
/* PSD helper function numbers-structures */
#define PSDHLP_VMALLOC          0x00000000  /* Allocate memory */
typedef struct vmalloc_s {                  /* vmalloc */
  ulong_t addr;                            /* Physical address to map */
                                            /*  if VMALLOC_PHYS */
                                            /* Lin addr to alloc at */
                                            /*  if VMALLOC_LOCSPECIFIC */
                                            /* on return, addr of allocation */
  ulong_t cbsize;                          /* Size of mapping in bytes */
  ulong_t flags;                          /* Allocation flags */
} VMALLOC;
#define VMALLOC_FIXED          0x00000001  /* Allocate resident memory */
#define VMALLOC_CONTIG          0x00000002  /* Allocate contiguous memory */
#define VMALLOC_LOCSPECIFIC    0x00000004  /* Alloc at a specific lin address */
#define VMALLOC_PHYS            0x00000008  /* Map physical address */
#define VMALLOC_1M              0x00000010  /* Allocate below 1M */
#define VMALLOC_FLAGMASK        0x0000001f  /* Valid flag mask */
#define PSDHLP_VMFREE          0x00000001  /* Free memory */
#define PSDHLP_SET_IRQ          0x00000002  /* Set up an IRQ */
typedef struct set_irq_s {                  /* set_irq */
  ushort_t irq;                            /* IRQ level */
  ushort_t flags;                          /* Set IRQ flags */
  ulong_t  vector;                        /* IRQ interrupt vector */
  P_F_2    handler;                        /* IRQ handler */
} SET_IRQ;
#define IRQf_IPI  0x0020                    /* IRQ for IPI */
#define IRQf_LSI  0x0040                    /* IRQ for LSI */
#define IRQf_SPI  0x0080                    /* IRQ for SPI */
#define PSDHLP_CALL_REAL_MODE  0x00000003  /* Call a function in real mode */
typedef struct call_real_mode_s {          /* call_real_mode */
  ulong_t function;                        /* Function address */
  ulong_t pdata;                          /* Pointer to data area */
} CALL_REAL_MODE;
#define PSDHLP_VMLINTOPHYS      0x00000004  /* Convert linear addr to phys */
#define PSDHLP_ADJ_PG_RANGES    0x00000005  /* Adjust page ranges */
typedef struct _pagerange_s {              /* pagerange */
  ulong_t lastframe;                      /* Last valid page in range */
  ulong_t firstframe;                      /* First valid page in range */
};
typedef struct adj_pg_ranges_s{            /* adj_pg_ranges */
  struct _pagerange_s *pprt;              /* Pointer to page range table */
  ulong_t nranges;                        /* Num of ranges in range table */
} ADJ_PG_RANGES;
/* PSD function prototypes */
extern void PSDEnter (ulong_t function, ulong_t arg, P_F_2 altEntry);
</PRE>
==Specific header==
<PRE>
/*
* Miscellaneous
*/
#define VERSION  0x00000010
#define _64K      (64 * 1024)
#define BIOS_SEG            0xF000
#define ALR_STRING_OFFSET  0xEC47
#define P2_AVAILABLE        0x00008000
/*
* PLMA structure
*/
typedef struct plma_s {
  ulong_t procnum;      /* Current processor number (0-based) */
  ulong_t controlport;  /* Control port for current processor */
} PLMA;
/*
* Generate delay between I/O instructions
*/
#define IODelay {int i; for(i = 0; i < IODelayCount; i++); }
/*
* IPI info
*/
#define IPI_IRQ    0x0d      /* IRQ level for IPI */
#define IPI_VECTOR  0x75      /* Vector number for IPI */
/*
* PIC Info
*/
#define NUM_IRQ_PER_PIC        0x08
#define OCW2_NON_SPECIFIC_EOI  0x20
#define PIC1_PORT0              0x20
#define PIC1_PORT1              0x21
#define PIC2_PORT0              0xA0
#define PIC2_PORT1              0xA1
/*
* The contents of the WHO_AM_I port (read-only) can be used
* by code to determine which processor we are currently on
*/
#define WHO_AM_I_PORT  0xC70
#define P1            0x00
#define P2            0xF0
/*
* The processor control port contains the bits used to control
* various functions of the associated processor
*/
#define P1_PROCESSOR_CONTROL_PORT  0x0C6A
#define P2_PROCESSOR_CONTROL_PORT  0xFC6A
struct _b_control_s {
  ulong_t _reset:1,      /* RESET - (Not implemented for P1) */
                          /*  1 = Resets processor */
          _387pres:1,    /* 387PRES - (Read only) */
                          /*  0 = 80387 is not installed */
                          /*  1 = 80387 is installed */
          _cacheon:1,    /* CACHEON - (Not implemented for P1) */
                          /*  0 = Disables cache */
                          /*  1 = Enables cache */
          _mbusaccess:1, /* M Bus Access (Not implemented for P1) */
                          /*  0 = Allows the processor to gain */
                          /*      control of the memory bus */
                          /*  1 = Prohibits the processor from gaining */
                          /*      access to the memory bus. The */
                          /*      processor can execute instructions */
                          /*      from its cache; however, cache read */
                          /*      misses, I/O, and writes cause the */
                          /*      processor to cease executing */
                          /*      instructions until the bit becomes */
                          /*      a "0" */
          _flush:1,      /* FLUSH */
                          /*  Writing a "1" to this bit followed by a "0" */
                          /*  causes invalidation of all cache address */
                          /*  information */
          _387err:1,    /* 387ERR */
                          /*  0 = No 80387 error */
                          /*  0 = An 80387 error has occurred. This bit */
                          /*      must be cleared by software */
          _pint:1,      /* PINT */
                          /*  A low-to-high transition of this bit causes */
                          /*  an interrupt. This bit must be cleared by  */
                          /*  software, preferably by the interrupt service */
                          /*  routine. On P2, the value stored in FC68h */
                          /*  contains the interrupt number. P1 is always */
                          /*  interrupted with IRQ13 */
          _intdis:1,    /* INTDIS */
                          /*  When set to "1", this bit disables interrupts */
                          /*  sent to the processor by way of the PINT bit. */
                          /*  The PINT bit can still be changed when */
                          /*  interrupts are disabled; however, the */
                          /*  low-to-high transition is not seen by the */
                          /*  processor until the INTDIS bit is made inactive */
          _pad:24;
};
struct _l_control_s {    /* to treat control as an unsigned long */
    unsigned long _long;
};
union _control_u {
    struct _b_control_s b_control_s;
    struct _l_control_s l_control_s;
};
struct control_s {
    union _control_u control_u;
};
#define b_reset      control_u.b_control_s._reset
#define b_387pres    control_u.b_control_s._387pres
#define b_cacheon    control_u.b_control_s._cacheon
#define b_mbusaccess  control_u.b_control_s._mbusaccess
#define b_flush      control_u.b_control_s._flush
#define b_387err      control_u.b_control_s._387err
#define b_pint        control_u.b_control_s._pint
#define b_intdis      control_u.b_control_s._intdis
#define b_all        control_u.l_control_s._long
/*
* The interrupt vector control port contains the 8-bit interrupt
* number that is executed when the PINT bit transitions from "0"
* to "1". This vector is only used for P2. P1 is always interrupted
* with IRQ 13.
*/
#define P2_INTERRUPT_VECTOR_CONTROL_PORT 0xFC68
/*
* The following ports contain the EISA identification of the
* system processor boards
*/
#define COMPAQ_ID1  0x0000000E
#define COMPAQ_ID2  0x00000011
#define P1_EISA_PRODUCT_ID_PORT1  0x0C80  /* Compressed COMPAQ ID - OEh */
#define P1_EISA_PRODUCT_ID_PORT2  0x0C81  /*                        11h */
#define P1_EISA_PRODUCT_ID_PORT3  0x0C82  /* Product code for the proc board */
#define P1_EISA_PRODUCT_ID_PORT4  0x0C83  /* Revision number */
#define P2_EISA_PRODUCT_ID_PORT1  0xFC80  /* Compressed COMPAQ ID - OEh */
#define P2_EISA_PRODUCT_ID_PORT2  0xFC81  /*                        11h */
#define P2_EISA_PRODUCT_ID_PORT3  0xFC82  /* Product code for the proc board */
#define P2_EISA_PRODUCT_ID_PORT4  0xFC83  /* Revision number */
/*
* Any write to The RAM Relocation Register (memory mapped)
* will flush the caches of both P1 and P2
*/
#define RAM_RELOCATION_REGISTER      0x80C00000
/*
* The P1 Cache Control Register (memory mapped)
*/
#define P1_CACHE_CONTROL_REGISTER    0x80C00002
struct p1cache_s {
  ulong_t _reserved1:6,
          _p1cc:1,      /* P1 Cache Control */
                          /*  0 = Disables P1 cache */
                          /*  1 = Enables P1 cache */
          _reserved2:9;
};
/*
* Expanision board control ports
*/
#define P1_EISA_EXPANSION_BOARD_CONTROL  0x0C84
#define P2_EISA_EXPANSION_BOARD_CONTROL  0xFC84
</PRE>
==Makefile ==
<PRE>
# SCCSID = @(#)makefile 6.7 92/06/03
#/***********************************************************************/
#/*                                                                    */
#/* PSD Name: ALR.PSD - ALR PSD                                        */
#/*          -----------------------------------                      */
#/*                                                                    */
#/* Source File Name: MAKEFILE                                          */
#/*                                                                    */
#/* Descriptive Name: MAKEFILE for the ALR PSD                          */
#/*                                                                    */
#/* Function:                                                          */
#/*                                                                    */
#/*                                                                    */
#/*---------------------------------------------------------------------*/
#/*                                                                    */
#/* Copyright (C) 1992 IBM Corporation                                  */
#/*                                                                    */
#/* DISCLAIMER OF WARRANTIES.  The following enclosed code is          */
#/* provided to you solely for the purpose of assisting you in          */
#/* the development of your applications. The code is provided          */
#/* "AS IS", without warranty of any kind. IBM shall not be liable      */
#/* for any damages arising out of your use of this code, even if      */
#/* they have been advised of the possibility of such damages.          */
#/*                                                                    */
#/*---------------------------------------------------------------------*/
#/*                                                                    */
#/* Change Log                                                          */
#/*                                                                    */
#/* Mark    Date      Programmer  Comment                              */
#/* ----    ----      ----------  -------                              */
#/* @nnnn  mm/dd/yy  NNN                                              */
#/*                                                                    */
#/*                                                                    */
#/***********************************************************************/
# ******  NOTE  ******
#
#      If you are using a SED command with TAB characters, many editors
#      will expand tabs causing unpredictable results in other programs.
#
#      Documentation:
#
#      Using SED command with TABS. Besure to invoke set tab save option
#      on your editor. If you don't, the program 'xyz' will not work
#      correctly.
#
#****************************************************************************
#  Dot directive definition area (usually just suffixes)
#****************************************************************************
.SUFFIXES:
.SUFFIXES: .com .sys .exe .obj .mbj .asm .inc .def .lnk .lrf .crf .ref
.SUFFIXES: .lst .sym .map .c .h .lib
#****************************************************************************
#  Environment Setup for the component(s).
#****************************************************************************
#
# Conditional Setup Area and User Defined Macros
#
#
# Compiler Location w/ includes, libs and tools
#
INC    = ..\..\..\inc
H      = ..\..\..\h
LIB    = ..\..\..\lib386;..\..\..\lib
TOOLSPATH = ..\..\..\tools
#
# Because the compiler/linker and other tools use environment
# variables ( INCLUDE, LIB, etc ) in order to get the location of files,
# the following line will check the environment for the LIFE of the
# makefile and will be specific to this set of instructions. All MAKEFILES
# are requested to use this format to insure that they are using the correct
# level of files and tools.
#
!if set INCLUDE=$(INC) || \
    set LIB=$(LIB) || set PATH=$(TOOLSPATH);$(DK_TOOLS)
!endif
#
# Compiler/tools Macros
#
AS=masm
CC=cl386
IMPLIB=implib
IPF=ipfc
LIBUTIL=lib
LINK=link386
MAPSYM=mapsym
RC=rc
#
# Compiler and Linker Options
#
AFLAGS = -MX -T -Z $(ENV)
AINC  = -I. -I$(INC)
CINC  = -I$(H) -I$(MAKEDIR)
CFLAGS = /c /Zp /Gs /AS $(ENV)
LFLAGS = /map /nod /exepack
LIBS = os2386.lib
DEF = ALR.def
#****************************************************************************
# Set up Macros that will contain all the different dependencies for the
# executables and dlls etc. that are generated.
#****************************************************************************
#
#
#
OBJ1 =  entry.obj main.obj
#
#      LIST Files
#
LIST =
OBJS = $(OBJ1)
#****************************************************************************
#  Setup the inference rules for compiling and assembling source code to
#  object code.
#****************************************************************************
.asm.obj:
        $(AS) $(AFLAGS) $(AINC) $*.asm;
.asm.mbj:
        $(AS) $(AFLAGS) -DMMIOPH $(AINC) $*.asm $*.mbj;
.asm.lst:
        $(AS) -l -n $(AFLAGS) $(AINC) $*.asm;
.c.obj:
        $(CC) $(CFLAGS) $(CINC) $*.c
.c.lst:
        $(CC) $(CFLAGS) /Fc $(CINC) $*.c
        copy $*.cod $*.lst
        del $*.cod
#****************************************************************************
#  Target Information
#****************************************************************************
#
# This is a very important step. The following small amount of code MUST
# NOT be removed from the program. The following directive will do
# dependency checking every time this component is built UNLESS the
# following is performed:
#              A specific tag is used -- ie. all
#
# This allows the developer as well as the B & I group to perform incremental
# build with a degree of accuracy that has not been used before.
# There are some instances where certain types of INCLUDE files must be
# created first. This type of format will allow the developer to require
# that file to be created first. In order to achieve that, all that has to
# be done is to make the DEPEND.MAK tag have your required target. Below is
# an example:
#
#    depend.mak:  { your file(s) } dephold
#
# Please DON'T remove the following line
#
!include      "$(H)\common.mak"
!include      "$(H)\version.mak"
#
# Should be the default tag for all general processing
#
all:    ALR.psd
list: $(LIST)
clean:
        if exist *.lnk del *.lnk
        if exist *.obj del *.obj
        if exist *.mbj del *.mbj
        if exist *.map del *.map
        if exist *.old del *.old
        if exist *.lst del *.lst
        if exist *.lsd del *.lsd
        if exist *.sym del *.sym
        if exist *.sys del *.sys
#*****************************************************************************
#  Specific Description Block Information
#*****************************************************************************
# This section would only be for specific direction as to how to create
# unique elements that are necessary to the build process. This could
# be compiling or assembling, creation of DEF files and other unique
# files.
# If all compiler and assembly rules are the same, use an inference rule to
# perform the compilation.
#
alr.psd:  $(OBJS) makefile
        Rem Create DEF file <<$(DEF)
LIBRARY ALR
EXPORTS
  PSD_INSTALL          = _Install
  PSD_DEINSTALL        = _DeInstall
  PSD_INIT            = _Init
  PSD_PROC_INIT        = _ProcInit
  PSD_START_PROC      = _StartProcessor
  PSD_GET_NUM_OF_PROCS = _GetNumOfProcs
  PSD_GEN_IPI          = _GenIPI
  PSD_END_IPI          = _EndIPI
<<keep
        $(LINK) $(LFLAGS) @<<$(@B).lnk
$(OBJ1)
$*.psd
$*.map
$(LIBS)
$(DEF)
<<keep
        $(MAPSYM) $*.map
#****************************************************************************
#  Dependency generation and Checking
#****************************************************************************
depend.mak:  dephold
        touch depchk
        includes -e -sobj -llst -I. -I$(H) -I$(DISKH) -I$(INC) -P$$(H)=$(H) *.c *.asm >$@
        -del depchk
dephold:
        touch $@
!include depend.mak
</PRE>

Revision as of 19:38, 24 May 2025

The following is the source code for an actual PSD.

Main program

#define INCL_ERROR_H

#include <os2.h>
#include <psd.h>
#include <alr.h>


extern ulong_t RMP2Available(void);


/*
 *  Global Variables
 */

P_F_2   router = 0;
char   *pParmString = 0;
int     IODelayCount = 30;
PLMA   *pPSDPLMA = 0;
ulong_t sizePLMA = 0;


/***  Disable - Disable interrupts
 *
 *    This function disables interrupts, and returns
 *    the original state of eflags
 *
 *    ENTRY   None
 *
 *    EXIT    EFLAGS
 *
 */

ulong_t Disable(void) {

   ulong_t eflags;

   _asm {
      pushfd
      pop   eax
      mov   eflags,eax
      cli
   };

   return (eflags);
}


/***  Enable - Restore the state of eflags
 *
 *    This function restores the state of eflags
 *
 *    ENTRY   eflags - state of eflags to restore
 *
 *    EXIT    None
 *
 */

void Enable(ulong_t eflags) {

   _asm {
      push  eflags
      popfd
   };

   return;
}


 /***  InByte - Read a byte from a port
  *
  *    This function reads a byte from a specified port
  *
  *    ENTRY   port - port number to read from
  *
  *    EXIT    data read
  *
  */

 ulong_t InByte(ulong_t port) {

    ulong_t data;

    _asm {
       mov   dx,port
       in    al,dx
       movzx eax,al
       mov   data,eax
    };

    return (data);
}


/***  OutByte - Writes a byte to a port
 *
 *    This function writes a byte to a specified port
 *
 *    ENTRY   port - port number to read from
 *            data - data to write
 *
 *    EXIT    None
 *
 */

void OutByte(ulong_t port, ulong_t data) {

   _asm {
      mov   dx,port
      mov   al,byte ptr data
      out   dx,al
   };

   return;
}


/***  SendEOI - Send an end of interrupt
 *
 *    This function sends an end of interrupt.
 *
 *    ENTRY   irq - irq level to end
 *
 *    EXIT    None
 *
 */

ulong_t SendEOI(ulong_t irq) {

   ulong_t flags;

   flags = Disable();

   if (irq < NUM_IRQ_PER_PIC)
      OutByte(PIC1_PORT0, OCW2_NON_SPECIFIC_EOI);
   else {
      OutByte(PIC2_PORT0, OCW2_NON_SPECIFIC_EOI);
      IODelay;
      OutByte(PIC1_PORT0, OCW2_NON_SPECIFIC_EOI);
   }

   Enable(flags);
}


/***  WHO_AM_I - Returns the current processor number
 *
 *    This function returns the current processor number
 *
 *    ENTRY   NONE
 *
 *    EXIT    Current processor number (P1 or P2)
 *
 */

ulong_t WHO_AM_I (void) {
   return(InByte(WHO_AM_I_PORT));
}


/***  IPIPresent - Detects the presence of an IPI
 *
 *    This function detects the presence of an IPI on the current
 *    processor
 *
 *    ENTRY   None
 *
 *    EXIT    NO_ERROR - IPI present
 *            -1       - IPI not present
 *
 */

ulong_t IPIPresent (void) {

   ulong_t rc = 0;
   struct control_s ctrl;
   ulong_t port;

   port = pPSDPLMA->controlport;

   ctrl.b_all = InByte(port);
   if (ctrl.b_387err)
   {
      OutByte (0xf0, 0); // The busy latch for NPX must be cleared.
                         // When we call the interrupt handler
                         // (w/ Call16bitDD int.asm), ints. are 1st enabled.
                         // If the busy latch is not cleared, then we
                         // will take this interrupt in again and will
                         // eventually nest until the interrupt stack is
                         // overrun.
      rc = -1;
   }
   return (rc);
}


/***  Install - Install PSD
 *
 *    This function checks to see if this PSD is installable on the
 *    current platform.
 *
 *    ENTRY   pinstall - pointer to an INSTALL structure
 *
 *    EXIT    NO_ERROR - PSD Installed
 *            -1       - PSD not valid for this platform
 *
 */

ulong_t Install(INSTALL *pinstall) {

   VMALLOC vmac;
   int i;
   char *p;
   ulong_t rc = 0;
   char ALR_String =  "PROVEISA";

// _asm int 3;

   /* Setup Global variables */

   router = pinstall->pPSDHlpRouter;
   pParmString = pinstall->pParmString;
   pPSDPLMA = (void *)pinstall->pPSDPLMA;
   sizePLMA = pinstall->sizePLMA;

   vmac.addr = BIOS_SEG << 4;
   vmac.cbsize = _64K;
   vmac.flags = VMALLOC_PHYS;

   /* Map BIOS area */

   if ((rc = PSDHelp(router, PSDHLP_VMALLOC, &vmac)) == NO_ERROR) {

      /* Check for ALR string */

      p = (char *)vmac.addr + ALR_STRING_OFFSET;

      for (i = 0; ALR_String i != '\0'; i++)
         if (p i  != ALR_String i) {
            rc = -1;
            break;
         }

      /* Free BIOS mapping */

      PSDHelp(router, PSDHLP_VMFREE, vmac.addr);
   }

   return (rc);
}


/***  DeInstall - DeInstall PSD
 *
 *    This function deinstalls the PSD.
 *
 *    ENTRY   None
 *
 *    EXIT    NO_ERROR
 *
 */

ulong_t DeInstall(void) {

   return (NO_ERROR);
}


/***  Init - Initialize the PSD
 *
 *    This function initializes the PSD.
 *
 *    ENTRY   None
 *
 *    EXIT    NO_ERROR - PSD initialized
 *            -1       - PSD not initialized
 *
 */

ulong_t Init(INIT *pinit) {

   struct control_s ctrl;
   SET_IRQ set_irq;


   /* Initialize P1 control port */

   ctrl.b_all = 0;
   ctrl.b_cacheon = 1;


   OutByte(P1_PROCESSOR_CONTROL_PORT, ctrl.b_all);

   /* Setup P2 interrupt vector */

   OutByte(P2_INTERRUPT_VECTOR_CONTROL_PORT, IPI_VECTOR);

   /* Setup IPI info */

   set_irq.irq = 13;
   set_irq.flags = IRQf_IPI;
   set_irq.vector = 0;
   set_irq.handler = (P_F_2)IPIPresent;

   PSDHelp(router, PSDHLP_SET_IRQ, &set_irq);

   /* Fill init structure */

   pinit->flags = INIT_EOI_IRQ13_ON_CPU0;           //76422
   pinit->version = VERSION;

   return (NO_ERROR);
}


/***  ProcInit - Processor initialization
 *
 *    This function initializes per processor items.
 *
 *    NOTE: This function is called once on each processor
 *          in the system.
 *
 *    ENTRY   None
 *
 *    EXIT    NO_ERROR - Processor initialized
 *            -1       - Processor not initialized
 *
 */

ulong_t ProcInit(void) {

   if (WHO_AM_I() == P1) {
      pPSDPLMA->procnum = 0;
      pPSDPLMA->controlport = P1_PROCESSOR_CONTROL_PORT;
   }
   else {
      pPSDPLMA->procnum = 1;
      pPSDPLMA->controlport = P2_PROCESSOR_CONTROL_PORT;
   }

   return (NO_ERROR);
}


/***  StartProcessor - Start a processor
 *
 *    This function starts a processor.
 *
 *    ENTRY   procnum - processor number to start (0-based)
 *
 *    EXIT    Return Code
 *
 */

ulong_t StartProcessor(ulong_t procnum) {

   CALL_REAL_MODE rm;
   struct control_s ctrl;
   ulong_t rc = -1;


   if (procnum == 1) {

      rm.function = (ulong_t)&RMP2Available;
      rm.pdata = 0;

      rc = PSDHelp(router, PSDHLP_CALL_REAL_MODE, &rm);

      if (rc & P2_AVAILABLE) {

         /* Dispatch P2 */

         ctrl.b_all = 0;
         ctrl.b_cacheon = 1;

         OutByte(P2_PROCESSOR_CONTROL_PORT, ctrl.b_all);
         rc = NO_ERROR;
      }
      else
         rc = -1;
   }

   return (rc);
}


/***  GetNumOfProcs - Get number of processors
 *
 *    This function gets the number of processors which exist on this
 *    platform.
 *
 *    ENTRY   None
 *
 *    EXIT    Number of processors
 *
 */

ulong_t GetNumOfProcs(void) {

   ulong_t cprocs = 2;

   return (cprocs);
}


/***  GenIPI - Generate an inter-processor interrupt
 *
 *    This function generates an IPI.
 *
 *    ENTRY   procnum - processor number to interrupt (0-based)
 *
 *    EXIT    NO_ERROR
 *
 */

ulong_t GenIPI(ulong_t procnum) {

   struct control_s ctrl;
   ulong_t port;


   if (procnum == 0)
      port = P1_PROCESSOR_CONTROL_PORT;
   else
      port = P2_PROCESSOR_CONTROL_PORT;


   ctrl.b_all = InByte(port);
   ctrl.b_pint = 1;

   OutByte(port, ctrl.b_all);

   return (NO_ERROR);
}


/***  EndIPI - End an inter-processor interrupt
 *
 *    This function ends an IPI.
 *
 *    ENTRY   procnum - processor number to end interrupt on (0-based)
 *
 *    EXIT    NO_ERROR
 *
 */

ulong_t EndIPI(ulong_t procnum) {

   struct control_s ctrl;
   ulong_t port;

   if (procnum == 0)
      port = P1_PROCESSOR_CONTROL_PORT;
   else
      port = P2_PROCESSOR_CONTROL_PORT;

   ctrl.b_all = InByte(port);
   ctrl.b_pint = 0;

   OutByte(port, ctrl.b_all);

   if (procnum == 0)
      SendEOI(IPI_IRQ);

   return (NO_ERROR);
}

Entry stub

.386

_TEXT SEGMENT

ASSUME CS:_TEXT,DS:NOTHING

      PUBLIC  _RMP2Available

_RMP2Available PROC

      mov   ah,0E2h
      mov   al,0
      int   15h
      movzx eax,ax
      retf

_RMP2Available ENDP

_TEXT ENDS

END

PSD.H

/*static char *SCCSID = "@(#)psd.h 1.0 93/18/08";*/


// XLATOFF

#ifndef ulong_t

typedef unsigned long   ulong_t;
typedef unsigned short  ushort_t;
typedef unsigned char   uchar_t;

#endif

typedef int (*P_F_1)(ulong_t arg);
typedef int (*P_F_2)(ulong_t arg1, ulong_t arg2);

#define PSDHelp(router, function, arg) \
   ((*router)((function), (ulong_t)(arg)))

// XLATON
/* ASM
P_F_1 struc
dd ?
P_F_1 ends
P_F_2 struc
dd ?
P_F_2 ends
*/


#define WARM_REBOOT_VECTOR_SEG  0x40
#define WARM_REBOOT_VECTOR_OFF  0x67


/* PSD Info structure */

typedef struct info_s {                     /* psd */
   ulong_t  flags;                          /* PSD flags */
   ulong_t  version;                        /* PSD version */
   ulong_t  hmte;                           /* MTE handle of PSD */
   uchar_t *pParmString;                    /* Pointer to ASCIIZ PSD parameter*/
   ulong_t  IRQ_IPI;                        /* IRQ for IPI */
   ulong_t  IRQ_LSI;                        /* IRQ for LSI */
   ulong_t  IRQ_SPI;                        /* IRQ for SPI */
} PSDINFO;


/* PSD flags definition */

#define PSD_ADV_INT_MODE        0x20000000  /* PSD is in adv int mode #81531 */
#define PSD_INSTALLED           0x40000000  /* PSD has been installed */
#define PSD_INITIALIZED         0x80000000  /* PSD has been initialized */

/* PSD function numbers-structures */

#define PSD_INSTALL             0x00000000  /* Install PSD */

typedef struct install_s {                  /* install */
   P_F_2   pPSDHlpRouter;                   /* Address of PSDHlpRouter */
   char   *pParmString;                     /* Pointer to parameter string */
   void   *pPSDPLMA;                        /* Pointer to PSD's PLMA */
   ulong_t sizePLMA;                        /* Size of PLMA in bytes */
} INSTALL;

#define PSD_DEINSTALL           0x00000001  /* DeInstall PSD */

#define PSD_INIT                0x00000002  /* Initialize PSD */

typedef struct init_s {                     /* init */
   ulong_t flags;                           /* Init flags */
   ulong_t version;                         /* PSD Version number */
} INIT;

#define INIT_GLOBAL_IRQ_ACCESS  0x00000001  /* Platform has global IRQ access */
#define INIT_USE_FPERR_TRAP     0x00000002  /* Use Trap 16 to report FP err's */
#define INIT_EOI_IRQ13_ON_CPU0  0x00000004  /* eoi IRQ 13 only if on cpu 0    */
#define INIT_TIMER_CPU0         0x00000008  /* system timer is on CPU 0       */

#define PSD_PROC_INIT           0x00000003  /* Initialize processor */

#define PSD_START_PROC          0x00000004  /* Start processor */

#define PSD_GET_NUM_OF_PROCS    0x00000005  /* Get number of processors */

#define PSD_GEN_IPI             0x00000006  /* Generate an IPI */

#define PSD_END_IPI             0x00000007  /* End an IPI */

#define PSD_PORT_IO             0x00000008  /* Port I/O */

typedef struct port_io_s {                  /* port_io */
   ulong_t port;                            /* Port number to access */
   ulong_t data;                            /* Data read, or data to write */
   ulong_t flags;                           /* IO Flags */
} PORT_IO;

#define IO_READ_BYTE    0x0000              /* Read a byte from the port */
#define IO_READ_WORD    0x0001              /* Read a word from the port */
#define IO_READ_DWORD   0x0002              /* Read a dword from the port */
#define IO_WRITE_BYTE   0x0003              /* Write a byte to the port */
#define IO_WRITE_WORD   0x0004              /* Write a word to the port */
#define IO_WRITE_DWORD  0x0005              /* Write a dword to the port */

#define IO_FLAGMASK     0x0007              /* Flag mask */

#define PSD_IRQ_MASK            0x00000009  /* Mask/Unmask IRQ levels */

typedef struct psd_irq_s {                  /* psd_irq */
   ulong_t flags;                           /* IRQ flags */
   ulong_t data;                            /* IRQ data */
                                            /*   depending on type of irq */
                                            /*   operation, the data field */
                                            /*   can contain any of the */
                                            /*   following info: */
                                            /*   1) Mask or UNMasking data */
                                            /*   2) IRR or ISR reg values */
                                            /*   3) IRQ # for EOI operations */
   ulong_t procnum;                         /* Processor number */
} PSD_IRQ;

#define PSD_IRQ_REG             0x0000000A  /* Access IRQ related regs */

#define PSD_IRQ_EOI             0x0000000B  /* Issue an EOI */

#define IRQ_MASK                0x00000001  /* Turn on IRQ mask bits */
#define IRQ_UNMASK              0x00000002  /* Turn off IRQ mask bits */
#define IRQ_GETMASK             0x00000004  /* Get IRQ mask bits */
#define IRQ_NEWMASK             0x00000010  /* Set and/or Reset all masks */
#define IRQ_READ_IRR            0x00000100  /* Read the IRR reg */
#define IRQ_READ_ISR            0x00000200  /* Read the ISR reg */

#define PSD_APP_COMM            0x0000000C  /* PSD/APP Communication */

#define PSD_SET_ADV_INT_MODE    0x0000000D  /* Set advanced int mode */

#define PSD_SET_PROC_STATE      0x0000000E  /* Set proc state; idle, or busy */

#define PROC_STATE_IDLE         0x00000000  /* Processor is idle */
#define PROC_STATE_BUSY         0x00000001  /* Processor is busy */

#define PSD_QUERY_SYSTEM_TIMER  0x0000000F  /* Query Value of System Timer 0 */

typedef struct psd_qrytmr_s {               /* psd_qrytmr */
   ulong_t qw_ulLo_psd;                     /* Timer count */
   ulong_t qw_ulHi_psd;                     /* Timer count */
   ulong_t pqwTmr;                          /* 16:16 ptr to qwTmr */
} PSD_QRYTMR;

#define PSD_SET_SYSTEM_TIMER    0x00000010  /* Set System Timer 0 counter    */

typedef struct psd_settmr_s {               /* psd_settmr */
   ulong_t NewRollOver;                     /* NewRollover*/
   ulong_t pqwTmrRollover;                  /* 16:16 ptr to qwTmrRollover */
} PSD_SETTMR;

/* PSD helper function numbers-structures */

#define PSDHLP_VMALLOC          0x00000000  /* Allocate memory */

typedef struct vmalloc_s {                  /* vmalloc */
   ulong_t addr;                            /* Physical address to map */
                                            /*  if VMALLOC_PHYS */
                                            /* Lin addr to alloc at */
                                            /*  if VMALLOC_LOCSPECIFIC */
                                            /* on return, addr of allocation */
   ulong_t cbsize;                          /* Size of mapping in bytes */
   ulong_t flags;                           /* Allocation flags */
} VMALLOC;

#define VMALLOC_FIXED           0x00000001  /* Allocate resident memory */
#define VMALLOC_CONTIG          0x00000002  /* Allocate contiguous memory */
#define VMALLOC_LOCSPECIFIC     0x00000004  /* Alloc at a specific lin address */
#define VMALLOC_PHYS            0x00000008  /* Map physical address */
#define VMALLOC_1M              0x00000010  /* Allocate below 1M */

#define VMALLOC_FLAGMASK        0x0000001f  /* Valid flag mask */

#define PSDHLP_VMFREE           0x00000001  /* Free memory */

#define PSDHLP_SET_IRQ          0x00000002  /* Set up an IRQ */

typedef struct set_irq_s {                  /* set_irq */
   ushort_t irq;                            /* IRQ level */
   ushort_t flags;                          /* Set IRQ flags */
   ulong_t  vector;                         /* IRQ interrupt vector */
   P_F_2    handler;                        /* IRQ handler */
} SET_IRQ;

#define IRQf_IPI  0x0020                    /* IRQ for IPI */
#define IRQf_LSI  0x0040                    /* IRQ for LSI */
#define IRQf_SPI  0x0080                    /* IRQ for SPI */

#define PSDHLP_CALL_REAL_MODE   0x00000003  /* Call a function in real mode */

typedef struct call_real_mode_s {           /* call_real_mode */
   ulong_t function;                        /* Function address */
   ulong_t pdata;                           /* Pointer to data area */
} CALL_REAL_MODE;

#define PSDHLP_VMLINTOPHYS      0x00000004  /* Convert linear addr to phys */

#define PSDHLP_ADJ_PG_RANGES    0x00000005  /* Adjust page ranges */

typedef struct _pagerange_s {               /* pagerange */
   ulong_t lastframe;                       /* Last valid page in range */
   ulong_t firstframe;                      /* First valid page in range */
};

typedef struct adj_pg_ranges_s{             /* adj_pg_ranges */
   struct _pagerange_s *pprt;               /* Pointer to page range table */
   ulong_t nranges;                         /* Num of ranges in range table */
} ADJ_PG_RANGES;

/* PSD function prototypes */

extern void PSDEnter (ulong_t function, ulong_t arg, P_F_2 altEntry);

Specific header

/*
 * Miscellaneous
 */

#define VERSION   0x00000010

#define _64K      (64 * 1024)

#define BIOS_SEG             0xF000
#define ALR_STRING_OFFSET   0xEC47

#define P2_AVAILABLE         0x00008000


/*
 * PLMA structure
 */

typedef struct plma_s {
   ulong_t procnum;       /* Current processor number (0-based) */
   ulong_t controlport;   /* Control port for current processor */
} PLMA;


/*
 * Generate delay between I/O instructions
 */

#define IODelay {int i; for(i = 0; i < IODelayCount; i++); }


/*
 * IPI info
 */

#define IPI_IRQ     0x0d      /* IRQ level for IPI */
#define IPI_VECTOR  0x75      /* Vector number for IPI */


/*
 * PIC Info
 */

#define NUM_IRQ_PER_PIC         0x08
#define OCW2_NON_SPECIFIC_EOI   0x20
#define PIC1_PORT0              0x20
#define PIC1_PORT1              0x21
#define PIC2_PORT0              0xA0
#define PIC2_PORT1              0xA1


/*
 * The contents of the WHO_AM_I port (read-only) can be used
 * by code to determine which processor we are currently on
 */

#define WHO_AM_I_PORT  0xC70
#define P1             0x00
#define P2             0xF0


/*
 * The processor control port contains the bits used to control
 * various functions of the associated processor
 */

#define P1_PROCESSOR_CONTROL_PORT  0x0C6A
#define P2_PROCESSOR_CONTROL_PORT  0xFC6A

struct _b_control_s {
   ulong_t _reset:1,      /* RESET - (Not implemented for P1) */
                          /*  1 = Resets processor */

           _387pres:1,    /* 387PRES - (Read only) */
                          /*  0 = 80387 is not installed */
                          /*  1 = 80387 is installed */

           _cacheon:1,    /* CACHEON - (Not implemented for P1) */
                          /*  0 = Disables cache */
                          /*  1 = Enables cache */

           _mbusaccess:1, /* M Bus Access (Not implemented for P1) */
                          /*  0 = Allows the processor to gain */
                          /*      control of the memory bus */
                          /*  1 = Prohibits the processor from gaining */
                          /*      access to the memory bus. The */
                          /*      processor can execute instructions */
                          /*      from its cache; however, cache read */
                          /*      misses, I/O, and writes cause the */
                          /*      processor to cease executing */
                          /*      instructions until the bit becomes */
                          /*      a "0" */

           _flush:1,      /* FLUSH */
                          /*  Writing a "1" to this bit followed by a "0" */
                          /*  causes invalidation of all cache address */
                          /*  information */

           _387err:1,     /* 387ERR */
                          /*  0 = No 80387 error */
                          /*  0 = An 80387 error has occurred. This bit */
                          /*      must be cleared by software */

           _pint:1,       /* PINT */
                          /*  A low-to-high transition of this bit causes */
                          /*  an interrupt. This bit must be cleared by  */
                          /*  software, preferably by the interrupt service */
                          /*  routine. On P2, the value stored in FC68h */
                          /*  contains the interrupt number. P1 is always */
                          /*  interrupted with IRQ13 */

           _intdis:1,     /* INTDIS */
                          /*  When set to "1", this bit disables interrupts */
                          /*  sent to the processor by way of the PINT bit. */
                          /*  The PINT bit can still be changed when */
                          /*  interrupts are disabled; however, the */
                          /*  low-to-high transition is not seen by the */
                          /*  processor until the INTDIS bit is made inactive */
           _pad:24;
};

struct _l_control_s {     /* to treat control as an unsigned long */
    unsigned long _long;
};

union _control_u {
    struct _b_control_s b_control_s;
    struct _l_control_s l_control_s;
};

struct control_s {
    union _control_u control_u;
};

#define b_reset       control_u.b_control_s._reset
#define b_387pres     control_u.b_control_s._387pres
#define b_cacheon     control_u.b_control_s._cacheon
#define b_mbusaccess  control_u.b_control_s._mbusaccess
#define b_flush       control_u.b_control_s._flush
#define b_387err      control_u.b_control_s._387err
#define b_pint        control_u.b_control_s._pint
#define b_intdis      control_u.b_control_s._intdis
#define b_all         control_u.l_control_s._long


/*
 * The interrupt vector control port contains the 8-bit interrupt
 * number that is executed when the PINT bit transitions from "0"
 * to "1". This vector is only used for P2. P1 is always interrupted
 * with IRQ 13.
 */

#define P2_INTERRUPT_VECTOR_CONTROL_PORT 0xFC68


/*
 * The following ports contain the EISA identification of the
 * system processor boards
 */

#define COMPAQ_ID1  0x0000000E
#define COMPAQ_ID2  0x00000011

#define P1_EISA_PRODUCT_ID_PORT1  0x0C80  /* Compressed COMPAQ ID - OEh */
#define P1_EISA_PRODUCT_ID_PORT2  0x0C81  /*                        11h */
#define P1_EISA_PRODUCT_ID_PORT3  0x0C82  /* Product code for the proc board */
#define P1_EISA_PRODUCT_ID_PORT4  0x0C83  /* Revision number */

#define P2_EISA_PRODUCT_ID_PORT1  0xFC80  /* Compressed COMPAQ ID - OEh */
#define P2_EISA_PRODUCT_ID_PORT2  0xFC81  /*                        11h */
#define P2_EISA_PRODUCT_ID_PORT3  0xFC82  /* Product code for the proc board */
#define P2_EISA_PRODUCT_ID_PORT4  0xFC83  /* Revision number */

/*
 * Any write to The RAM Relocation Register (memory mapped)
 * will flush the caches of both P1 and P2
 */

#define RAM_RELOCATION_REGISTER       0x80C00000


/*
 * The P1 Cache Control Register (memory mapped)
 */

#define P1_CACHE_CONTROL_REGISTER     0x80C00002

struct p1cache_s {
   ulong_t _reserved1:6,
           _p1cc:1,       /* P1 Cache Control */
                          /*  0 = Disables P1 cache */
                          /*  1 = Enables P1 cache */
           _reserved2:9;
};


/*
 * Expanision board control ports
 */

#define P1_EISA_EXPANSION_BOARD_CONTROL  0x0C84
#define P2_EISA_EXPANSION_BOARD_CONTROL  0xFC84

Makefile

# SCCSID = @(#)makefile 6.7 92/06/03

#/***********************************************************************/
#/*                                                                     */
#/* PSD Name: ALR.PSD - ALR PSD                                         */
#/*           -----------------------------------                       */
#/*                                                                     */
#/* Source File Name: MAKEFILE                                          */
#/*                                                                     */
#/* Descriptive Name: MAKEFILE for the ALR PSD                          */
#/*                                                                     */
#/* Function:                                                           */
#/*                                                                     */
#/*                                                                     */
#/*---------------------------------------------------------------------*/
#/*                                                                     */
#/* Copyright (C) 1992 IBM Corporation                                  */
#/*                                                                     */
#/* DISCLAIMER OF WARRANTIES.  The following enclosed code is           */
#/* provided to you solely for the purpose of assisting you in          */
#/* the development of your applications. The code is provided          */
#/* "AS IS", without warranty of any kind. IBM shall not be liable      */
#/* for any damages arising out of your use of this code, even if       */
#/* they have been advised of the possibility of such damages.          */
#/*                                                                     */
#/*---------------------------------------------------------------------*/
#/*                                                                     */
#/* Change Log                                                          */
#/*                                                                     */
#/* Mark    Date      Programmer  Comment                               */
#/* ----    ----      ----------  -------                               */
#/* @nnnn   mm/dd/yy  NNN                                               */
#/*                                                                     */
#/*                                                                     */
#/***********************************************************************/

# ******  NOTE  ******
#
#       If you are using a SED command with TAB characters, many editors
#       will expand tabs causing unpredictable results in other programs.
#
#       Documentation:
#
#       Using SED command with TABS. Besure to invoke set tab save option
#       on your editor. If you don't, the program 'xyz' will not work
#       correctly.
#

#****************************************************************************
#  Dot directive definition area (usually just suffixes)
#****************************************************************************

.SUFFIXES:
.SUFFIXES: .com .sys .exe .obj .mbj .asm .inc .def .lnk .lrf .crf .ref
.SUFFIXES: .lst .sym .map .c .h .lib

#****************************************************************************
#  Environment Setup for the component(s).
#****************************************************************************

#
# Conditional Setup Area and User Defined Macros
#

#
# Compiler Location w/ includes, libs and tools
#

INC    = ..\..\..\inc
H      = ..\..\..\h
LIB    = ..\..\..\lib386;..\..\..\lib
TOOLSPATH = ..\..\..\tools

#
# Because the compiler/linker and other tools use environment
# variables ( INCLUDE, LIB, etc ) in order to get the location of files,
# the following line will check the environment for the LIFE of the
# makefile and will be specific to this set of instructions. All MAKEFILES
# are requested to use this format to insure that they are using the correct
# level of files and tools.
#

!if set INCLUDE=$(INC) || \
    set LIB=$(LIB) || set PATH=$(TOOLSPATH);$(DK_TOOLS)
!endif


#
# Compiler/tools Macros
#

AS=masm
CC=cl386
IMPLIB=implib
IPF=ipfc
LIBUTIL=lib
LINK=link386
MAPSYM=mapsym
RC=rc

#
# Compiler and Linker Options
#

AFLAGS = -MX -T -Z $(ENV)
AINC   = -I. -I$(INC)
CINC   = -I$(H) -I$(MAKEDIR)
CFLAGS = /c /Zp /Gs /AS $(ENV)
LFLAGS = /map /nod /exepack

LIBS = os2386.lib
DEF = ALR.def

#****************************************************************************
# Set up Macros that will contain all the different dependencies for the
# executables and dlls etc. that are generated.
#****************************************************************************

#
#
#
OBJ1 =  entry.obj main.obj

#
#       LIST Files
#
LIST =

OBJS = $(OBJ1)

#****************************************************************************
#   Setup the inference rules for compiling and assembling source code to
#   object code.
#****************************************************************************


.asm.obj:
        $(AS) $(AFLAGS) $(AINC) $*.asm;

.asm.mbj:
        $(AS) $(AFLAGS) -DMMIOPH $(AINC) $*.asm $*.mbj;

.asm.lst:
        $(AS) -l -n $(AFLAGS) $(AINC) $*.asm;

.c.obj:
        $(CC) $(CFLAGS) $(CINC) $*.c

.c.lst:
        $(CC) $(CFLAGS) /Fc $(CINC) $*.c
        copy $*.cod $*.lst
        del $*.cod


#****************************************************************************
#   Target Information
#****************************************************************************
#
# This is a very important step. The following small amount of code MUST
# NOT be removed from the program. The following directive will do
# dependency checking every time this component is built UNLESS the
# following is performed:
#               A specific tag is used -- ie. all
#
# This allows the developer as well as the B & I group to perform incremental
# build with a degree of accuracy that has not been used before.
# There are some instances where certain types of INCLUDE files must be
# created first. This type of format will allow the developer to require
# that file to be created first. In order to achieve that, all that has to
# be done is to make the DEPEND.MAK tag have your required target. Below is
# an example:
#
#    depend.mak:   { your file(s) } dephold
#
# Please DON'T remove the following line
#

!include      "$(H)\common.mak"
!include      "$(H)\version.mak"

#
# Should be the default tag for all general processing
#

all:    ALR.psd

list: $(LIST)

clean:
        if exist *.lnk	del *.lnk
        if exist *.obj	del *.obj
        if exist *.mbj	del *.mbj
        if exist *.map	del *.map
        if exist *.old	del *.old
        if exist *.lst	del *.lst
        if exist *.lsd	del *.lsd
        if exist *.sym	del *.sym
        if exist *.sys	del *.sys




#*****************************************************************************
#   Specific Description Block Information
#*****************************************************************************

# This section would only be for specific direction as to how to create
# unique elements that are necessary to the build process. This could
# be compiling or assembling, creation of DEF files and other unique
# files.
# If all compiler and assembly rules are the same, use an inference rule to
# perform the compilation.
#

alr.psd:  $(OBJS) makefile
        Rem Create DEF file <<$(DEF)
LIBRARY ALR

EXPORTS

   PSD_INSTALL          = _Install
   PSD_DEINSTALL        = _DeInstall
   PSD_INIT             = _Init
   PSD_PROC_INIT        = _ProcInit
   PSD_START_PROC       = _StartProcessor
   PSD_GET_NUM_OF_PROCS = _GetNumOfProcs
   PSD_GEN_IPI          = _GenIPI
   PSD_END_IPI          = _EndIPI
<<keep
        $(LINK) $(LFLAGS) @<<$(@B).lnk
$(OBJ1)
$*.psd
$*.map
$(LIBS)
$(DEF)
<<keep
        $(MAPSYM) $*.map



#****************************************************************************
#  Dependency generation and Checking
#****************************************************************************

depend.mak:  dephold
        touch depchk
        includes -e -sobj -llst -I. -I$(H) -I$(DISKH) -I$(INC) -P$$(H)=$(H) *.c *.asm >$@
        -del depchk

dephold:
        touch $@

!include depend.mak