Diff for /qemu/hw/openpic.c between versions 1.1.1.8 and 1.1.1.9

version 1.1.1.8, 2018/04/24 18:37:22 version 1.1.1.9, 2018/04/24 19:26:53
Line 2 Line 2
  * OpenPIC emulation   * OpenPIC emulation
  *   *
  * Copyright (c) 2004 Jocelyn Mayer   * Copyright (c) 2004 Jocelyn Mayer
    *               2011 Alexander Graf
  *   *
  * Permission is hereby granted, free of charge, to any person obtaining a copy   * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal   * of this software and associated documentation files (the "Software"), to deal
Line 56 Line 57
 #define MAX_MBX     4  #define MAX_MBX     4
 #define MAX_TMR     4  #define MAX_TMR     4
 #define VECTOR_BITS 8  #define VECTOR_BITS 8
 #define MAX_IPI     0  #define MAX_IPI     4
   
 #define VID (0x00000000)  #define VID (0x00000000)
   
 #elif defined(USE_MPCxxx)  #elif defined(USE_MPCxxx)
   
 #define MAX_CPU     2  #define MAX_CPU    15
 #define MAX_IRQ   128  #define MAX_IRQ   128
 #define MAX_DBL     0  #define MAX_DBL     0
 #define MAX_MBX     0  #define MAX_MBX     0
Line 127  enum { Line 128  enum {
 #define MPIC_MSI_REG_START        0x11C00  #define MPIC_MSI_REG_START        0x11C00
 #define MPIC_MSI_REG_SIZE         0x100  #define MPIC_MSI_REG_SIZE         0x100
 #define MPIC_CPU_REG_START        0x20000  #define MPIC_CPU_REG_START        0x20000
 #define MPIC_CPU_REG_SIZE         0x100  #define MPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
   
 enum mpic_ide_bits {  enum mpic_ide_bits {
     IDR_EP     = 0,      IDR_EP     = 31,
     IDR_CI0     = 1,      IDR_CI0     = 30,
     IDR_CI1     = 2,      IDR_CI1     = 29,
     IDR_P1     = 30,      IDR_P1     = 1,
     IDR_P0     = 31,      IDR_P0     = 0,
 };  };
   
 #else  #else
Line 161  static inline int test_bit (uint32_t *fi Line 162  static inline int test_bit (uint32_t *fi
     return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;      return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
 }  }
   
   static int get_current_cpu(void)
   {
     return cpu_single_env->cpu_index;
   }
   
   static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
                                             int idx);
   static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
                                          uint32_t val, int idx);
   
 enum {  enum {
     IRQ_EXTERNAL = 0x01,      IRQ_EXTERNAL = 0x01,
     IRQ_INTERNAL = 0x02,      IRQ_INTERNAL = 0x02,
Line 205  typedef struct IRQ_dst_t { Line 216  typedef struct IRQ_dst_t {
   
 typedef struct openpic_t {  typedef struct openpic_t {
     PCIDevice pci_dev;      PCIDevice pci_dev;
     int mem_index;      MemoryRegion mem;
   
       /* Sub-regions */
       MemoryRegion sub_io_mem[7];
   
     /* Global registers */      /* Global registers */
     uint32_t frep; /* Feature reporting register */      uint32_t frep; /* Feature reporting register */
     uint32_t glbc; /* Global configuration register  */      uint32_t glbc; /* Global configuration register  */
Line 461  static void openpic_reset (void *opaque) Line 476  static void openpic_reset (void *opaque)
     opp->glbc = 0x00000000;      opp->glbc = 0x00000000;
 }  }
   
 static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)  static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ)
 {  {
     uint32_t retval;      return opp->src[n_IRQ].ide;
   }
     switch (reg) {  
     case IRQ_IPVP:  
         retval = opp->src[n_IRQ].ipvp;  
         break;  
     case IRQ_IDE:  
         retval = opp->src[n_IRQ].ide;  
         break;  
     }  
   
     return retval;  static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ)
   {
       return opp->src[n_IRQ].ipvp;
 }  }
   
 static inline void write_IRQreg (openpic_t *opp, int n_IRQ,  static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val)
                                  uint32_t reg, uint32_t val)  
 {  {
     uint32_t tmp;      uint32_t tmp;
   
     switch (reg) {      tmp = val & 0xC0000000;
     case IRQ_IPVP:      tmp |= val & ((1ULL << MAX_CPU) - 1);
         /* NOTE: not fully accurate for special IRQs, but simple and      opp->src[n_IRQ].ide = tmp;
            sufficient */      DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
         /* ACTIVITY bit is read-only */  }
         opp->src[n_IRQ].ipvp =  
             (opp->src[n_IRQ].ipvp & 0x40000000) |  static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val)
             (val & 0x800F00FF);  {
         openpic_update_irq(opp, n_IRQ);      /* NOTE: not fully accurate for special IRQs, but simple and sufficient */
         DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",      /* ACTIVITY bit is read-only */
                 n_IRQ, val, opp->src[n_IRQ].ipvp);      opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000)
         break;                           | (val & 0x800F00FF);
     case IRQ_IDE:      openpic_update_irq(opp, n_IRQ);
         tmp = val & 0xC0000000;      DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
         tmp |= val & ((1 << MAX_CPU) - 1);              opp->src[n_IRQ].ipvp);
         opp->src[n_IRQ].ide = tmp;  
         DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);  
         break;  
     }  
 }  }
   
 #if 0 // Code provision for Intel model  #if 0 // Code provision for Intel model
