Annotation of qemu/hw/ppc.c, revision 1.1.1.4

1.1       root        1: /*
1.1.1.4 ! root        2:  * QEMU generic PowerPC hardware System Emulator
        !             3:  *
        !             4:  * Copyright (c) 2003-2007 Jocelyn Mayer
        !             5:  *
1.1       root        6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
1.1.1.4 ! root       24: #include "hw.h"
        !            25: #include "ppc.h"
        !            26: #include "qemu-timer.h"
        !            27: #include "sysemu.h"
        !            28: #include "nvram.h"
        !            29: 
        !            30: //#define PPC_DEBUG_IRQ
        !            31: //#define PPC_DEBUG_TB
        !            32: 
        !            33: extern FILE *logfile;
        !            34: extern int loglevel;
        !            35: 
        !            36: static void cpu_ppc_tb_stop (CPUState *env);
        !            37: static void cpu_ppc_tb_start (CPUState *env);
        !            38: 
        !            39: static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
        !            40: {
        !            41:     if (level) {
        !            42:         env->pending_interrupts |= 1 << n_IRQ;
        !            43:         cpu_interrupt(env, CPU_INTERRUPT_HARD);
        !            44:     } else {
        !            45:         env->pending_interrupts &= ~(1 << n_IRQ);
        !            46:         if (env->pending_interrupts == 0)
        !            47:             cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
        !            48:     }
        !            49: #if defined(PPC_DEBUG_IRQ)
        !            50:     if (loglevel & CPU_LOG_INT) {
        !            51:         fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08" PRIx32
        !            52:                 "req %08x\n", __func__, env, n_IRQ, level,
        !            53:                 env->pending_interrupts, env->interrupt_request);
        !            54:     }
        !            55: #endif
        !            56: }
1.1       root       57: 
1.1.1.4 ! root       58: /* PowerPC 6xx / 7xx internal IRQ controller */
        !            59: static void ppc6xx_set_irq (void *opaque, int pin, int level)
        !            60: {
        !            61:     CPUState *env = opaque;
        !            62:     int cur_level;
        !            63: 
        !            64: #if defined(PPC_DEBUG_IRQ)
        !            65:     if (loglevel & CPU_LOG_INT) {
        !            66:         fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
        !            67:                 env, pin, level);
        !            68:     }
        !            69: #endif
        !            70:     cur_level = (env->irq_input_state >> pin) & 1;
        !            71:     /* Don't generate spurious events */
        !            72:     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
        !            73:         switch (pin) {
        !            74:         case PPC6xx_INPUT_TBEN:
        !            75:             /* Level sensitive - active high */
        !            76: #if defined(PPC_DEBUG_IRQ)
        !            77:             if (loglevel & CPU_LOG_INT) {
        !            78:                 fprintf(logfile, "%s: %s the time base\n",
        !            79:                         __func__, level ? "start" : "stop");
        !            80:             }
        !            81: #endif
        !            82:             if (level) {
        !            83:                 cpu_ppc_tb_start(env);
        !            84:             } else {
        !            85:                 cpu_ppc_tb_stop(env);
        !            86:             }
        !            87:         case PPC6xx_INPUT_INT:
        !            88:             /* Level sensitive - active high */
        !            89: #if defined(PPC_DEBUG_IRQ)
        !            90:             if (loglevel & CPU_LOG_INT) {
        !            91:                 fprintf(logfile, "%s: set the external IRQ state to %d\n",
        !            92:                         __func__, level);
        !            93:             }
        !            94: #endif
        !            95:             ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
        !            96:             break;
        !            97:         case PPC6xx_INPUT_SMI:
        !            98:             /* Level sensitive - active high */
        !            99: #if defined(PPC_DEBUG_IRQ)
        !           100:             if (loglevel & CPU_LOG_INT) {
        !           101:                 fprintf(logfile, "%s: set the SMI IRQ state to %d\n",
        !           102:                         __func__, level);
        !           103:             }
        !           104: #endif
        !           105:             ppc_set_irq(env, PPC_INTERRUPT_SMI, level);
        !           106:             break;
        !           107:         case PPC6xx_INPUT_MCP:
        !           108:             /* Negative edge sensitive */
        !           109:             /* XXX: TODO: actual reaction may depends on HID0 status
        !           110:              *            603/604/740/750: check HID0[EMCP]
        !           111:              */
        !           112:             if (cur_level == 1 && level == 0) {
        !           113: #if defined(PPC_DEBUG_IRQ)
        !           114:                 if (loglevel & CPU_LOG_INT) {
        !           115:                     fprintf(logfile, "%s: raise machine check state\n",
        !           116:                             __func__);
        !           117:                 }
        !           118: #endif
        !           119:                 ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
        !           120:             }
        !           121:             break;
        !           122:         case PPC6xx_INPUT_CKSTP_IN:
        !           123:             /* Level sensitive - active low */
        !           124:             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
        !           125:             /* XXX: Note that the only way to restart the CPU is to reset it */
        !           126:             if (level) {
        !           127: #if defined(PPC_DEBUG_IRQ)
        !           128:                 if (loglevel & CPU_LOG_INT) {
        !           129:                     fprintf(logfile, "%s: stop the CPU\n", __func__);
        !           130:                 }
        !           131: #endif
        !           132:                 env->halted = 1;
        !           133:             }
        !           134:             break;
        !           135:         case PPC6xx_INPUT_HRESET:
        !           136:             /* Level sensitive - active low */
        !           137:             if (level) {
        !           138: #if defined(PPC_DEBUG_IRQ)
        !           139:                 if (loglevel & CPU_LOG_INT) {
        !           140:                     fprintf(logfile, "%s: reset the CPU\n", __func__);
        !           141:                 }
        !           142: #endif
        !           143:                 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
        !           144:                 /* XXX: TOFIX */
        !           145: #if 0
        !           146:                 cpu_ppc_reset(env);
        !           147: #else
        !           148:                 qemu_system_reset_request();
        !           149: #endif
        !           150:             }
        !           151:             break;
        !           152:         case PPC6xx_INPUT_SRESET:
        !           153: #if defined(PPC_DEBUG_IRQ)
        !           154:             if (loglevel & CPU_LOG_INT) {
        !           155:                 fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
        !           156:                         __func__, level);
        !           157:             }
        !           158: #endif
        !           159:             ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
        !           160:             break;
        !           161:         default:
        !           162:             /* Unknown pin - do nothing */
        !           163: #if defined(PPC_DEBUG_IRQ)
        !           164:             if (loglevel & CPU_LOG_INT) {
        !           165:                 fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
        !           166:             }
        !           167: #endif
        !           168:             return;
        !           169:         }
        !           170:         if (level)
        !           171:             env->irq_input_state |= 1 << pin;
        !           172:         else
        !           173:             env->irq_input_state &= ~(1 << pin);
        !           174:     }
        !           175: }
        !           176: 
        !           177: void ppc6xx_irq_init (CPUState *env)
        !           178: {
        !           179:     env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env,
        !           180:                                                   PPC6xx_INPUT_NB);
        !           181: }
        !           182: 
        !           183: #if defined(TARGET_PPC64)
        !           184: /* PowerPC 970 internal IRQ controller */
        !           185: static void ppc970_set_irq (void *opaque, int pin, int level)
        !           186: {
        !           187:     CPUState *env = opaque;
        !           188:     int cur_level;
        !           189: 
        !           190: #if defined(PPC_DEBUG_IRQ)
        !           191:     if (loglevel & CPU_LOG_INT) {
        !           192:         fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
        !           193:                 env, pin, level);
        !           194:     }
        !           195: #endif
        !           196:     cur_level = (env->irq_input_state >> pin) & 1;
        !           197:     /* Don't generate spurious events */
        !           198:     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
        !           199:         switch (pin) {
        !           200:         case PPC970_INPUT_INT:
        !           201:             /* Level sensitive - active high */
        !           202: #if defined(PPC_DEBUG_IRQ)
        !           203:             if (loglevel & CPU_LOG_INT) {
        !           204:                 fprintf(logfile, "%s: set the external IRQ state to %d\n",
        !           205:                         __func__, level);
        !           206:             }
        !           207: #endif
        !           208:             ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
        !           209:             break;
        !           210:         case PPC970_INPUT_THINT:
        !           211:             /* Level sensitive - active high */
        !           212: #if defined(PPC_DEBUG_IRQ)
        !           213:             if (loglevel & CPU_LOG_INT) {
        !           214:                 fprintf(logfile, "%s: set the SMI IRQ state to %d\n", __func__,
        !           215:                         level);
        !           216:             }
        !           217: #endif
        !           218:             ppc_set_irq(env, PPC_INTERRUPT_THERM, level);
        !           219:             break;
        !           220:         case PPC970_INPUT_MCP:
        !           221:             /* Negative edge sensitive */
        !           222:             /* XXX: TODO: actual reaction may depends on HID0 status
        !           223:              *            603/604/740/750: check HID0[EMCP]
        !           224:              */
        !           225:             if (cur_level == 1 && level == 0) {
        !           226: #if defined(PPC_DEBUG_IRQ)
        !           227:                 if (loglevel & CPU_LOG_INT) {
        !           228:                     fprintf(logfile, "%s: raise machine check state\n",
        !           229:                             __func__);
        !           230:                 }
        !           231: #endif
        !           232:                 ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
        !           233:             }
        !           234:             break;
        !           235:         case PPC970_INPUT_CKSTP:
        !           236:             /* Level sensitive - active low */
        !           237:             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
        !           238:             if (level) {
        !           239: #if defined(PPC_DEBUG_IRQ)
        !           240:                 if (loglevel & CPU_LOG_INT) {
        !           241:                     fprintf(logfile, "%s: stop the CPU\n", __func__);
        !           242:                 }
        !           243: #endif
        !           244:                 env->halted = 1;
        !           245:             } else {
        !           246: #if defined(PPC_DEBUG_IRQ)
        !           247:                 if (loglevel & CPU_LOG_INT) {
        !           248:                     fprintf(logfile, "%s: restart the CPU\n", __func__);
        !           249:                 }
        !           250: #endif
        !           251:                 env->halted = 0;
        !           252:             }
        !           253:             break;
        !           254:         case PPC970_INPUT_HRESET:
        !           255:             /* Level sensitive - active low */
        !           256:             if (level) {
        !           257: #if 0 // XXX: TOFIX
        !           258: #if defined(PPC_DEBUG_IRQ)
        !           259:                 if (loglevel & CPU_LOG_INT) {
        !           260:                     fprintf(logfile, "%s: reset the CPU\n", __func__);
        !           261:                 }
        !           262: #endif
        !           263:                 cpu_reset(env);
        !           264: #endif
        !           265:             }
        !           266:             break;
        !           267:         case PPC970_INPUT_SRESET:
        !           268: #if defined(PPC_DEBUG_IRQ)
        !           269:             if (loglevel & CPU_LOG_INT) {
        !           270:                 fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
        !           271:                         __func__, level);
        !           272:             }
        !           273: #endif
        !           274:             ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
        !           275:             break;
        !           276:         case PPC970_INPUT_TBEN:
        !           277: #if defined(PPC_DEBUG_IRQ)
        !           278:             if (loglevel & CPU_LOG_INT) {
        !           279:                 fprintf(logfile, "%s: set the TBEN state to %d\n", __func__,
        !           280:                         level);
        !           281:             }
        !           282: #endif
        !           283:             /* XXX: TODO */
        !           284:             break;
        !           285:         default:
        !           286:             /* Unknown pin - do nothing */
        !           287: #if defined(PPC_DEBUG_IRQ)
        !           288:             if (loglevel & CPU_LOG_INT) {
        !           289:                 fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
        !           290:             }
        !           291: #endif
        !           292:             return;
        !           293:         }
        !           294:         if (level)
        !           295:             env->irq_input_state |= 1 << pin;
        !           296:         else
        !           297:             env->irq_input_state &= ~(1 << pin);
        !           298:     }
        !           299: }
