summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--hw/misc/macio/mac_dbdma.c125
-rw-r--r--hw/ppc/spapr_cpu_core.c27
-rw-r--r--hw/vfio/spapr.c1
-rw-r--r--target-ppc/helper_regs.h46
-rw-r--r--target-ppc/kvm.c10
-rw-r--r--target-ppc/mmu-hash64.c3
-rw-r--r--target-ppc/translate_init.c4
7 files changed, 119 insertions, 97 deletions
diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c
index f116f9c36d..15452b9a28 100644
--- a/hw/misc/macio/mac_dbdma.c
+++ b/hw/misc/macio/mac_dbdma.c
@@ -45,14 +45,22 @@
 #include "sysemu/dma.h"
 
 /* debug DBDMA */
-//#define DEBUG_DBDMA
-
-#ifdef DEBUG_DBDMA
-#define DBDMA_DPRINTF(fmt, ...)                                 \
-    do { printf("DBDMA: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DBDMA_DPRINTF(fmt, ...)
-#endif
+#define DEBUG_DBDMA 0
+#define DEBUG_DBDMA_CHANMASK ((1ull << DBDMA_CHANNELS) - 1)
+
+#define DBDMA_DPRINTF(fmt, ...) do { \
+    if (DEBUG_DBDMA) { \
+        printf("DBDMA: " fmt , ## __VA_ARGS__); \
+    } \
+} while (0);
+
+#define DBDMA_DPRINTFCH(ch, fmt, ...) do { \
+    if (DEBUG_DBDMA) { \
+        if ((1ul << (ch)->channel) & DEBUG_DBDMA_CHANMASK) { \
+            printf("DBDMA[%02x]: " fmt , (ch)->channel, ## __VA_ARGS__); \
+        } \
+    } \
+} while (0);
 
 /*
  */
@@ -62,7 +70,7 @@ static DBDMAState *dbdma_from_ch(DBDMA_channel *ch)
     return container_of(ch, DBDMAState, channels[ch->channel]);
 }
 
-#ifdef DEBUG_DBDMA
+#if DEBUG_DBDMA
 static void dump_dbdma_cmd(dbdma_cmd *cmd)
 {
     printf("dbdma_cmd %p\n", cmd);
@@ -80,26 +88,26 @@ static void dump_dbdma_cmd(dbdma_cmd *cmd)
 #endif
 static void dbdma_cmdptr_load(DBDMA_channel *ch)
 {
-    DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n",
-                  ch->regs[DBDMA_CMDPTR_LO]);
+    DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_load 0x%08x\n",
+                    ch->regs[DBDMA_CMDPTR_LO]);
     dma_memory_read(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO],
                     &ch->current, sizeof(dbdma_cmd));
 }
 
 static void dbdma_cmdptr_save(DBDMA_channel *ch)
 {
-    DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n",
-                  ch->regs[DBDMA_CMDPTR_LO]);
-    DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n",
-                  le16_to_cpu(ch->current.xfer_status),
-                  le16_to_cpu(ch->current.res_count));
+    DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_save 0x%08x\n",
+                    ch->regs[DBDMA_CMDPTR_LO]);
+    DBDMA_DPRINTFCH(ch, "xfer_status 0x%08x res_count 0x%04x\n",
+                    le16_to_cpu(ch->current.xfer_status),
+                    le16_to_cpu(ch->current.res_count));
     dma_memory_write(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO],
                      &ch->current, sizeof(dbdma_cmd));
 }
 
 static void kill_channel(DBDMA_channel *ch)
 {
-    DBDMA_DPRINTF("kill_channel\n");
+    DBDMA_DPRINTFCH(ch, "kill_channel\n");
 
     ch->regs[DBDMA_STATUS] |= DEAD;
     ch->regs[DBDMA_STATUS] &= ~ACTIVE;
@@ -115,7 +123,7 @@ static void conditional_interrupt(DBDMA_channel *ch)
     uint32_t status;
     int cond;
 
-    DBDMA_DPRINTF("%s\n", __func__);
+    DBDMA_DPRINTFCH(ch, "%s\n", __func__);
 
     intr = le16_to_cpu(current->command) & INTR_MASK;
 
@@ -124,7 +132,7 @@ static void conditional_interrupt(DBDMA_channel *ch)
         return;
     case INTR_ALWAYS: /* always interrupt */
         qemu_irq_raise(ch->irq);
-        DBDMA_DPRINTF("%s: raise\n", __func__);
+        DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__);
         return;
     }
 