Line 512  static uint32_t read_doorbell_register ( Line 516  static uint32_t read_doorbell_register (
   
     switch (offset) {      switch (offset) {
     case DBL_IPVP_OFFSET:      case DBL_IPVP_OFFSET:
         retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);          retval = read_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl);
         break;          break;
     case DBL_IDE_OFFSET:      case DBL_IDE_OFFSET:
         retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);          retval = read_IRQreg_ide(opp, IRQ_DBL0 + n_dbl);
         break;          break;
     case DBL_DMR_OFFSET:      case DBL_DMR_OFFSET:
         retval = opp->doorbells[n_dbl].dmr;          retval = opp->doorbells[n_dbl].dmr;
Line 530  static void write_doorbell_register (pen Line 534  static void write_doorbell_register (pen
 {  {
     switch (offset) {      switch (offset) {
     case DBL_IVPR_OFFSET:      case DBL_IVPR_OFFSET:
         write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);          write_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl, value);
         break;          break;
     case DBL_IDE_OFFSET:      case DBL_IDE_OFFSET:
         write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);          write_IRQreg_ide(opp, IRQ_DBL0 + n_dbl, value);
         break;          break;
     case DBL_DMR_OFFSET:      case DBL_DMR_OFFSET:
         opp->doorbells[n_dbl].dmr = value;          opp->doorbells[n_dbl].dmr = value;
Line 553  static uint32_t read_mailbox_register (o Line 557  static uint32_t read_mailbox_register (o
         retval = opp->mailboxes[n_mbx].mbr;          retval = opp->mailboxes[n_mbx].mbr;
         break;          break;
     case MBX_IVPR_OFFSET:      case MBX_IVPR_OFFSET:
         retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);          retval = read_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx);
         break;          break;
     case MBX_DMR_OFFSET:      case MBX_DMR_OFFSET:
         retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);          retval = read_IRQreg_ide(opp, IRQ_MBX0 + n_mbx);
         break;          break;
     }      }
   
Line 571  static void write_mailbox_register (open Line 575  static void write_mailbox_register (open
         opp->mailboxes[n_mbx].mbr = value;          opp->mailboxes[n_mbx].mbr = value;
         break;          break;
     case MBX_IVPR_OFFSET:      case MBX_IVPR_OFFSET:
         write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);          write_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx, value);
         break;          break;
     case MBX_DMR_OFFSET:      case MBX_DMR_OFFSET:
         write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);          write_IRQreg_ide(opp, IRQ_MBX0 + n_mbx, value);
         break;          break;
     }      }
 }  }