1.1       root      300: 
1.1.1.4 ! root      301: void ppc970_irq_init (CPUState *env)
        !           302: {
        !           303:     env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env,
        !           304:                                                   PPC970_INPUT_NB);
        !           305: }
        !           306: #endif /* defined(TARGET_PPC64) */
        !           307: 
        !           308: /* PowerPC 40x internal IRQ controller */
        !           309: static void ppc40x_set_irq (void *opaque, int pin, int level)
        !           310: {
        !           311:     CPUState *env = opaque;
        !           312:     int cur_level;
        !           313: 
        !           314: #if defined(PPC_DEBUG_IRQ)
        !           315:     if (loglevel & CPU_LOG_INT) {
        !           316:         fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
        !           317:                 env, pin, level);
        !           318:     }
        !           319: #endif
        !           320:     cur_level = (env->irq_input_state >> pin) & 1;
        !           321:     /* Don't generate spurious events */
        !           322:     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
        !           323:         switch (pin) {
        !           324:         case PPC40x_INPUT_RESET_SYS:
        !           325:             if (level) {
        !           326: #if defined(PPC_DEBUG_IRQ)
        !           327:                 if (loglevel & CPU_LOG_INT) {
        !           328:                     fprintf(logfile, "%s: reset the PowerPC system\n",
        !           329:                             __func__);
        !           330:                 }
        !           331: #endif
        !           332:                 ppc40x_system_reset(env);
        !           333:             }
        !           334:             break;
        !           335:         case PPC40x_INPUT_RESET_CHIP:
        !           336:             if (level) {
        !           337: #if defined(PPC_DEBUG_IRQ)
        !           338:                 if (loglevel & CPU_LOG_INT) {
        !           339:                     fprintf(logfile, "%s: reset the PowerPC chip\n", __func__);
        !           340:                 }
        !           341: #endif
        !           342:                 ppc40x_chip_reset(env);
        !           343:             }
        !           344:             break;
        !           345:         case PPC40x_INPUT_RESET_CORE:
        !           346:             /* XXX: TODO: update DBSR[MRR] */
        !           347:             if (level) {
        !           348: #if defined(PPC_DEBUG_IRQ)
        !           349:                 if (loglevel & CPU_LOG_INT) {
        !           350:                     fprintf(logfile, "%s: reset the PowerPC core\n", __func__);
        !           351:                 }
        !           352: #endif
        !           353:                 ppc40x_core_reset(env);
        !           354:             }
        !           355:             break;
        !           356:         case PPC40x_INPUT_CINT:
        !           357:             /* Level sensitive - active high */
        !           358: #if defined(PPC_DEBUG_IRQ)
        !           359:             if (loglevel & CPU_LOG_INT) {
        !           360:                 fprintf(logfile, "%s: set the critical IRQ state to %d\n",
        !           361:                         __func__, level);
        !           362:             }
        !           363: #endif
        !           364:             ppc_set_irq(env, PPC_INTERRUPT_CEXT, level);
        !           365:             break;
        !           366:         case PPC40x_INPUT_INT:
        !           367:             /* Level sensitive - active high */
        !           368: #if defined(PPC_DEBUG_IRQ)
        !           369:             if (loglevel & CPU_LOG_INT) {
        !           370:                 fprintf(logfile, "%s: set the external IRQ state to %d\n",
        !           371:                         __func__, level);
        !           372:             }
        !           373: #endif
        !           374:             ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
        !           375:             break;
        !           376:         case PPC40x_INPUT_HALT:
        !           377:             /* Level sensitive - active low */
        !           378:             if (level) {
        !           379: #if defined(PPC_DEBUG_IRQ)
        !           380:                 if (loglevel & CPU_LOG_INT) {
        !           381:                     fprintf(logfile, "%s: stop the CPU\n", __func__);
        !           382:                 }
        !           383: #endif
        !           384:                 env->halted = 1;
        !           385:             } else {
        !           386: #if defined(PPC_DEBUG_IRQ)
        !           387:                 if (loglevel & CPU_LOG_INT) {
        !           388:                     fprintf(logfile, "%s: restart the CPU\n", __func__);
        !           389:                 }
        !           390: #endif
        !           391:                 env->halted = 0;
        !           392:             }
        !           393:             break;
        !           394:         case PPC40x_INPUT_DEBUG:
        !           395:             /* Level sensitive - active high */
        !           396: #if defined(PPC_DEBUG_IRQ)
        !           397:             if (loglevel & CPU_LOG_INT) {
        !           398:                 fprintf(logfile, "%s: set the debug pin state to %d\n",
        !           399:                         __func__, level);
        !           400:             }
        !           401: #endif
        !           402:             ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level);
        !           403:             break;
        !           404:         default:
        !           405:             /* Unknown pin - do nothing */
        !           406: #if defined(PPC_DEBUG_IRQ)
        !           407:             if (loglevel & CPU_LOG_INT) {
        !           408:                 fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
        !           409:             }
        !           410: #endif
        !           411:             return;
        !           412:         }
        !           413:         if (level)
        !           414:             env->irq_input_state |= 1 << pin;
        !           415:         else
        !           416:             env->irq_input_state &= ~(1 << pin);
        !           417:     }
        !           418: }
        !           419: 
        !           420: void ppc40x_irq_init (CPUState *env)
        !           421: {
        !           422:     env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
        !           423:                                                   env, PPC40x_INPUT_NB);
        !           424: }
        !           425: 
        !           426: /*****************************************************************************/
        !           427: /* PowerPC time base and decrementer emulation */
