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
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
{{SMPV211}}
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>

Latest revision as of 19:38, 24 May 2025

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

OS/2 for SMP V2.11 Reference
  1. Notices
  2. Overview of OS/2 for SMP Version 2.11
  3. Platform Specific Drivers (PSDs)
  4. Understanding Spinlocks
  5. Device Drivers In OS/2 for SMP V2.11
  6. Application Considerations
  7. Avoiding Device Driver Deadlocks
  8. New Device Helper (DevHlp) Routines
  9. New Kernel Debugger Commands
  10. The Single Processor Utility Program
  11. OS/2 for SMP V2.11 Tools
  12. Appendix A
  13. Glossary

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