Line 590  static void openpic_gbl_write (void *opa Line 594  static void openpic_gbl_write (void *opa
     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);      DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
     if (addr & 0xF)      if (addr & 0xF)
         return;          return;
     addr &= 0xFF;  
     switch (addr) {      switch (addr) {
     case 0x00: /* FREP */      case 0x40:
       case 0x50:
       case 0x60:
       case 0x70:
       case 0x80:
       case 0x90:
       case 0xA0:
       case 0xB0:
           openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
           break;
       case 0x1000: /* FREP */
         break;          break;
     case 0x20: /* GLBC */      case 0x1020: /* GLBC */
         if (val & 0x80000000 && opp->reset)          if (val & 0x80000000 && opp->reset)
             opp->reset(opp);              opp->reset(opp);
         opp->glbc = val & ~0x80000000;          opp->glbc = val & ~0x80000000;
         break;          break;
     case 0x80: /* VENI */      case 0x1080: /* VENI */
         break;          break;
     case 0x90: /* PINT */      case 0x1090: /* PINT */
         for (idx = 0; idx < opp->nb_cpus; idx++) {          for (idx = 0; idx < opp->nb_cpus; idx++) {
             if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {              if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
                 DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);                  DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
Line 615  static void openpic_gbl_write (void *opa Line 628  static void openpic_gbl_write (void *opa
         }          }
         opp->pint = val;          opp->pint = val;
         break;          break;
 #if MAX_IPI > 0      case 0x10A0: /* IPI_IPVP */
     case 0xA0: /* IPI_IPVP */      case 0x10B0:
     case 0xB0:      case 0x10C0:
     case 0xC0:      case 0x10D0:
     case 0xD0:  
         {          {
             int idx;              int idx;
             idx = (addr - 0xA0) >> 4;              idx = (addr - 0x10A0) >> 4;
             write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP, val);              write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val);
         }          }
         break;          break;
 #endif      case 0x10E0: /* SPVE */
     case 0xE0: /* SPVE */  
         opp->spve = val & 0x000000FF;          opp->spve = val & 0x000000FF;
         break;          break;
     case 0xF0: /* TIFR */      case 0x10F0: /* TIFR */
         opp->tifr = val;          opp->tifr = val;
         break;          break;
     default:      default:
Line 647  static uint32_t openpic_gbl_read (void * Line 658  static uint32_t openpic_gbl_read (void *
     retval = 0xFFFFFFFF;      retval = 0xFFFFFFFF;
     if (addr & 0xF)      if (addr & 0xF)
         return retval;          return retval;
     addr &= 0xFF;  
     switch (addr) {      switch (addr) {
     case 0x00: /* FREP */      case 0x1000: /* FREP */
         retval = opp->frep;          retval = opp->frep;
         break;          break;
     case 0x20: /* GLBC */      case 0x1020: /* GLBC */
         retval = opp->glbc;          retval = opp->glbc;
         break;          break;
     case 0x80: /* VENI */      case 0x1080: /* VENI */
         retval = opp->veni;          retval = opp->veni;
         break;          break;
     case 0x90: /* PINT */      case 0x1090: /* PINT */
         retval = 0x00000000;          retval = 0x00000000;
         break;          break;
 #if MAX_IPI > 0      case 0x40:
     case 0xA0: /* IPI_IPVP */      case 0x50:
       case 0x60:
       case 0x70:
       case 0x80:
       case 0x90:
       case 0xA0:
     case 0xB0:      case 0xB0:
     case 0xC0:          retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
     case 0xD0:          break;
       case 0x10A0: /* IPI_IPVP */
       case 0x10B0:
       case 0x10C0:
       case 0x10D0:
         {          {
             int idx;              int idx;
             idx = (addr - 0xA0) >> 4;              idx = (addr - 0x10A0) >> 4;
             retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP);              retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx);
         }          }
         break;          break;
 #endif      case 0x10E0: /* SPVE */
     case 0xE0: /* SPVE */  
         retval = opp->spve;          retval = opp->spve;
         break;          break;
     case 0xF0: /* TIFR */      case 0x10F0: /* TIFR */
         retval = opp->tifr;          retval = opp->tifr;
         break;          break;
     default:      default:
Line 710  static void openpic_timer_write (void *o Line 728  static void openpic_timer_write (void *o
         opp->timers[idx].tibc = val;          opp->timers[idx].tibc = val;
         break;          break;
     case 0x20: /* TIVP */      case 0x20: /* TIVP */
         write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP, val);          write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val);
         break;          break;
     case 0x30: /* TIDE */      case 0x30: /* TIDE */
         write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE, val);          write_IRQreg_ide(opp, opp->irq_tim0 + idx, val);
         break;          break;
     }      }
 }  }
Line 740  static uint32_t openpic_timer_read (void Line 758  static uint32_t openpic_timer_read (void
         retval = opp->timers[idx].tibc;          retval = opp->timers[idx].tibc;
         break;          break;
     case 0x20: /* TIPV */      case 0x20: /* TIPV */
         retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP);          retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx);
         break;          break;
     case 0x30: /* TIDE */      case 0x30: /* TIDE */
         retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE);          retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx);
         break;          break;
     }      }
     DPRINTF("%s: => %08x\n", __func__, retval);      DPRINTF("%s: => %08x\n", __func__, retval);
Line 763  static void openpic_src_write (void *opa Line 781  static void openpic_src_write (void *opa
     idx = addr >> 5;      idx = addr >> 5;
     if (addr & 0x10) {      if (addr & 0x10) {
         /* EXDE / IFEDE / IEEDE */          /* EXDE / IFEDE / IEEDE */
         write_IRQreg(opp, idx, IRQ_IDE, val);          write_IRQreg_ide(opp, idx, val);
     } else {      } else {
         /* EXVP / IFEVP / IEEVP */          /* EXVP / IFEVP / IEEVP */
         write_IRQreg(opp, idx, IRQ_IPVP, val);          write_IRQreg_ipvp(opp, idx, val);
     }      }
 }  }
   
Line 784  static uint32_t openpic_src_read (void * Line 802  static uint32_t openpic_src_read (void *
     idx = addr >> 5;      idx = addr >> 5;
     if (addr & 0x10) {      if (addr & 0x10) {
         /* EXDE / IFEDE / IEEDE */          /* EXDE / IFEDE / IEEDE */
         retval = read_IRQreg(opp, idx, IRQ_IDE);          retval = read_IRQreg_ide(opp, idx);
     } else {      } else {
         /* EXVP / IFEVP / IEEVP */          /* EXVP / IFEVP / IEEVP */
         retval = read_IRQreg(opp, idx, IRQ_IPVP);          retval = read_IRQreg_ipvp(opp, idx);
     }      }
     DPRINTF("%s: => %08x\n", __func__, retval);      DPRINTF("%s: => %08x\n", __func__, retval);
   
     return retval;      return retval;
 }  }
   
 static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t val)  static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
                                          uint32_t val, int idx)
 {  {
     openpic_t *opp = opaque;      openpic_t *opp = opaque;
     IRQ_src_t *src;      IRQ_src_t *src;
     IRQ_dst_t *dst;      IRQ_dst_t *dst;
     int idx, s_IRQ, n_IRQ;      int s_IRQ, n_IRQ;
   
     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);      DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx,
               addr, val);
     if (addr & 0xF)      if (addr & 0xF)
         return;          return;
     addr &= 0x1FFF0;  
     idx = addr / 0x1000;  
     dst = &opp->dst[idx];      dst = &opp->dst[idx];
     addr &= 0xFF0;      addr &= 0xFF0;
     switch (addr) {      switch (addr) {
 #if MAX_IPI > 0  #if MAX_IPI > 0
     case 0x40: /* PIPD */      case 0x40: /* IPIDR */
     case 0x50:      case 0x50:
     case 0x60:      case 0x60:
     case 0x70:      case 0x70:
         idx = (addr - 0x40) >> 4;          idx = (addr - 0x40) >> 4;
         write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE, val);          /* we use IDE as mask which CPUs to deliver the IPI to still. */
           write_IRQreg_ide(opp, opp->irq_ipi0 + idx,
                            opp->src[opp->irq_ipi0 + idx].ide | val);
         openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);          openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
         openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);          openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
         break;          break;