1.1       root      428: struct ppc_tb_t {
                    429:     /* Time base management */
1.1.1.4 ! root      430:     int64_t  tb_offset;    /* Compensation                    */
        !           431:     int64_t  atb_offset;   /* Compensation                    */
        !           432:     uint32_t tb_freq;      /* TB frequency                    */
1.1       root      433:     /* Decrementer management */
1.1.1.4 ! root      434:     uint64_t decr_next;    /* Tick for next decr interrupt    */
        !           435:     uint32_t decr_freq;    /* decrementer frequency           */
1.1       root      436:     struct QEMUTimer *decr_timer;
1.1.1.4 ! root      437:     /* Hypervisor decrementer management */
        !           438:     uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
        !           439:     struct QEMUTimer *hdecr_timer;
        !           440:     uint64_t purr_load;
        !           441:     uint64_t purr_start;
        !           442:     void *opaque;
1.1       root      443: };
                    444: 
1.1.1.4 ! root      445: static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, uint64_t vmclk,
        !           446:                                               int64_t tb_offset)
1.1       root      447: {
                    448:     /* TB time in tb periods */
1.1.1.4 ! root      449:     return muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec) + tb_offset;
1.1       root      450: }
                    451: 
                    452: uint32_t cpu_ppc_load_tbl (CPUState *env)
                    453: {
                    454:     ppc_tb_t *tb_env = env->tb_env;
                    455:     uint64_t tb;
                    456: 
1.1.1.4 ! root      457:     tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
        !           458: #if defined(PPC_DEBUG_TB)
        !           459:     if (loglevel != 0) {
        !           460:         fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb);
1.1       root      461:     }
                    462: #endif
                    463: 
                    464:     return tb & 0xFFFFFFFF;
                    465: }
                    466: 
1.1.1.4 ! root      467: static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env)
1.1       root      468: {
                    469:     ppc_tb_t *tb_env = env->tb_env;
                    470:     uint64_t tb;
                    471: 
1.1.1.4 ! root      472:     tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
        !           473: #if defined(PPC_DEBUG_TB)
        !           474:     if (loglevel != 0) {
        !           475:         fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb);
        !           476:     }
1.1       root      477: #endif
1.1.1.4 ! root      478: 
1.1       root      479:     return tb >> 32;
                    480: }
                    481: 
1.1.1.4 ! root      482: uint32_t cpu_ppc_load_tbu (CPUState *env)
1.1       root      483: {
1.1.1.4 ! root      484:     return _cpu_ppc_load_tbu(env);
        !           485: }
        !           486: 
        !           487: static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t vmclk,
        !           488:                                             int64_t *tb_offsetp,
        !           489:                                             uint64_t value)
        !           490: {
        !           491:     *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec);
        !           492: #ifdef PPC_DEBUG_TB
        !           493:     if (loglevel != 0) {
        !           494:         fprintf(logfile, "%s: tb %016" PRIx64 " offset %08" PRIx64 "\n",
        !           495:                 __func__, value, *tb_offsetp);
        !           496:     }
1.1       root      497: #endif
                    498: }
                    499: 
1.1.1.4 ! root      500: void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
        !           501: {
        !           502:     ppc_tb_t *tb_env = env->tb_env;
        !           503:     uint64_t tb;
        !           504: 
        !           505:     tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
        !           506:     tb &= 0xFFFFFFFF00000000ULL;
        !           507:     cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
        !           508:                      &tb_env->tb_offset, tb | (uint64_t)value);
        !           509: }
        !           510: 
        !           511: static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value)
        !           512: {
        !           513:     ppc_tb_t *tb_env = env->tb_env;
        !           514:     uint64_t tb;
        !           515: 
        !           516:     tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
        !           517:     tb &= 0x00000000FFFFFFFFULL;
        !           518:     cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
        !           519:                      &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
        !           520: }
        !           521: 
1.1       root      522: void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
                    523: {
1.1.1.4 ! root      524:     _cpu_ppc_store_tbu(env, value);
        !           525: }
        !           526: 
        !           527: uint32_t cpu_ppc_load_atbl (CPUState *env)
        !           528: {
1.1       root      529:     ppc_tb_t *tb_env = env->tb_env;
1.1.1.4 ! root      530:     uint64_t tb;
1.1       root      531: 
1.1.1.4 ! root      532:     tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
        !           533: #if defined(PPC_DEBUG_TB)
        !           534:     if (loglevel != 0) {
        !           535:         fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb);
        !           536:     }
        !           537: #endif
        !           538: 
        !           539:     return tb & 0xFFFFFFFF;