@@ -139,13 +147,13 @@ static void conditional_interrupt(DBDMA_channel *ch)
     case INTR_IFSET:  /* intr if condition bit is 1 */
         if (cond) {
             qemu_irq_raise(ch->irq);
-            DBDMA_DPRINTF("%s: raise\n", __func__);
+            DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__);
         }
         return;
     case INTR_IFCLR:  /* intr if condition bit is 0 */
         if (!cond) {
             qemu_irq_raise(ch->irq);
-            DBDMA_DPRINTF("%s: raise\n", __func__);
+            DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__);
         }
         return;
     }
@@ -159,7 +167,7 @@ static int conditional_wait(DBDMA_channel *ch)
     uint32_t status;
     int cond;
 
-    DBDMA_DPRINTF("conditional_wait\n");
+    DBDMA_DPRINTFCH(ch, "conditional_wait\n");
 
     wait = le16_to_cpu(current->command) & WAIT_MASK;
 
@@ -205,7 +213,7 @@ static void branch(DBDMA_channel *ch)
 {
     dbdma_cmd *current = &ch->current;
 
-    ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep;
+    ch->regs[DBDMA_CMDPTR_LO] = le32_to_cpu(current->cmd_dep);
     ch->regs[DBDMA_STATUS] |= BT;
     dbdma_cmdptr_load(ch);
 }
@@ -218,7 +226,7 @@ static void conditional_branch(DBDMA_channel *ch)
     uint32_t status;
     int cond;
 
-    DBDMA_DPRINTF("conditional_branch\n");
+    DBDMA_DPRINTFCH(ch, "conditional_branch\n");
 
     /* check if we must branch */
 
@@ -263,7 +271,7 @@ static void dbdma_end(DBDMA_io *io)
     DBDMA_channel *ch = io->channel;
     dbdma_cmd *current = &ch->current;
 
-    DBDMA_DPRINTF("%s\n", __func__);
+    DBDMA_DPRINTFCH(ch, "%s\n", __func__);
 
     if (conditional_wait(ch))
         goto wait;