Line 852  static void openpic_cpu_write (void *opa Line 872  static void openpic_cpu_write (void *opa
     }      }
 }  }
   
 static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr)  static void openpic_cpu_write(void *opaque, target_phys_addr_t addr, uint32_t val)
   {
       openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
   }
   
   static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
                                             int idx)
 {  {
     openpic_t *opp = opaque;      openpic_t *opp = opaque;
     IRQ_src_t *src;      IRQ_src_t *src;
     IRQ_dst_t *dst;      IRQ_dst_t *dst;
     uint32_t retval;      uint32_t retval;
     int idx, n_IRQ;      int n_IRQ;
   
     DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);      DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr);
     retval = 0xFFFFFFFF;      retval = 0xFFFFFFFF;
     if (addr & 0xF)      if (addr & 0xF)
         return retval;          return retval;
     addr &= 0x1FFF0;  
     idx = addr / 0x1000;  
     dst = &opp->dst[idx];      dst = &opp->dst[idx];
     addr &= 0xFF0;      addr &= 0xFF0;
     switch (addr) {      switch (addr) {
Line 905  static uint32_t openpic_cpu_read (void * Line 929  static uint32_t openpic_cpu_read (void *
                 reset_bit(&src->ipvp, IPVP_ACTIVITY);                  reset_bit(&src->ipvp, IPVP_ACTIVITY);
                 src->pending = 0;                  src->pending = 0;
             }              }
   
               if ((n_IRQ >= opp->irq_ipi0) &&  (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) {
                   src->ide &= ~(1 << idx);
                   if (src->ide && !test_bit(&src->ipvp, IPVP_SENSE)) {
                       /* trigger on CPUs that didn't know about it yet */
                       openpic_set_irq(opp, n_IRQ, 1);
                       openpic_set_irq(opp, n_IRQ, 0);
                       /* if all CPUs knew about it, set active bit again */
                       set_bit(&src->ipvp, IPVP_ACTIVITY);
                   }
               }
         }          }
         break;          break;
     case 0xB0: /* PEOI */      case 0xB0: /* PEOI */
         retval = 0;          retval = 0;
         break;          break;
 #if MAX_IPI > 0  
     case 0x40: /* IDE */  
     case 0x50:  
         idx = (addr - 0x40) >> 4;  
         retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE);  
         break;  
 #endif  
     default:      default:
         break;          break;
     }      }