1.1       root      540: }
                    541: 
1.1.1.4 ! root      542: uint32_t cpu_ppc_load_atbu (CPUState *env)
1.1       root      543: {
                    544:     ppc_tb_t *tb_env = env->tb_env;
1.1.1.4 ! root      545:     uint64_t tb;
1.1       root      546: 
1.1.1.4 ! root      547:     tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
        !           548: #if defined(PPC_DEBUG_TB)
        !           549:     if (loglevel != 0) {
        !           550:         fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb);
        !           551:     }
        !           552: #endif
        !           553: 
        !           554:     return tb >> 32;
1.1       root      555: }
                    556: 
1.1.1.4 ! root      557: void cpu_ppc_store_atbl (CPUState *env, uint32_t value)
        !           558: {
        !           559:     ppc_tb_t *tb_env = env->tb_env;
        !           560:     uint64_t tb;
        !           561: 
        !           562:     tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
        !           563:     tb &= 0xFFFFFFFF00000000ULL;
        !           564:     cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
        !           565:                      &tb_env->atb_offset, tb | (uint64_t)value);
        !           566: }
        !           567: 
        !           568: void cpu_ppc_store_atbu (CPUState *env, uint32_t value)
        !           569: {
        !           570:     ppc_tb_t *tb_env = env->tb_env;
        !           571:     uint64_t tb;
        !           572: 
        !           573:     tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
        !           574:     tb &= 0x00000000FFFFFFFFULL;
        !           575:     cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
        !           576:                      &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
        !           577: }
        !           578: 
        !           579: static void cpu_ppc_tb_stop (CPUState *env)
        !           580: {
        !           581:     ppc_tb_t *tb_env = env->tb_env;
        !           582:     uint64_t tb, atb, vmclk;
        !           583: 
        !           584:     /* If the time base is already frozen, do nothing */
        !           585:     if (tb_env->tb_freq != 0) {
        !           586:         vmclk = qemu_get_clock(vm_clock);
        !           587:         /* Get the time base */
        !           588:         tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
        !           589:         /* Get the alternate time base */
        !           590:         atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
        !           591:         /* Store the time base value (ie compute the current offset) */
        !           592:         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
        !           593:         /* Store the alternate time base value (compute the current offset) */
        !           594:         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
        !           595:         /* Set the time base frequency to zero */
        !           596:         tb_env->tb_freq = 0;
        !           597:         /* Now, the time bases are frozen to tb_offset / atb_offset value */
        !           598:     }
        !           599: }
        !           600: 
        !           601: static void cpu_ppc_tb_start (CPUState *env)
        !           602: {
        !           603:     ppc_tb_t *tb_env = env->tb_env;
        !           604:     uint64_t tb, atb, vmclk;
        !           605: 
        !           606:     /* If the time base is not frozen, do nothing */
        !           607:     if (tb_env->tb_freq == 0) {
        !           608:         vmclk = qemu_get_clock(vm_clock);
        !           609:         /* Get the time base from tb_offset */
        !           610:         tb = tb_env->tb_offset;
        !           611:         /* Get the alternate time base from atb_offset */
        !           612:         atb = tb_env->atb_offset;
        !           613:         /* Restore the tb frequency from the decrementer frequency */
        !           614:         tb_env->tb_freq = tb_env->decr_freq;
        !           615:         /* Store the time base value */
        !           616:         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
        !           617:         /* Store the alternate time base value */
        !           618:         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
        !           619:     }
        !           620: }
        !           621: 
        !           622: static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env,
        !           623:                                                   uint64_t *next)
1.1       root      624: {
                    625:     ppc_tb_t *tb_env = env->tb_env;
                    626:     uint32_t decr;
                    627:     int64_t diff;
                    628: 
                    629:     diff = tb_env->decr_next - qemu_get_clock(vm_clock);
                    630:     if (diff >= 0)
1.1.1.4 ! root      631:         decr = muldiv64(diff, tb_env->decr_freq, ticks_per_sec);
1.1       root      632:     else
1.1.1.4 ! root      633:         decr = -muldiv64(-diff, tb_env->decr_freq, ticks_per_sec);
        !           634: #if defined(PPC_DEBUG_TB)
        !           635:     if (loglevel != 0) {
        !           636:         fprintf(logfile, "%s: %08" PRIx32 "\n", __func__, decr);
        !           637:     }
1.1       root      638: #endif
1.1.1.4 ! root      639: 
1.1       root      640:     return decr;
                    641: }
                    642: 
1.1.1.4 ! root      643: uint32_t cpu_ppc_load_decr (CPUState *env)
        !           644: {
        !           645:     ppc_tb_t *tb_env = env->tb_env;
        !           646: 
        !           647:     return _cpu_ppc_load_decr(env, &tb_env->decr_next);
        !           648: }
        !           649: 
        !           650: uint32_t cpu_ppc_load_hdecr (CPUState *env)
        !           651: {
        !           652:     ppc_tb_t *tb_env = env->tb_env;
        !           653: 
        !           654:     return _cpu_ppc_load_decr(env, &tb_env->hdecr_next);
        !           655: }
        !           656: 
        !           657: uint64_t cpu_ppc_load_purr (CPUState *env)
        !           658: {
        !           659:     ppc_tb_t *tb_env = env->tb_env;
        !           660:     uint64_t diff;
        !           661: 
        !           662:     diff = qemu_get_clock(vm_clock) - tb_env->purr_start;
        !           663: 
        !           664:     return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
        !           665: }
        !           666: 
1.1       root      667: /* When decrementer expires,
                    668:  * all we need to do is generate or queue a CPU exception
                    669:  */
1.1.1.4 ! root      670: static always_inline void cpu_ppc_decr_excp (CPUState *env)
        !           671: {
        !           672:     /* Raise it */
        !           673: #ifdef PPC_DEBUG_TB
        !           674:     if (loglevel != 0) {
        !           675:         fprintf(logfile, "raise decrementer exception\n");
        !           676:     }
        !           677: #endif
        !           678:     ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
        !           679: }
        !           680: 
        !           681: static always_inline void cpu_ppc_hdecr_excp (CPUState *env)
1.1       root      682: {
                    683:     /* Raise it */
1.1.1.4 ! root      684: #ifdef PPC_DEBUG_TB
        !           685:     if (loglevel != 0) {
        !           686:         fprintf(logfile, "raise decrementer exception\n");
        !           687:     }
1.1       root      688: #endif
1.1.1.4 ! root      689:     ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1);
1.1       root      690: }
                    691: 
1.1.1.4 ! root      692: static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp,
        !           693:                                   struct QEMUTimer *timer,
        !           694:                                   void (*raise_excp)(CPUState *),
        !           695:                                   uint32_t decr, uint32_t value,
        !           696:                                   int is_excp)