@@ -289,13 +297,13 @@ wait:
 static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
                         uint16_t req_count, int is_last)
 {
-    DBDMA_DPRINTF("start_output\n");
+    DBDMA_DPRINTFCH(ch, "start_output\n");
 
     /* KEY_REGS, KEY_DEVICE and KEY_STREAM
      * are not implemented in the mac-io chip
      */
 
-    DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
+    DBDMA_DPRINTFCH(ch, "addr 0x%x key 0x%x\n", addr, key);
     if (!addr || key > KEY_STREAM3) {
         kill_channel(ch);
         return;
@@ -315,13 +323,13 @@ static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
 static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
                        uint16_t req_count, int is_last)
 {
-    DBDMA_DPRINTF("start_input\n");
+    DBDMA_DPRINTFCH(ch, "start_input\n");
 
     /* KEY_REGS, KEY_DEVICE and KEY_STREAM
      * are not implemented in the mac-io chip
      */
 
-    DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
+    DBDMA_DPRINTFCH(ch, "addr 0x%x key 0x%x\n", addr, key);
     if (!addr || key > KEY_STREAM3) {
         kill_channel(ch);
         return;
@@ -342,9 +350,8 @@ static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
                      uint16_t len)
 {
     dbdma_cmd *current = &ch->current;
-    uint32_t val;
 
-    DBDMA_DPRINTF("load_word\n");
+    DBDMA_DPRINTFCH(ch, "load_word %d bytes, addr=%08x\n", len, addr);
 
     /* only implements KEY_SYSTEM */
 
@@ -354,14 +361,7 @@ static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
         return;
     }
 
-    dma_memory_read(&address_space_memory, addr, &val, len);
-
-    if (len == 2)
-        val = (val << 16) | (current->cmd_dep & 0x0000ffff);
-    else if (len == 1)
-        val = (val << 24) | (current->cmd_dep & 0x00ffffff);
-
-    current->cmd_dep = val;
+    dma_memory_read(&address_space_memory, addr, &current->cmd_dep, len);
 
     if (conditional_wait(ch))
         goto wait;
@@ -381,9 +381,9 @@ static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
                       uint16_t len)
 {
     dbdma_cmd *current = &ch->current;
-    uint32_t val;
 
-    DBDMA_DPRINTF("store_word\n");
+    DBDMA_DPRINTFCH(ch, "store_word %d bytes, addr=%08x pa=%x\n",
+                    len, addr, le32_to_cpu(current->cmd_dep));
 
     /* only implements KEY_SYSTEM */
 
@@ -393,13 +393,7 @@ static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
         return;
     }
 
-    val = current->cmd_dep;
-    if (len == 2)
-        val >>= 16;
-    else if (len == 1)
-        val >>= 24;
-
-    dma_memory_write(&address_space_memory, addr, &val, len);
+    dma_memory_write(&address_space_memory, addr, &current->cmd_dep, len);
 
     if (conditional_wait(ch))
         goto wait;
@@ -446,7 +440,7 @@ static void channel_run(DBDMA_channel *ch)
     uint16_t req_count;
     uint32_t phy_addr;
 
-    DBDMA_DPRINTF("channel_run\n");
+    DBDMA_DPRINTFCH(ch, "channel_run\n");
     dump_dbdma_cmd(current);
 
     /* clear WAKE flag at command fetch */
@@ -540,9 +534,9 @@ static void DBDMA_run_bh(void *opaque)
 {
     DBDMAState *s = opaque;
 
-    DBDMA_DPRINTF("DBDMA_run_bh\n");
-
+    DBDMA_DPRINTF("-> DBDMA_run_bh\n");
     DBDMA_run(s);
+    DBDMA_DPRINTF("<- DBDMA_run_bh\n");
 }
 
 void DBDMA_kick(DBDMAState *dbdma)
@@ -557,7 +551,7 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
     DBDMAState *s = dbdma;
     DBDMA_channel *ch = &s->channels[nchan];
 
-    DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
+    DBDMA_DPRINTFCH(ch, "DBDMA_register_channel 0x%x\n", nchan);
 
     assert(rw);
     assert(flush);
@@ -601,7 +595,7 @@ dbdma_control_write(DBDMA_channel *ch)
         status &= ~FLUSH;
     }
 
-    DBDMA_DPRINTF("    status 0x%08x\n", status);
+    DBDMA_DPRINTFCH(ch, "    status 0x%08x\n", status);
 
     ch->regs[DBDMA_STATUS] = status;
 