Line 925  static uint32_t openpic_cpu_read (void * Line 953  static uint32_t openpic_cpu_read (void *
     return retval;      return retval;
 }  }
   
   static uint32_t openpic_cpu_read(void *opaque, target_phys_addr_t addr)
   {
       return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
   }
   
 static void openpic_buggy_write (void *opaque,  static void openpic_buggy_write (void *opaque,
                                  target_phys_addr_t addr, uint32_t val)                                   target_phys_addr_t addr, uint32_t val)
 {  {
Line 984  static uint32_t openpic_readl (void *opa Line 1017  static uint32_t openpic_readl (void *opa
     return retval;      return retval;
 }  }
   
 static CPUWriteMemoryFunc * const openpic_write[] = {  static uint64_t openpic_read(void *opaque, target_phys_addr_t addr,
     &openpic_buggy_write,                               unsigned size)
     &openpic_buggy_write,  {
     &openpic_writel,      openpic_t *opp = opaque;
 };  
   
 static CPUReadMemoryFunc * const openpic_read[] = {      switch (size) {
     &openpic_buggy_read,      case 4: return openpic_readl(opp, addr);
     &openpic_buggy_read,      default: return openpic_buggy_read(opp, addr);
     &openpic_readl,      }
 };  }
   
 static void openpic_map(PCIDevice *pci_dev, int region_num,  static void openpic_write(void *opaque, target_phys_addr_t addr,
                         pcibus_t addr, pcibus_t size, int type)                            uint64_t data, unsigned size)
 {  {
     openpic_t *opp;      openpic_t *opp = opaque;
   
     DPRINTF("Map OpenPIC\n");      switch (size) {
     opp = (openpic_t *)pci_dev;      case 4: return openpic_writel(opp, addr, data);
     /* Global registers */      default: return openpic_buggy_write(opp, addr, data);
     DPRINTF("Register OPENPIC gbl   %08x => %08x\n",      }
             addr + 0x1000, addr + 0x1000 + 0x100);  
     /* Timer registers */  
     DPRINTF("Register OPENPIC timer %08x => %08x\n",  
             addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);  
     /* Interrupt source registers */  
     DPRINTF("Register OPENPIC src   %08x => %08x\n",  
             addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2));  
     /* Per CPU registers */  
     DPRINTF("Register OPENPIC dst   %08x => %08x\n",  
             addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);  
     cpu_register_physical_memory(addr, 0x40000, opp->mem_index);  
 #if 0 // Don't implement ISU for now  
     opp_io_memory = cpu_register_io_memory(openpic_src_read,  
                                            openpic_src_write, NULL  
                                            DEVICE_NATIVE_ENDIAN);  
     cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),  
                                  opp_io_memory);  
 #endif  
 }  }
   
   static const MemoryRegionOps openpic_ops = {
       .read = openpic_read,
       .write = openpic_write,
       .endianness = DEVICE_LITTLE_ENDIAN,
   };
   
 static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)  static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
 {  {
     unsigned int i;      unsigned int i;
Line 1161  static void openpic_irq_raise(openpic_t  Line 1181  static void openpic_irq_raise(openpic_t 
     qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);      qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
 }  }
   
 qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,  qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
                         qemu_irq **irqs, qemu_irq irq_out)                          qemu_irq **irqs, qemu_irq irq_out)
 {  {
     openpic_t *opp;      openpic_t *opp;
Line 1180  qemu_irq *openpic_init (PCIBus *bus, int Line 1200  qemu_irq *openpic_init (PCIBus *bus, int
         pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?          pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
         pci_conf[0x3d] = 0x00; // no interrupt pin          pci_conf[0x3d] = 0x00; // no interrupt pin
   
           memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
   #if 0 // Don't implement ISU for now
           opp_io_memory = cpu_register_io_memory(openpic_src_read,
                                                  openpic_src_write, NULL
                                                  DEVICE_NATIVE_ENDIAN);
           cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
                                        opp_io_memory);
   #endif
   
         /* Register I/O spaces */          /* Register I/O spaces */
         pci_register_bar(&opp->pci_dev, 0, 0x40000,          pci_register_bar(&opp->pci_dev, 0,
                                PCI_BASE_ADDRESS_SPACE_MEMORY, &openpic_map);                           PCI_BASE_ADDRESS_SPACE_MEMORY, &opp->mem);
     } else {      } else {
         opp = qemu_mallocz(sizeof(openpic_t));          opp = g_malloc0(sizeof(openpic_t));
           memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
     }      }
     opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp,  
                                             DEVICE_LITTLE_ENDIAN);  
   
     //    isu_base &= 0xFFFC0000;      //    isu_base &= 0xFFFC0000;
     opp->nb_cpus = nb_cpus;      opp->nb_cpus = nb_cpus;
Line 1223  qemu_irq *openpic_init (PCIBus *bus, int Line 1251  qemu_irq *openpic_init (PCIBus *bus, int
     opp->irq_raise = openpic_irq_raise;      opp->irq_raise = openpic_irq_raise;
     opp->reset = openpic_reset;      opp->reset = openpic_reset;
   
     if (pmem_index)      if (pmem)
         *pmem_index = opp->mem_index;          *pmem = &opp->mem;
   
     return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);      return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
 }  }
Line 1248  static void mpic_reset (void *opaque) Line 1276  static void mpic_reset (void *opaque)
   
     mpp->glbc = 0x80000000;      mpp->glbc = 0x80000000;
     /* Initialise controller registers */      /* Initialise controller registers */
     mpp->frep = 0x004f0002;      mpp->frep = 0x004f0002 | ((mpp->nb_cpus - 1) << 8);
     mpp->veni = VENI;      mpp->veni = VENI;
     mpp->pint = 0x00000000;      mpp->pint = 0x00000000;
     mpp->spve = 0x0000FFFF;      mpp->spve = 0x0000FFFF;
Line 1257  static void mpic_reset (void *opaque) Line 1285  static void mpic_reset (void *opaque)
         mpp->src[i].ipvp = 0x80800000;          mpp->src[i].ipvp = 0x80800000;
         mpp->src[i].ide  = 0x00000001;          mpp->src[i].ide  = 0x00000001;
     }      }
       /* Set IDE for IPIs to 0 so we don't get spurious interrupts */
       for (i = mpp->irq_ipi0; i < (mpp->irq_ipi0 + MAX_IPI); i++) {
           mpp->src[i].ide = 0;
       }
     /* Initialise IRQ destinations */      /* Initialise IRQ destinations */
     for (i = 0; i < MAX_CPU; i++) {      for (i = 0; i < MAX_CPU; i++) {
         mpp->dst[i].pctp      = 0x0000000F;          mpp->dst[i].pctp      = 0x0000000F;
Line 1297  static void mpic_timer_write (void *opaq Line 1329  static void mpic_timer_write (void *opaq
         mpp->timers[idx].tibc = val;          mpp->timers[idx].tibc = val;
         break;          break;
     case 0x20: /* GTIVPR */      case 0x20: /* GTIVPR */
         write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP, val);          write_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx, val);
         break;          break;
     case 0x30: /* GTIDR & TFRR */      case 0x30: /* GTIDR & TFRR */
         if ((addr & 0xF0) == 0xF0)          if ((addr & 0xF0) == 0xF0)
             mpp->dst[cpu].tfrr = val;              mpp->dst[cpu].tfrr = val;
         else          else
             write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE, val);              write_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx, val);
         break;          break;
     }      }
 }  }