1.1       root      697: {
                    698:     ppc_tb_t *tb_env = env->tb_env;
                    699:     uint64_t now, next;
                    700: 
1.1.1.4 ! root      701: #ifdef PPC_DEBUG_TB
        !           702:     if (loglevel != 0) {
        !           703:         fprintf(logfile, "%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
        !           704:                 decr, value);
        !           705:     }
1.1       root      706: #endif
                    707:     now = qemu_get_clock(vm_clock);
1.1.1.4 ! root      708:     next = now + muldiv64(value, ticks_per_sec, tb_env->decr_freq);
1.1       root      709:     if (is_excp)
1.1.1.4 ! root      710:         next += *nextp - now;
1.1       root      711:     if (next == now)
1.1.1.4 ! root      712:         next++;
        !           713:     *nextp = next;
1.1       root      714:     /* Adjust timer */
1.1.1.4 ! root      715:     qemu_mod_timer(timer, next);
1.1       root      716:     /* If we set a negative value and the decrementer was positive,
                    717:      * raise an exception.
                    718:      */
                    719:     if ((value & 0x80000000) && !(decr & 0x80000000))
1.1.1.4 ! root      720:         (*raise_excp)(env);
        !           721: }
        !           722: 
        !           723: static always_inline void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
        !           724:                                                uint32_t value, int is_excp)
        !           725: {
        !           726:     ppc_tb_t *tb_env = env->tb_env;
        !           727: 
        !           728:     __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer,
        !           729:                          &cpu_ppc_decr_excp, decr, value, is_excp);
1.1       root      730: }
                    731: 
                    732: void cpu_ppc_store_decr (CPUState *env, uint32_t value)
                    733: {
                    734:     _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
                    735: }
                    736: 
                    737: static void cpu_ppc_decr_cb (void *opaque)
                    738: {
                    739:     _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
                    740: }
                    741: 
1.1.1.4 ! root      742: static always_inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr,
        !           743:                                                 uint32_t value, int is_excp)
        !           744: {
        !           745:     ppc_tb_t *tb_env = env->tb_env;
        !           746: 
        !           747:     if (tb_env->hdecr_timer != NULL) {
        !           748:         __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer,
        !           749:                              &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
        !           750:     }
        !           751: }
        !           752: 
        !           753: void cpu_ppc_store_hdecr (CPUState *env, uint32_t value)
        !           754: {
        !           755:     _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0);
        !           756: }
        !           757: 
        !           758: static void cpu_ppc_hdecr_cb (void *opaque)
        !           759: {
        !           760:     _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1);
        !           761: }
        !           762: 
        !           763: void cpu_ppc_store_purr (CPUState *env, uint64_t value)
        !           764: {
        !           765:     ppc_tb_t *tb_env = env->tb_env;
        !           766: 
        !           767:     tb_env->purr_load = value;
        !           768:     tb_env->purr_start = qemu_get_clock(vm_clock);
        !           769: }
        !           770: 
        !           771: static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
        !           772: {
        !           773:     CPUState *env = opaque;
        !           774:     ppc_tb_t *tb_env = env->tb_env;
        !           775: 
        !           776:     tb_env->tb_freq = freq;
        !           777:     tb_env->decr_freq = freq;
        !           778:     /* There is a bug in Linux 2.4 kernels:
        !           779:      * if a decrementer exception is pending when it enables msr_ee at startup,
        !           780:      * it's not ready to handle it...
        !           781:      */
        !           782:     _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
        !           783:     _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
        !           784:     cpu_ppc_store_purr(env, 0x0000000000000000ULL);
        !           785: }
        !           786: 
1.1       root      787: /* Set up (once) timebase frequency (in Hz) */
1.1.1.4 ! root      788: clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
1.1       root      789: {
                    790:     ppc_tb_t *tb_env;
                    791: 
                    792:     tb_env = qemu_mallocz(sizeof(ppc_tb_t));
                    793:     if (tb_env == NULL)
                    794:         return NULL;
                    795:     env->tb_env = tb_env;
1.1.1.4 ! root      796:     /* Create new timer */
        !           797:     tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
        !           798:     if (0) {
        !           799:         /* XXX: find a suitable condition to enable the hypervisor decrementer
        !           800:          */
        !           801:         tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env);
        !           802:     } else {
        !           803:         tb_env->hdecr_timer = NULL;
        !           804:     }
        !           805:     cpu_ppc_set_tb_clk(env, freq);
        !           806: 
        !           807:     return &cpu_ppc_set_tb_clk;
        !           808: }
        !           809: 
        !           810: /* Specific helpers for POWER & PowerPC 601 RTC */
        !           811: clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
        !           812: {
        !           813:     return cpu_ppc_tb_init(env, 7812500);
        !           814: }
        !           815: 
        !           816: void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
        !           817: {
        !           818:     _cpu_ppc_store_tbu(env, value);
        !           819: }
        !           820: 
        !           821: uint32_t cpu_ppc601_load_rtcu (CPUState *env)
        !           822: {
        !           823:     return _cpu_ppc_load_tbu(env);
        !           824: }
        !           825: 
        !           826: void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
        !           827: {
        !           828:     cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
        !           829: }
        !           830: 
        !           831: uint32_t cpu_ppc601_load_rtcl (CPUState *env)
        !           832: {
        !           833:     return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
        !           834: }
        !           835: 
        !           836: /*****************************************************************************/
        !           837: /* Embedded PowerPC timers */
        !           838: 
        !           839: /* PIT, FIT & WDT */
        !           840: typedef struct ppcemb_timer_t ppcemb_timer_t;
        !           841: struct ppcemb_timer_t {
        !           842:     uint64_t pit_reload;  /* PIT auto-reload value        */
        !           843:     uint64_t fit_next;    /* Tick for next FIT interrupt  */
        !           844:     struct QEMUTimer *fit_timer;
        !           845:     uint64_t wdt_next;    /* Tick for next WDT interrupt  */
        !           846:     struct QEMUTimer *wdt_timer;
        !           847: };
        !           848: 
        !           849: /* Fixed interval timer */
        !           850: static void cpu_4xx_fit_cb (void *opaque)
        !           851: {
        !           852:     CPUState *env;
        !           853:     ppc_tb_t *tb_env;
        !           854:     ppcemb_timer_t *ppcemb_timer;
        !           855:     uint64_t now, next;
        !           856: 
        !           857:     env = opaque;
        !           858:     tb_env = env->tb_env;
        !           859:     ppcemb_timer = tb_env->opaque;
        !           860:     now = qemu_get_clock(vm_clock);
        !           861:     switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
        !           862:     case 0:
        !           863:         next = 1 << 9;
        !           864:         break;
        !           865:     case 1:
        !           866:         next = 1 << 13;
        !           867:         break;
        !           868:     case 2:
        !           869:         next = 1 << 17;
        !           870:         break;
        !           871:     case 3:
        !           872:         next = 1 << 21;
        !           873:         break;
        !           874:     default:
        !           875:         /* Cannot occur, but makes gcc happy */
        !           876:         return;
1.1       root      877:     }
1.1.1.4 ! root      878:     next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
        !           879:     if (next == now)
        !           880:         next++;
        !           881:     qemu_mod_timer(ppcemb_timer->fit_timer, next);
        !           882:     env->spr[SPR_40x_TSR] |= 1 << 26;
        !           883:     if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
        !           884:         ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
        !           885: #ifdef PPC_DEBUG_TB
        !           886:     if (loglevel != 0) {
        !           887:         fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__,
        !           888:                 (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
        !           889:                 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
        !           890:     }
        !           891: #endif
        !           892: }