@@ -618,10 +612,10 @@ static void dbdma_write(void *opaque, hwaddr addr,
     DBDMA_channel *ch = &s->channels[channel];
     int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
 
-    DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n",
-                  addr, value);
-    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
-                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
+    DBDMA_DPRINTFCH(ch, "writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n",
+                    addr, value);
+    DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n",
+                    (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
 
     /* cmdptr cannot be modified if channel is ACTIVE */
 
@@ -672,9 +666,9 @@ static uint64_t dbdma_read(void *opaque, hwaddr addr,
 
     value = ch->regs[reg];
 
-    DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
-    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
-                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
+    DBDMA_DPRINTFCH(ch, "readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
+    DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n",
+                    (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
 
     switch(reg) {
     case DBDMA_CONTROL:
@@ -784,13 +778,24 @@ static void dbdma_unassigned_rw(DBDMA_io *io)
     DBDMA_channel *ch = io->channel;
     qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
                   __func__, ch->channel);
+    ch->io.processing = false;
 }
 
 static void dbdma_unassigned_flush(DBDMA_io *io)
 {
     DBDMA_channel *ch = io->channel;
+    dbdma_cmd *current = &ch->current;
+    uint16_t cmd;
     qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
                   __func__, ch->channel);
+
+    cmd = le16_to_cpu(current->command) & COMMAND_MASK;
+    if (cmd == OUTPUT_MORE || cmd == OUTPUT_LAST ||
+        cmd == INPUT_MORE || cmd == INPUT_LAST) {
+        current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS] | FLUSH);
+        current->res_count = cpu_to_le16(io->len);
+        dbdma_cmdptr_save(ch);
+    }
 }
 
 void* DBDMA_init (MemoryRegion **dbdma_mem)
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 9347f0741e..4bfc96bd5a 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -126,14 +126,23 @@ static void spapr_core_release(DeviceState *dev, void *opaque)
 void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
                        Error **errp)
 {
-    sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
-    PowerPCCPU *cpu = POWERPC_CPU(core->threads);
-    int id = ppc_get_vcpu_dt_id(cpu);
+    sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+    CPUCore *cc = CPU_CORE(dev);
     sPAPRDRConnector *drc =
-        spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, id);
+        spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, cc->core_id);
     sPAPRDRConnectorClass *drck;
     Error *local_err = NULL;
+    int smt = kvmppc_smt_threads();
+    int index = cc->core_id / smt;
+    int spapr_max_cores = max_cpus / smp_threads;
+    int i;
 
+    for (i = spapr_max_cores - 1; i > index; i--) {
+        if (spapr->cores[i]) {
+            error_setg(errp, "core-id %d should be removed first", i * smt);
+            return;
+        }
+    }
     g_assert(drc);
 
     drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
@@ -216,7 +225,7 @@ void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(OBJECT(hotplug_dev));
     sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
     int spapr_max_cores = max_cpus / smp_threads;
-    int index;
+    int index, i;
     int smt = kvmppc_smt_threads();
     Error *local_err = NULL;
     CPUCore *cc = CPU_CORE(dev);
@@ -254,6 +263,14 @@ void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
         goto out;
     }
 
+    for (i = 0; i < index; i++) {
+        if (!spapr->cores[i]) {
+            error_setg(&local_err, "core-id %d should be added first",
+                       i * smt);
+            goto out;
+        }
+    }
+
 out:
     g_free(base_core_type);
     error_propagate(errp, local_err);
diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c
index 0af342332c..7443d348d9 100644
--- a/hw/vfio/spapr.c
+++ b/hw/vfio/spapr.c
@@ -177,7 +177,6 @@ int vfio_spapr_create_window(VFIOContainer *container,
         error_report("Host doesn't support DMA window at %"HWADDR_PRIx", must be %"PRIx64,
                      section->offset_within_address_space,
                      (uint64_t)create.start_addr);
-        ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_REMOVE, &remove);
         return -EINVAL;
     }
     trace_vfio_spapr_create_window(create.page_shift,
diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h
index 8d38828936..3d279f1d8a 100644
--- a/target-ppc/helper_regs.h
+++ b/target-ppc/helper_regs.h
@@ -41,17 +41,19 @@ static inline void hreg_swap_gpr_tgpr(CPUPPCState *env)
 
 static inline void hreg_compute_mem_idx(CPUPPCState *env)
 {
-    /* This is our encoding for server processors
+    /* This is our encoding for server processors. The architecture
+     * specifies that there is no such thing as userspace with
+     * translation off, however it appears that MacOS does it and
+     * some 32-bit CPUs support it. Weird...
      *
      *   0 = Guest User space virtual mode
      *   1 = Guest Kernel space virtual mode
-     *   2 = Guest Kernel space real mode
-     *   3 = HV User space virtual mode
-     *   4 = HV Kernel space virtual mode
-     *   5 = HV Kernel space real mode
-     *
-     * The combination PR=1 IR&DR=0 is invalid, we will treat
-     * it as IR=DR=1
+     *   2 = Guest User space real mode
+     *   3 = Guest Kernel space real mode
+     *   4 = HV User space virtual mode
+     *   5 = HV Kernel space virtual mode
+     *   6 = HV User space real mode
+     *   7 = HV Kernel space real mode
      *
      * For BookE, we need 8 MMU modes as follow:
      *
@@ -71,20 +73,11 @@ static inline void hreg_compute_mem_idx(CPUPPCState *env)
         env->immu_idx += msr_gs ? 4 : 0;
         env->dmmu_idx += msr_gs ? 4 : 0;
     } else {
-        /* First calucalte a base value independent of HV */
-        if (msr_pr != 0) {
-            /* User space, ignore IR and DR */
-            env->immu_idx = env->dmmu_idx = 0;
-        } else {
-            /* Kernel, setup a base I/D value */
-            env->immu_idx = msr_ir ? 1 : 2;
-            env->dmmu_idx = msr_dr ? 1 : 2;
-        }
-        /* Then offset it for HV */
-        if (msr_hv) {
-            env->immu_idx += 3;
-            env->dmmu_idx += 3;
-        }
+        env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1;
+        env->immu_idx += msr_ir ? 0 : 2;
+        env->dmmu_idx += msr_dr ? 0 : 2;
+        env->immu_idx += msr_hv ? 4 : 0;
+        env->dmmu_idx += msr_hv ? 4 : 0;
     }
 }
 