Line 1329  static uint32_t mpic_timer_read (void *o Line 1361  static uint32_t mpic_timer_read (void *o
         retval = mpp->timers[idx].tibc;          retval = mpp->timers[idx].tibc;
         break;          break;
     case 0x20: /* TIPV */      case 0x20: /* TIPV */
         retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP);          retval = read_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx);
         break;          break;
     case 0x30: /* TIDR */      case 0x30: /* TIDR */
         if ((addr &0xF0) == 0XF0)          if ((addr &0xF0) == 0XF0)
             retval = mpp->dst[cpu].tfrr;              retval = mpp->dst[cpu].tfrr;
         else          else
             retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE);              retval = read_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx);
         break;          break;
     }      }
     DPRINTF("%s: => %08x\n", __func__, retval);      DPRINTF("%s: => %08x\n", __func__, retval);
Line 1358  static void mpic_src_ext_write (void *op Line 1390  static void mpic_src_ext_write (void *op
         idx += (addr & 0xFFF0) >> 5;          idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {          if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */              /* EXDE / IFEDE / IEEDE */
             write_IRQreg(mpp, idx, IRQ_IDE, val);              write_IRQreg_ide(mpp, idx, val);
         } else {          } else {
             /* EXVP / IFEVP / IEEVP */              /* EXVP / IFEVP / IEEVP */
             write_IRQreg(mpp, idx, IRQ_IPVP, val);              write_IRQreg_ipvp(mpp, idx, val);
         }          }
     }      }
 }  }
Line 1382  static uint32_t mpic_src_ext_read (void  Line 1414  static uint32_t mpic_src_ext_read (void 
         idx += (addr & 0xFFF0) >> 5;          idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {          if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */              /* EXDE / IFEDE / IEEDE */
             retval = read_IRQreg(mpp, idx, IRQ_IDE);              retval = read_IRQreg_ide(mpp, idx);
         } else {          } else {
             /* EXVP / IFEVP / IEEVP */              /* EXVP / IFEVP / IEEVP */
             retval = read_IRQreg(mpp, idx, IRQ_IPVP);              retval = read_IRQreg_ipvp(mpp, idx);
         }          }
         DPRINTF("%s: => %08x\n", __func__, retval);          DPRINTF("%s: => %08x\n", __func__, retval);
     }      }
Line 1408  static void mpic_src_int_write (void *op Line 1440  static void mpic_src_int_write (void *op
         idx += (addr & 0xFFF0) >> 5;          idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {          if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */              /* EXDE / IFEDE / IEEDE */
             write_IRQreg(mpp, idx, IRQ_IDE, val);              write_IRQreg_ide(mpp, idx, val);
         } else {          } else {
             /* EXVP / IFEVP / IEEVP */              /* EXVP / IFEVP / IEEVP */
             write_IRQreg(mpp, idx, IRQ_IPVP, val);              write_IRQreg_ipvp(mpp, idx, val);
         }          }
     }      }
 }  }
Line 1432  static uint32_t mpic_src_int_read (void  Line 1464  static uint32_t mpic_src_int_read (void 
         idx += (addr & 0xFFF0) >> 5;          idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {          if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */              /* EXDE / IFEDE / IEEDE */
             retval = read_IRQreg(mpp, idx, IRQ_IDE);              retval = read_IRQreg_ide(mpp, idx);
         } else {          } else {
             /* EXVP / IFEVP / IEEVP */              /* EXVP / IFEVP / IEEVP */
             retval = read_IRQreg(mpp, idx, IRQ_IPVP);              retval = read_IRQreg_ipvp(mpp, idx);
         }          }
         DPRINTF("%s: => %08x\n", __func__, retval);          DPRINTF("%s: => %08x\n", __func__, retval);
     }      }
Line 1458  static void mpic_src_msg_write (void *op Line 1490  static void mpic_src_msg_write (void *op
         idx += (addr & 0xFFF0) >> 5;          idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {          if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */              /* EXDE / IFEDE / IEEDE */
             write_IRQreg(mpp, idx, IRQ_IDE, val);              write_IRQreg_ide(mpp, idx, val);
         } else {          } else {
             /* EXVP / IFEVP / IEEVP */              /* EXVP / IFEVP / IEEVP */
             write_IRQreg(mpp, idx, IRQ_IPVP, val);              write_IRQreg_ipvp(mpp, idx, val);
         }          }
     }      }
 }  }