1.1       root      893: 
1.1.1.4 ! root      894: /* Programmable interval timer */
        !           895: static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
        !           896: {
        !           897:     ppcemb_timer_t *ppcemb_timer;
        !           898:     uint64_t now, next;
        !           899: 
        !           900:     ppcemb_timer = tb_env->opaque;
        !           901:     if (ppcemb_timer->pit_reload <= 1 ||
        !           902:         !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
        !           903:         (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
        !           904:         /* Stop PIT */
        !           905: #ifdef PPC_DEBUG_TB
        !           906:         if (loglevel != 0) {
        !           907:             fprintf(logfile, "%s: stop PIT\n", __func__);
        !           908:         }
        !           909: #endif
        !           910:         qemu_del_timer(tb_env->decr_timer);
        !           911:     } else {
        !           912: #ifdef PPC_DEBUG_TB
        !           913:         if (loglevel != 0) {
        !           914:             fprintf(logfile, "%s: start PIT %016" PRIx64 "\n",
        !           915:                     __func__, ppcemb_timer->pit_reload);
        !           916:         }
        !           917: #endif
        !           918:         now = qemu_get_clock(vm_clock);
        !           919:         next = now + muldiv64(ppcemb_timer->pit_reload,
        !           920:                               ticks_per_sec, tb_env->decr_freq);
        !           921:         if (is_excp)
        !           922:             next += tb_env->decr_next - now;
        !           923:         if (next == now)
        !           924:             next++;
        !           925:         qemu_mod_timer(tb_env->decr_timer, next);
        !           926:         tb_env->decr_next = next;
        !           927:     }
        !           928: }
        !           929: 
        !           930: static void cpu_4xx_pit_cb (void *opaque)
        !           931: {
        !           932:     CPUState *env;
        !           933:     ppc_tb_t *tb_env;
        !           934:     ppcemb_timer_t *ppcemb_timer;
        !           935: 
        !           936:     env = opaque;
        !           937:     tb_env = env->tb_env;
        !           938:     ppcemb_timer = tb_env->opaque;
        !           939:     env->spr[SPR_40x_TSR] |= 1 << 27;
        !           940:     if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
        !           941:         ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
        !           942:     start_stop_pit(env, tb_env, 1);
        !           943: #ifdef PPC_DEBUG_TB
        !           944:     if (loglevel != 0) {
        !           945:         fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " "
        !           946:                 "%016" PRIx64 "\n", __func__,
        !           947:                 (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
        !           948:                 (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
        !           949:                 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
        !           950:                 ppcemb_timer->pit_reload);
        !           951:     }
        !           952: #endif
        !           953: }
        !           954: 
        !           955: /* Watchdog timer */
        !           956: static void cpu_4xx_wdt_cb (void *opaque)
        !           957: {
        !           958:     CPUState *env;
        !           959:     ppc_tb_t *tb_env;
        !           960:     ppcemb_timer_t *ppcemb_timer;
        !           961:     uint64_t now, next;
        !           962: 
        !           963:     env = opaque;
        !           964:     tb_env = env->tb_env;
        !           965:     ppcemb_timer = tb_env->opaque;
        !           966:     now = qemu_get_clock(vm_clock);
        !           967:     switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
        !           968:     case 0:
        !           969:         next = 1 << 17;
        !           970:         break;
        !           971:     case 1:
        !           972:         next = 1 << 21;
        !           973:         break;
        !           974:     case 2:
        !           975:         next = 1 << 25;
        !           976:         break;
        !           977:     case 3:
        !           978:         next = 1 << 29;
        !           979:         break;
        !           980:     default:
        !           981:         /* Cannot occur, but makes gcc happy */
        !           982:         return;
        !           983:     }
        !           984:     next = now + muldiv64(next, ticks_per_sec, tb_env->decr_freq);
        !           985:     if (next == now)
        !           986:         next++;
        !           987: #ifdef PPC_DEBUG_TB
        !           988:     if (loglevel != 0) {
        !           989:         fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__,
        !           990:                 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
        !           991:     }
        !           992: #endif
        !           993:     switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
        !           994:     case 0x0:
        !           995:     case 0x1:
        !           996:         qemu_mod_timer(ppcemb_timer->wdt_timer, next);
        !           997:         ppcemb_timer->wdt_next = next;
        !           998:         env->spr[SPR_40x_TSR] |= 1 << 31;
        !           999:         break;
        !          1000:     case 0x2:
        !          1001:         qemu_mod_timer(ppcemb_timer->wdt_timer, next);
        !          1002:         ppcemb_timer->wdt_next = next;
        !          1003:         env->spr[SPR_40x_TSR] |= 1 << 30;
        !          1004:         if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
        !          1005:             ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
        !          1006:         break;
        !          1007:     case 0x3:
        !          1008:         env->spr[SPR_40x_TSR] &= ~0x30000000;
        !          1009:         env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
        !          1010:         switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
        !          1011:         case 0x0:
        !          1012:             /* No reset */
        !          1013:             break;
        !          1014:         case 0x1: /* Core reset */
        !          1015:             ppc40x_core_reset(env);
        !          1016:             break;
        !          1017:         case 0x2: /* Chip reset */
        !          1018:             ppc40x_chip_reset(env);
        !          1019:             break;
        !          1020:         case 0x3: /* System reset */
        !          1021:             ppc40x_system_reset(env);
        !          1022:             break;
        !          1023:         }
        !          1024:     }
        !          1025: }
        !          1026: 
        !          1027: void store_40x_pit (CPUState *env, target_ulong val)
        !          1028: {
        !          1029:     ppc_tb_t *tb_env;
        !          1030:     ppcemb_timer_t *ppcemb_timer;
        !          1031: 
        !          1032:     tb_env = env->tb_env;
        !          1033:     ppcemb_timer = tb_env->opaque;
        !          1034: #ifdef PPC_DEBUG_TB
        !          1035:     if (loglevel != 0) {
        !          1036:         fprintf(logfile, "%s val" ADDRX "\n", __func__, val);
        !          1037:     }
        !          1038: #endif
        !          1039:     ppcemb_timer->pit_reload = val;
        !          1040:     start_stop_pit(env, tb_env, 0);
        !          1041: }
        !          1042: 
        !          1043: target_ulong load_40x_pit (CPUState *env)
        !          1044: {
        !          1045:     return cpu_ppc_load_decr(env);
        !          1046: }
        !          1047: 
        !          1048: void store_booke_tsr (CPUState *env, target_ulong val)
        !          1049: {
        !          1050: #ifdef PPC_DEBUG_TB
        !          1051:     if (loglevel != 0) {
        !          1052:         fprintf(logfile, "%s: val " ADDRX "\n", __func__, val);
        !          1053:     }
        !          1054: #endif
        !          1055:     env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
        !          1056:     if (val & 0x80000000)
        !          1057:         ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
        !          1058: }
        !          1059: 
        !          1060: void store_booke_tcr (CPUState *env, target_ulong val)
        !          1061: {
        !          1062:     ppc_tb_t *tb_env;
        !          1063: 
        !          1064:     tb_env = env->tb_env;
        !          1065: #ifdef PPC_DEBUG_TB
        !          1066:     if (loglevel != 0) {
        !          1067:         fprintf(logfile, "%s: val " ADDRX "\n", __func__, val);
        !          1068:     }
        !          1069: #endif
        !          1070:     env->spr[SPR_40x_TCR] = val & 0xFFC00000;
        !          1071:     start_stop_pit(env, tb_env, 1);
        !          1072:     cpu_4xx_wdt_cb(env);
        !          1073: }
        !          1074: 
        !          1075: static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
        !          1076: {
        !          1077:     CPUState *env = opaque;
        !          1078:     ppc_tb_t *tb_env = env->tb_env;
        !          1079: 
        !          1080: #ifdef PPC_DEBUG_TB
        !          1081:     if (loglevel != 0) {
        !          1082:         fprintf(logfile, "%s set new frequency to %" PRIu32 "\n", __func__,
        !          1083:                 freq);
        !          1084:     }
        !          1085: #endif
        !          1086:     tb_env->tb_freq = freq;
        !          1087:     tb_env->decr_freq = freq;
        !          1088:     /* XXX: we should also update all timers */
        !          1089: }
        !          1090: 
        !          1091: clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
        !          1092: {
        !          1093:     ppc_tb_t *tb_env;
        !          1094:     ppcemb_timer_t *ppcemb_timer;
        !          1095: 
        !          1096:     tb_env = qemu_mallocz(sizeof(ppc_tb_t));
        !          1097:     if (tb_env == NULL) {
        !          1098:         return NULL;
        !          1099:     }
        !          1100:     env->tb_env = tb_env;
        !          1101:     ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
        !          1102:     tb_env->tb_freq = freq;
        !          1103:     tb_env->decr_freq = freq;
        !          1104:     tb_env->opaque = ppcemb_timer;
        !          1105: #ifdef PPC_DEBUG_TB
        !          1106:     if (loglevel != 0) {
        !          1107:         fprintf(logfile, "%s freq %" PRIu32 "\n", __func__, freq);
        !          1108:     }
        !          1109: #endif
        !          1110:     if (ppcemb_timer != NULL) {
        !          1111:         /* We use decr timer for PIT */
        !          1112:         tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
        !          1113:         ppcemb_timer->fit_timer =
        !          1114:             qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
        !          1115:         ppcemb_timer->wdt_timer =
        !          1116:             qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
        !          1117:     }
        !          1118: 
        !          1119:     return &ppc_emb_set_tb_clk;
        !          1120: }
        !          1121: 
        !          1122: /*****************************************************************************/
        !          1123: /* Embedded PowerPC Device Control Registers */
        !          1124: typedef struct ppc_dcrn_t ppc_dcrn_t;
        !          1125: struct ppc_dcrn_t {
        !          1126:     dcr_read_cb dcr_read;
        !          1127:     dcr_write_cb dcr_write;
        !          1128:     void *opaque;
        !          1129: };
        !          1130: 
        !          1131: /* XXX: on 460, DCR addresses are 32 bits wide,
        !          1132:  *      using DCRIPR to get the 22 upper bits of the DCR address
        !          1133:  */
        !          1134: #define DCRN_NB 1024
        !          1135: struct ppc_dcr_t {
        !          1136:     ppc_dcrn_t dcrn[DCRN_NB];
        !          1137:     int (*read_error)(int dcrn);
        !          1138:     int (*write_error)(int dcrn);
        !          1139: };
        !          1140: 
        !          1141: int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
        !          1142: {
        !          1143:     ppc_dcrn_t *dcr;
        !          1144: 
        !          1145:     if (dcrn < 0 || dcrn >= DCRN_NB)
        !          1146:         goto error;
        !          1147:     dcr = &dcr_env->dcrn[dcrn];
        !          1148:     if (dcr->dcr_read == NULL)
        !          1149:         goto error;
        !          1150:     *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
        !          1151: 
        !          1152:     return 0;
        !          1153: 
        !          1154:  error:
        !          1155:     if (dcr_env->read_error != NULL)
        !          1156:         return (*dcr_env->read_error)(dcrn);
        !          1157: 
        !          1158:     return -1;
        !          1159: }
        !          1160: 
        !          1161: int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
        !          1162: {
        !          1163:     ppc_dcrn_t *dcr;
        !          1164: 
        !          1165:     if (dcrn < 0 || dcrn >= DCRN_NB)
        !          1166:         goto error;
        !          1167:     dcr = &dcr_env->dcrn[dcrn];
        !          1168:     if (dcr->dcr_write == NULL)
        !          1169:         goto error;
        !          1170:     (*dcr->dcr_write)(dcr->opaque, dcrn, val);
        !          1171: 
        !          1172:     return 0;
        !          1173: 
        !          1174:  error:
        !          1175:     if (dcr_env->write_error != NULL)
        !          1176:         return (*dcr_env->write_error)(dcrn);
        !          1177: 
        !          1178:     return -1;
        !          1179: }
        !          1180: 
        !          1181: int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
        !          1182:                       dcr_read_cb dcr_read, dcr_write_cb dcr_write)
        !          1183: {
        !          1184:     ppc_dcr_t *dcr_env;
        !          1185:     ppc_dcrn_t *dcr;
        !          1186: 
        !          1187:     dcr_env = env->dcr_env;
        !          1188:     if (dcr_env == NULL)
        !          1189:         return -1;
        !          1190:     if (dcrn < 0 || dcrn >= DCRN_NB)
        !          1191:         return -1;
        !          1192:     dcr = &dcr_env->dcrn[dcrn];
        !          1193:     if (dcr->opaque != NULL ||
        !          1194:         dcr->dcr_read != NULL ||
        !          1195:         dcr->dcr_write != NULL)
        !          1196:         return -1;
        !          1197:     dcr->opaque = opaque;
        !          1198:     dcr->dcr_read = dcr_read;
        !          1199:     dcr->dcr_write = dcr_write;
        !          1200: 
        !          1201:     return 0;
        !          1202: }
        !          1203: 
        !          1204: int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
        !          1205:                   int (*write_error)(int dcrn))
        !          1206: {
        !          1207:     ppc_dcr_t *dcr_env;
        !          1208: 
        !          1209:     dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
        !          1210:     if (dcr_env == NULL)
        !          1211:         return -1;
        !          1212:     dcr_env->read_error = read_error;
        !          1213:     dcr_env->write_error = write_error;
        !          1214:     env->dcr_env = dcr_env;
        !          1215: 
        !          1216:     return 0;
1.1       root     1217: }
                   1218: 
                   1219: #if 0
                   1220: /*****************************************************************************/
                   1221: /* Handle system reset (for now, just stop emulation) */
                   1222: void cpu_ppc_reset (CPUState *env)
                   1223: {
                   1224:     printf("Reset asked... Stop emulation\n");
                   1225:     abort();
                   1226: }
                   1227: #endif
                   1228: 
                   1229: /*****************************************************************************/
                   1230: /* Debug port */
                   1231: void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
                   1232: {
                   1233:     addr &= 0xF;
                   1234:     switch (addr) {
                   1235:     case 0:
                   1236:         printf("%c", val);
                   1237:         break;
                   1238:     case 1:
                   1239:         printf("\n");
                   1240:         fflush(stdout);
                   1241:         break;
                   1242:     case 2:
1.1.1.4 ! root     1243:         printf("Set loglevel to %04" PRIx32 "\n", val);
1.1       root     1244:         cpu_set_log(val | 0x100);
                   1245:         break;
                   1246:     }
                   1247: }
                   1248: 
                   1249: /*****************************************************************************/
                   1250: /* NVRAM helpers */