@@ -136,8 +129,13 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
         /* Change the exception prefix on PowerPC 601 */
         env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000;
     }
-    /* If PR=1 then EE, IR and DR must be 1 */
-    if ((value >> MSR_PR) & 1) {
+    /* If PR=1 then EE, IR and DR must be 1
+     *
+     * Note: We only enforce this on 64-bit processors. It appears that
+     * 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS
+     * exploits it.
+     */
+    if ((env->insns_flags & PPC_64B) && ((value >> MSR_PR) & 1)) {
         value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR);
     }
 #endif
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 884d564e0f..7a8f5559d9 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -389,12 +389,16 @@ static long getrampagesize(void)
 
     object_child_foreach(memdev_root, find_max_supported_pagesize, &hpsize);
 
-    if (hpsize == LONG_MAX) {
+    if (hpsize == LONG_MAX || hpsize == getpagesize()) {
         return getpagesize();
     }
 
-    if (nb_numa_nodes == 0 && hpsize > getpagesize()) {
-        /* No NUMA nodes and normal RAM without -mem-path ==> no huge pages! */
+    /* If NUMA is disabled or the NUMA nodes are not backed with a
+     * memory-backend, then there is at least one node using "normal"
+     * RAM. And since normal RAM has not been configured with "-mem-path"
+     * (what we've checked earlier here already), we can not use huge pages!
+     */
+    if (nb_numa_nodes == 0 || numa_info[0].node_memdev == NULL) {
         static bool warned;
         if (!warned) {
             error_report("Huge page support disabled (n/a for main memory).");
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 82c2186bcf..5de1358d1c 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -24,7 +24,6 @@
 #include "exec/helper-proto.h"
 #include "qemu/error-report.h"
 #include "sysemu/kvm.h"
-#include "qemu/error-report.h"
 #include "kvm_ppc.h"
 #include "mmu-hash64.h"
 #include "exec/log.h"
@@ -479,7 +478,7 @@ static unsigned hpte_page_shift(const struct ppc_one_seg_page_size *sps,
 
         mask = ((1ULL << ps->page_shift) - 1) & HPTE64_R_RPN;
 
-        if ((pte1 & mask) == (ps->pte_enc << HPTE64_R_RPN_SHIFT)) {
+        if ((pte1 & mask) == ((uint64_t)ps->pte_enc << HPTE64_R_RPN_SHIFT)) {
             return ps->page_shift;
         }
     }
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 7cb784262c..5ecafc7b8b 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8446,8 +8446,8 @@ static void powerpc_get_compat(Object *obj, Visitor *v, const char *name,
     case 0:
         break;
     default:
-        error_setg(errp, "Internal error: compat is set to %x",
-                   max_compat ? *max_compat : -1);
+        error_report("Internal error: compat is set to %x", *max_compat);
+        abort();
         break;
     }