Line 1482  static uint32_t mpic_src_msg_read (void  Line 1514  static uint32_t mpic_src_msg_read (void 
         idx += (addr & 0xFFF0) >> 5;          idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {          if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */              /* EXDE / IFEDE / IEEDE */
             retval = read_IRQreg(mpp, idx, IRQ_IDE);              retval = read_IRQreg_ide(mpp, idx);
         } else {          } else {
             /* EXVP / IFEVP / IEEVP */              /* EXVP / IFEVP / IEEVP */
             retval = read_IRQreg(mpp, idx, IRQ_IPVP);              retval = read_IRQreg_ipvp(mpp, idx);
         }          }
         DPRINTF("%s: => %08x\n", __func__, retval);          DPRINTF("%s: => %08x\n", __func__, retval);
     }      }
Line 1508  static void mpic_src_msi_write (void *op Line 1540  static void mpic_src_msi_write (void *op
         idx += (addr & 0xFFF0) >> 5;          idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {          if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */              /* EXDE / IFEDE / IEEDE */
             write_IRQreg(mpp, idx, IRQ_IDE, val);              write_IRQreg_ide(mpp, idx, val);
         } else {          } else {
             /* EXVP / IFEVP / IEEVP */              /* EXVP / IFEVP / IEEVP */
             write_IRQreg(mpp, idx, IRQ_IPVP, val);              write_IRQreg_ipvp(mpp, idx, val);
         }          }
     }      }
 }  }
Line 1531  static uint32_t mpic_src_msi_read (void  Line 1563  static uint32_t mpic_src_msi_read (void 
         idx += (addr & 0xFFF0) >> 5;          idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {          if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */              /* EXDE / IFEDE / IEEDE */
             retval = read_IRQreg(mpp, idx, IRQ_IDE);              retval = read_IRQreg_ide(mpp, idx);
         } else {          } else {
             /* EXVP / IFEVP / IEEVP */              /* EXVP / IFEVP / IEEVP */
             retval = read_IRQreg(mpp, idx, IRQ_IPVP);              retval = read_IRQreg_ipvp(mpp, idx);
         }          }
         DPRINTF("%s: => %08x\n", __func__, retval);          DPRINTF("%s: => %08x\n", __func__, retval);
     }      }