1.1.1.4 ! root     1251: static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr)
        !          1252: {
        !          1253:     return (*nvram->read_fn)(nvram->opaque, addr);;
        !          1254: }
        !          1255: 
        !          1256: static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val)
1.1       root     1257: {
1.1.1.4 ! root     1258:     (*nvram->write_fn)(nvram->opaque, addr, val);
1.1       root     1259: }
                   1260: 
1.1.1.4 ! root     1261: void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value)
1.1       root     1262: {
1.1.1.4 ! root     1263:     nvram_write(nvram, addr, value);
1.1       root     1264: }
                   1265: 
1.1.1.4 ! root     1266: uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr)
1.1       root     1267: {
1.1.1.4 ! root     1268:     return nvram_read(nvram, addr);
1.1       root     1269: }
                   1270: 
1.1.1.4 ! root     1271: void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value)
        !          1272: {
        !          1273:     nvram_write(nvram, addr, value >> 8);
        !          1274:     nvram_write(nvram, addr + 1, value & 0xFF);
        !          1275: }
        !          1276: 
        !          1277: uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr)
1.1       root     1278: {
                   1279:     uint16_t tmp;
                   1280: 
1.1.1.4 ! root     1281:     tmp = nvram_read(nvram, addr) << 8;
        !          1282:     tmp |= nvram_read(nvram, addr + 1);
        !          1283: 
1.1       root     1284:     return tmp;
                   1285: }
                   1286: 