Line 1542  static uint32_t mpic_src_msi_read (void  Line 1574  static uint32_t mpic_src_msi_read (void 
     return retval;      return retval;
 }  }
   
 static CPUWriteMemoryFunc * const mpic_glb_write[] = {  static const MemoryRegionOps mpic_glb_ops = {
     &openpic_buggy_write,      .old_mmio = {
     &openpic_buggy_write,          .write = { openpic_buggy_write,
     &openpic_gbl_write,                     openpic_buggy_write,
 };                     openpic_gbl_write,
           },
 static CPUReadMemoryFunc * const mpic_glb_read[] = {          .read  = { openpic_buggy_read,
     &openpic_buggy_read,                     openpic_buggy_read,
     &openpic_buggy_read,                     openpic_gbl_read,
     &openpic_gbl_read,          },
 };      },
       .endianness = DEVICE_BIG_ENDIAN,
 static CPUWriteMemoryFunc * const mpic_tmr_write[] = {  
     &openpic_buggy_write,  
     &openpic_buggy_write,  
     &mpic_timer_write,  
 };  
   
 static CPUReadMemoryFunc * const mpic_tmr_read[] = {  
     &openpic_buggy_read,  
     &openpic_buggy_read,  
     &mpic_timer_read,  
 };  
   
 static CPUWriteMemoryFunc * const mpic_cpu_write[] = {  
     &openpic_buggy_write,  
     &openpic_buggy_write,  
     &openpic_cpu_write,  
 };  
   
 static CPUReadMemoryFunc * const mpic_cpu_read[] = {  
     &openpic_buggy_read,  
     &openpic_buggy_read,  
     &openpic_cpu_read,  
 };  };
   
 static CPUWriteMemoryFunc * const mpic_ext_write[] = {  static const MemoryRegionOps mpic_tmr_ops = {
     &openpic_buggy_write,      .old_mmio = {
     &openpic_buggy_write,          .write = { openpic_buggy_write,
     &mpic_src_ext_write,                     openpic_buggy_write,
                      mpic_timer_write,
           },
           .read  = { openpic_buggy_read,
                      openpic_buggy_read,
                      mpic_timer_read,
           },
       },
       .endianness = DEVICE_BIG_ENDIAN,
 };  };
   
 static CPUReadMemoryFunc * const mpic_ext_read[] = {  static const MemoryRegionOps mpic_cpu_ops = {
     &openpic_buggy_read,      .old_mmio = {
     &openpic_buggy_read,          .write = { openpic_buggy_write,
     &mpic_src_ext_read,                     openpic_buggy_write,
                      openpic_cpu_write,
           },
           .read  = { openpic_buggy_read,
                      openpic_buggy_read,
                      openpic_cpu_read,
           },
       },
       .endianness = DEVICE_BIG_ENDIAN,
 };  };
   
 static CPUWriteMemoryFunc * const mpic_int_write[] = {  static const MemoryRegionOps mpic_ext_ops = {
     &openpic_buggy_write,      .old_mmio = {
     &openpic_buggy_write,          .write = { openpic_buggy_write,
     &mpic_src_int_write,                     openpic_buggy_write,
                      mpic_src_ext_write,
           },
           .read  = { openpic_buggy_read,
                      openpic_buggy_read,
                      mpic_src_ext_read,
           },
       },
       .endianness = DEVICE_BIG_ENDIAN,
 };  };
   
 static CPUReadMemoryFunc * const mpic_int_read[] = {  static const MemoryRegionOps mpic_int_ops = {
     &openpic_buggy_read,      .old_mmio = {
     &openpic_buggy_read,          .write = { openpic_buggy_write,
     &mpic_src_int_read,                     openpic_buggy_write,
                      mpic_src_int_write,
           },
           .read  = { openpic_buggy_read,
                      openpic_buggy_read,
                      mpic_src_int_read,
           },
       },
       .endianness = DEVICE_BIG_ENDIAN,
 };  };
   
 static CPUWriteMemoryFunc * const mpic_msg_write[] = {  static const MemoryRegionOps mpic_msg_ops = {
     &openpic_buggy_write,      .old_mmio = {
     &openpic_buggy_write,          .write = { openpic_buggy_write,
     &mpic_src_msg_write,                     openpic_buggy_write,
                      mpic_src_msg_write,
           },
           .read  = { openpic_buggy_read,
                      openpic_buggy_read,
                      mpic_src_msg_read,
           },
       },
       .endianness = DEVICE_BIG_ENDIAN,
 };  };
   
 static CPUReadMemoryFunc * const mpic_msg_read[] = {  static const MemoryRegionOps mpic_msi_ops = {
     &openpic_buggy_read,      .old_mmio = {
     &openpic_buggy_read,          .write = { openpic_buggy_write,
     &mpic_src_msg_read,                     openpic_buggy_write,
 };                     mpic_src_msi_write,
 static CPUWriteMemoryFunc * const mpic_msi_write[] = {          },
     &openpic_buggy_write,          .read  = { openpic_buggy_read,
     &openpic_buggy_write,                     openpic_buggy_read,
     &mpic_src_msi_write,                     mpic_src_msi_read,
 };          },
       },
 static CPUReadMemoryFunc * const mpic_msi_read[] = {      .endianness = DEVICE_BIG_ENDIAN,
     &openpic_buggy_read,  
     &openpic_buggy_read,  
     &mpic_src_msi_read,  
 };  };
   
 qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,  qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base,
                         qemu_irq **irqs, qemu_irq irq_out)                       int nb_cpus, qemu_irq **irqs, qemu_irq irq_out)
 {  {
     openpic_t *mpp;      openpic_t    *mpp;
     int i;      int           i;
     struct {      struct {
         CPUReadMemoryFunc * const *read;          const char             *name;
         CPUWriteMemoryFunc * const *write;          MemoryRegionOps const  *ops;
         target_phys_addr_t start_addr;          target_phys_addr_t      start_addr;
         ram_addr_t size;          ram_addr_t              size;
     } const list[] = {      } const list[] = {
         {mpic_glb_read, mpic_glb_write, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},          {"glb", &mpic_glb_ops, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
         {mpic_tmr_read, mpic_tmr_write, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},          {"tmr", &mpic_tmr_ops, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
         {mpic_ext_read, mpic_ext_write, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},          {"ext", &mpic_ext_ops, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
         {mpic_int_read, mpic_int_write, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},          {"int", &mpic_int_ops, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
         {mpic_msg_read, mpic_msg_write, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},          {"msg", &mpic_msg_ops, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
         {mpic_msi_read, mpic_msi_write, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},          {"msi", &mpic_msi_ops, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
         {mpic_cpu_read, mpic_cpu_write, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},          {"cpu", &mpic_cpu_ops, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
     };      };
   
     /* XXX: for now, only one CPU is supported */      mpp = g_malloc0(sizeof(openpic_t));
     if (nb_cpus != 1)  
         return NULL;  
   
     mpp = qemu_mallocz(sizeof(openpic_t));      memory_region_init(&mpp->mem, "mpic", 0x40000);
       memory_region_add_subregion(address_space, base, &mpp->mem);
   
     for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {      for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
         int mem_index;  
   
         mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp,          memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp,
                                            DEVICE_BIG_ENDIAN);                                list[i].name, list[i].size);
         if (mem_index < 0) {  
             goto free;          memory_region_add_subregion(&mpp->mem, list[i].start_addr,
         }                                      &mpp->sub_io_mem[i]);
         cpu_register_physical_memory(base + list[i].start_addr,  
                                      list[i].size, mem_index);  
     }      }
   
     mpp->nb_cpus = nb_cpus;      mpp->nb_cpus = nb_cpus;
Line 1679  qemu_irq *mpic_init (target_phys_addr_t  Line 1722  qemu_irq *mpic_init (target_phys_addr_t 
     qemu_register_reset(mpic_reset, mpp);      qemu_register_reset(mpic_reset, mpp);
   
     return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);      return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
   
 free:  
     qemu_free(mpp);  
     return NULL;  
 }  }

Removed from v.1.1.1.8  
changed lines
  Added in v.1.1.1.9


unix.superglobalmegacorp.com