1.1.1.4 ! root     1287: void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value)
1.1       root     1288: {
1.1.1.4 ! root     1289:     nvram_write(nvram, addr, value >> 24);
        !          1290:     nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
        !          1291:     nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
        !          1292:     nvram_write(nvram, addr + 3, value & 0xFF);
1.1       root     1293: }
                   1294: 
1.1.1.4 ! root     1295: uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr)
1.1       root     1296: {
                   1297:     uint32_t tmp;
                   1298: 
1.1.1.4 ! root     1299:     tmp = nvram_read(nvram, addr) << 24;
        !          1300:     tmp |= nvram_read(nvram, addr + 1) << 16;
        !          1301:     tmp |= nvram_read(nvram, addr + 2) << 8;
        !          1302:     tmp |= nvram_read(nvram, addr + 3);
        !          1303: 
1.1       root     1304:     return tmp;
                   1305: }
                   1306: 
1.1.1.4 ! root     1307: void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
1.1       root     1308:                        const unsigned char *str, uint32_t max)
                   1309: {
                   1310:     int i;
                   1311: 
                   1312:     for (i = 0; i < max && str[i] != '\0'; i++) {
1.1.1.4 ! root     1313:         nvram_write(nvram, addr + i, str[i]);
1.1       root     1314:     }
1.1.1.4 ! root     1315:     nvram_write(nvram, addr + i, str[i]);
        !          1316:     nvram_write(nvram, addr + max - 1, '\0');
1.1       root     1317: }
                   1318: 
1.1.1.4 ! root     1319: int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max)
1.1       root     1320: {
                   1321:     int i;
                   1322: 
                   1323:     memset(dst, 0, max);
                   1324:     for (i = 0; i < max; i++) {
                   1325:         dst[i] = NVRAM_get_byte(nvram, addr + i);
                   1326:         if (dst[i] == '\0')
                   1327:             break;
                   1328:     }
                   1329: 
                   1330:     return i;
                   1331: }
                   1332: 
                   1333: static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
                   1334: {
                   1335:     uint16_t tmp;
                   1336:     uint16_t pd, pd1, pd2;
                   1337: 
                   1338:     tmp = prev >> 8;
                   1339:     pd = prev ^ value;
                   1340:     pd1 = pd & 0x000F;
                   1341:     pd2 = ((pd >> 4) & 0x000F) ^ pd1;
                   1342:     tmp ^= (pd1 << 3) | (pd1 << 8);
                   1343:     tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
                   1344: 
                   1345:     return tmp;
                   1346: }
                   1347: 
1.1.1.4 ! root     1348: uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count)
1.1       root     1349: {
                   1350:     uint32_t i;
                   1351:     uint16_t crc = 0xFFFF;
                   1352:     int odd;
                   1353: 
                   1354:     odd = count & 1;
                   1355:     count &= ~1;
                   1356:     for (i = 0; i != count; i++) {
1.1.1.4 ! root     1357:         crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
1.1       root     1358:     }
                   1359:     if (odd) {
1.1.1.4 ! root     1360:         crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
1.1       root     1361:     }
                   1362: 
                   1363:     return crc;
                   1364: }
                   1365: 
                   1366: #define CMDLINE_ADDR 0x017ff000
                   1367: 
1.1.1.4 ! root     1368: int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
1.1       root     1369:                           const unsigned char *arch,
                   1370:                           uint32_t RAM_size, int boot_device,
                   1371:                           uint32_t kernel_image, uint32_t kernel_size,
                   1372:                           const char *cmdline,
                   1373:                           uint32_t initrd_image, uint32_t initrd_size,
                   1374:                           uint32_t NVRAM_image,
                   1375:                           int width, int height, int depth)
                   1376: {
                   1377:     uint16_t crc;
                   1378: 
                   1379:     /* Set parameters for Open Hack'Ware BIOS */
                   1380:     NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
                   1381:     NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
                   1382:     NVRAM_set_word(nvram,   0x14, NVRAM_size);
                   1383:     NVRAM_set_string(nvram, 0x20, arch, 16);
                   1384:     NVRAM_set_lword(nvram,  0x30, RAM_size);
                   1385:     NVRAM_set_byte(nvram,   0x34, boot_device);
                   1386:     NVRAM_set_lword(nvram,  0x38, kernel_image);
                   1387:     NVRAM_set_lword(nvram,  0x3C, kernel_size);
                   1388:     if (cmdline) {
                   1389:         /* XXX: put the cmdline in NVRAM too ? */
                   1390:         strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
                   1391:         NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
                   1392:         NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
                   1393:     } else {
                   1394:         NVRAM_set_lword(nvram,  0x40, 0);
                   1395:         NVRAM_set_lword(nvram,  0x44, 0);
                   1396:     }
                   1397:     NVRAM_set_lword(nvram,  0x48, initrd_image);
                   1398:     NVRAM_set_lword(nvram,  0x4C, initrd_size);
                   1399:     NVRAM_set_lword(nvram,  0x50, NVRAM_image);
                   1400: 
                   1401:     NVRAM_set_word(nvram,   0x54, width);
                   1402:     NVRAM_set_word(nvram,   0x56, height);
                   1403:     NVRAM_set_word(nvram,   0x58, depth);
                   1404:     crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
1.1.1.4 ! root     1405:     NVRAM_set_word(nvram,   0xFC, crc);
1.1       root     1406: 
                   1407:     return 0;
                   1408: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.