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

1.1     ! root        1: /*
        !             2:  * QEMU generic PPC hardware System Emulator
        !             3:  * 
        !             4:  * Copyright (c) 2003-2004 Jocelyn Mayer
        !             5:  * 
        !             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:  */
        !            24: #include "vl.h"
        !            25: #include "m48t59.h"
        !            26: 
        !            27: /*****************************************************************************/
        !            28: /* PPC time base and decrementer emulation */
        !            29: //#define DEBUG_TB
        !            30: 
        !            31: struct ppc_tb_t {
        !            32:     /* Time base management */
        !            33:     int64_t  tb_offset;    /* Compensation               */
        !            34:     uint32_t tb_freq;      /* TB frequency               */
        !            35:     /* Decrementer management */
        !            36:     uint64_t decr_next;    /* Tick for next decr interrupt  */
        !            37:     struct QEMUTimer *decr_timer;
        !            38: };
        !            39: 
        !            40: static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
        !            41: {
        !            42:     /* TB time in tb periods */
        !            43:     return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
        !            44:                    tb_env->tb_freq, ticks_per_sec);
        !            45: }
        !            46: 
        !            47: uint32_t cpu_ppc_load_tbl (CPUState *env)
        !            48: {
        !            49:     ppc_tb_t *tb_env = env->tb_env;
        !            50:     uint64_t tb;
        !            51: 
        !            52:     tb = cpu_ppc_get_tb(tb_env);
        !            53: #ifdef DEBUG_TB
        !            54:     {
        !            55:          static int last_time;
        !            56:         int now;
        !            57:         now = time(NULL);
        !            58:         if (last_time != now) {
        !            59:             last_time = now;
        !            60:             printf("%s: tb=0x%016lx %d %08lx\n",
        !            61:                     __func__, tb, now, tb_env->tb_offset);
        !            62:         }
        !            63:     }
        !            64: #endif
        !            65: 
        !            66:     return tb & 0xFFFFFFFF;
        !            67: }
        !            68: 
        !            69: uint32_t cpu_ppc_load_tbu (CPUState *env)
        !            70: {
        !            71:     ppc_tb_t *tb_env = env->tb_env;
        !            72:     uint64_t tb;
        !            73: 
        !            74:     tb = cpu_ppc_get_tb(tb_env);
        !            75: #ifdef DEBUG_TB
        !            76:     printf("%s: tb=0x%016lx\n", __func__, tb);
        !            77: #endif
        !            78:     return tb >> 32;
        !            79: }
        !            80: 
        !            81: static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
        !            82: {
        !            83:     tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
        !            84:         - qemu_get_clock(vm_clock);
        !            85: #ifdef DEBUG_TB
        !            86:     printf("%s: tb=0x%016lx offset=%08x\n", __func__, value);
        !            87: #endif
        !            88: }
        !            89: 
        !            90: void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
        !            91: {
        !            92:     ppc_tb_t *tb_env = env->tb_env;
        !            93: 
        !            94:     cpu_ppc_store_tb(tb_env,
        !            95:                      ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
        !            96: }
        !            97: 
        !            98: void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
        !            99: {
        !           100:     ppc_tb_t *tb_env = env->tb_env;
        !           101: 
        !           102:     cpu_ppc_store_tb(tb_env,
        !           103:                      ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
        !           104: }
        !           105: 
        !           106: uint32_t cpu_ppc_load_decr (CPUState *env)
        !           107: {
        !           108:     ppc_tb_t *tb_env = env->tb_env;
        !           109:     uint32_t decr;
        !           110:     int64_t diff;
        !           111: 
        !           112:     diff = tb_env->decr_next - qemu_get_clock(vm_clock);
        !           113:     if (diff >= 0)
        !           114:         decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
        !           115:     else
        !           116:         decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
        !           117: #if defined(DEBUG_TB)
        !           118:     printf("%s: 0x%08x\n", __func__, decr);
        !           119: #endif
        !           120:     return decr;
        !           121: }
        !           122: 
        !           123: /* When decrementer expires,
        !           124:  * all we need to do is generate or queue a CPU exception
        !           125:  */
        !           126: static inline void cpu_ppc_decr_excp (CPUState *env)
        !           127: {
        !           128:     /* Raise it */
        !           129: #ifdef DEBUG_TB
        !           130:     printf("raise decrementer exception\n");
        !           131: #endif
        !           132:     cpu_interrupt(env, CPU_INTERRUPT_TIMER);
        !           133: }
        !           134: 
        !           135: static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
        !           136:                                  uint32_t value, int is_excp)
        !           137: {
        !           138:     ppc_tb_t *tb_env = env->tb_env;
        !           139:     uint64_t now, next;
        !           140: 
        !           141: #ifdef DEBUG_TB
        !           142:     printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value);
        !           143: #endif
        !           144:     now = qemu_get_clock(vm_clock);
        !           145:     next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
        !           146:     if (is_excp)
        !           147:         next += tb_env->decr_next - now;
        !           148:     if (next == now)
        !           149:        next++;
        !           150:     tb_env->decr_next = next;
        !           151:     /* Adjust timer */
        !           152:     qemu_mod_timer(tb_env->decr_timer, next);
        !           153:     /* If we set a negative value and the decrementer was positive,
        !           154:      * raise an exception.
        !           155:      */
        !           156:     if ((value & 0x80000000) && !(decr & 0x80000000))
        !           157:        cpu_ppc_decr_excp(env);
        !           158: }
        !           159: 
        !           160: void cpu_ppc_store_decr (CPUState *env, uint32_t value)
        !           161: {
        !           162:     _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
        !           163: }
        !           164: 
        !           165: static void cpu_ppc_decr_cb (void *opaque)
        !           166: {
        !           167:     _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
        !           168: }
        !           169: 
        !           170: /* Set up (once) timebase frequency (in Hz) */
        !           171: ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
        !           172: {
        !           173:     ppc_tb_t *tb_env;
        !           174: 
        !           175:     tb_env = qemu_mallocz(sizeof(ppc_tb_t));
        !           176:     if (tb_env == NULL)
        !           177:         return NULL;
        !           178:     env->tb_env = tb_env;
        !           179:     if (tb_env->tb_freq == 0 || 1) {
        !           180:        tb_env->tb_freq = freq;
        !           181:        /* Create new timer */
        !           182:        tb_env->decr_timer =
        !           183:             qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
        !           184:        /* There is a bug in  2.4 kernels:
        !           185:         * if a decrementer exception is pending when it enables msr_ee,
        !           186:         * it's not ready to handle it...
        !           187:         */
        !           188:        _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
        !           189:     }
        !           190: 
        !           191:     return tb_env;
        !           192: }
        !           193: 
        !           194: #if 0
        !           195: /*****************************************************************************/
        !           196: /* Handle system reset (for now, just stop emulation) */
        !           197: void cpu_ppc_reset (CPUState *env)
        !           198: {
        !           199:     printf("Reset asked... Stop emulation\n");
        !           200:     abort();
        !           201: }
        !           202: #endif
        !           203: 
        !           204: static void PPC_io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
        !           205: {
        !           206:     cpu_outb(NULL, addr & 0xffff, value);
        !           207: }
        !           208: 
        !           209: static uint32_t PPC_io_readb (void *opaque, target_phys_addr_t addr)
        !           210: {
        !           211:     uint32_t ret = cpu_inb(NULL, addr & 0xffff);
        !           212:     return ret;
        !           213: }
        !           214: 
        !           215: static void PPC_io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
        !           216: {
        !           217: #ifdef TARGET_WORDS_BIGENDIAN
        !           218:     value = bswap16(value);
        !           219: #endif
        !           220:     cpu_outw(NULL, addr & 0xffff, value);
        !           221: }
        !           222: 
        !           223: static uint32_t PPC_io_readw (void *opaque, target_phys_addr_t addr)
        !           224: {
        !           225:     uint32_t ret = cpu_inw(NULL, addr & 0xffff);
        !           226: #ifdef TARGET_WORDS_BIGENDIAN
        !           227:     ret = bswap16(ret);
        !           228: #endif
        !           229:     return ret;
        !           230: }
        !           231: 
        !           232: static void PPC_io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
        !           233: {
        !           234: #ifdef TARGET_WORDS_BIGENDIAN
        !           235:     value = bswap32(value);
        !           236: #endif
        !           237:     cpu_outl(NULL, addr & 0xffff, value);
        !           238: }
        !           239: 
        !           240: static uint32_t PPC_io_readl (void *opaque, target_phys_addr_t addr)
        !           241: {
        !           242:     uint32_t ret = cpu_inl(NULL, addr & 0xffff);
        !           243: 
        !           244: #ifdef TARGET_WORDS_BIGENDIAN
        !           245:     ret = bswap32(ret);
        !           246: #endif
        !           247:     return ret;
        !           248: }
        !           249: 
        !           250: CPUWriteMemoryFunc *PPC_io_write[] = {
        !           251:     &PPC_io_writeb,
        !           252:     &PPC_io_writew,
        !           253:     &PPC_io_writel,
        !           254: };
        !           255: 
        !           256: CPUReadMemoryFunc *PPC_io_read[] = {
        !           257:     &PPC_io_readb,
        !           258:     &PPC_io_readw,
        !           259:     &PPC_io_readl,
        !           260: };
        !           261: 
        !           262: /*****************************************************************************/
        !           263: /* Debug port */
        !           264: void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
        !           265: {
        !           266:     addr &= 0xF;
        !           267:     switch (addr) {
        !           268:     case 0:
        !           269:         printf("%c", val);
        !           270:         break;
        !           271:     case 1:
        !           272:         printf("\n");
        !           273:         fflush(stdout);
        !           274:         break;
        !           275:     case 2:
        !           276:         printf("Set loglevel to %04x\n", val);
        !           277:         cpu_set_log(val | 0x100);
        !           278:         break;
        !           279:     }
        !           280: }
        !           281: 
        !           282: /*****************************************************************************/
        !           283: /* NVRAM helpers */
        !           284: void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
        !           285: {
        !           286:     m48t59_set_addr(nvram, addr);
        !           287:     m48t59_write(nvram, value);
        !           288: }
        !           289: 
        !           290: uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
        !           291: {
        !           292:     m48t59_set_addr(nvram, addr);
        !           293:     return m48t59_read(nvram);
        !           294: }
        !           295: 
        !           296: void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
        !           297: {
        !           298:     m48t59_set_addr(nvram, addr);
        !           299:     m48t59_write(nvram, value >> 8);
        !           300:     m48t59_set_addr(nvram, addr + 1);
        !           301:     m48t59_write(nvram, value & 0xFF);
        !           302: }
        !           303: 
        !           304: uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
        !           305: {
        !           306:     uint16_t tmp;
        !           307: 
        !           308:     m48t59_set_addr(nvram, addr);
        !           309:     tmp = m48t59_read(nvram) << 8;
        !           310:     m48t59_set_addr(nvram, addr + 1);
        !           311:     tmp |= m48t59_read(nvram);
        !           312: 
        !           313:     return tmp;
        !           314: }
        !           315: 
        !           316: void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
        !           317: {
        !           318:     m48t59_set_addr(nvram, addr);
        !           319:     m48t59_write(nvram, value >> 24);
        !           320:     m48t59_set_addr(nvram, addr + 1);
        !           321:     m48t59_write(nvram, (value >> 16) & 0xFF);
        !           322:     m48t59_set_addr(nvram, addr + 2);
        !           323:     m48t59_write(nvram, (value >> 8) & 0xFF);
        !           324:     m48t59_set_addr(nvram, addr + 3);
        !           325:     m48t59_write(nvram, value & 0xFF);
        !           326: }
        !           327: 
        !           328: uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
        !           329: {
        !           330:     uint32_t tmp;
        !           331: 
        !           332:     m48t59_set_addr(nvram, addr);
        !           333:     tmp = m48t59_read(nvram) << 24;
        !           334:     m48t59_set_addr(nvram, addr + 1);
        !           335:     tmp |= m48t59_read(nvram) << 16;
        !           336:     m48t59_set_addr(nvram, addr + 2);
        !           337:     tmp |= m48t59_read(nvram) << 8;
        !           338:     m48t59_set_addr(nvram, addr + 3);
        !           339:     tmp |= m48t59_read(nvram);
        !           340: 
        !           341:     return tmp;
        !           342: }
        !           343: 
        !           344: void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
        !           345:                        const unsigned char *str, uint32_t max)
        !           346: {
        !           347:     int i;
        !           348: 
        !           349:     for (i = 0; i < max && str[i] != '\0'; i++) {
        !           350:         m48t59_set_addr(nvram, addr + i);
        !           351:         m48t59_write(nvram, str[i]);
        !           352:     }
        !           353:     m48t59_set_addr(nvram, addr + max - 1);
        !           354:     m48t59_write(nvram, '\0');
        !           355: }
        !           356: 
        !           357: int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
        !           358: {
        !           359:     int i;
        !           360: 
        !           361:     memset(dst, 0, max);
        !           362:     for (i = 0; i < max; i++) {
        !           363:         dst[i] = NVRAM_get_byte(nvram, addr + i);
        !           364:         if (dst[i] == '\0')
        !           365:             break;
        !           366:     }
        !           367: 
        !           368:     return i;
        !           369: }
        !           370: 
        !           371: static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
        !           372: {
        !           373:     uint16_t tmp;
        !           374:     uint16_t pd, pd1, pd2;
        !           375: 
        !           376:     tmp = prev >> 8;
        !           377:     pd = prev ^ value;
        !           378:     pd1 = pd & 0x000F;
        !           379:     pd2 = ((pd >> 4) & 0x000F) ^ pd1;
        !           380:     tmp ^= (pd1 << 3) | (pd1 << 8);
        !           381:     tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
        !           382: 
        !           383:     return tmp;
        !           384: }
        !           385: 
        !           386: uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
        !           387: {
        !           388:     uint32_t i;
        !           389:     uint16_t crc = 0xFFFF;
        !           390:     int odd;
        !           391: 
        !           392:     odd = count & 1;
        !           393:     count &= ~1;
        !           394:     for (i = 0; i != count; i++) {
        !           395:        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
        !           396:     }
        !           397:     if (odd) {
        !           398:        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
        !           399:     }
        !           400: 
        !           401:     return crc;
        !           402: }
        !           403: 
        !           404: #define CMDLINE_ADDR 0x017ff000
        !           405: 
        !           406: int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
        !           407:                           const unsigned char *arch,
        !           408:                           uint32_t RAM_size, int boot_device,
        !           409:                           uint32_t kernel_image, uint32_t kernel_size,
        !           410:                           const char *cmdline,
        !           411:                           uint32_t initrd_image, uint32_t initrd_size,
        !           412:                           uint32_t NVRAM_image,
        !           413:                           int width, int height, int depth)
        !           414: {
        !           415:     uint16_t crc;
        !           416: 
        !           417:     /* Set parameters for Open Hack'Ware BIOS */
        !           418:     NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
        !           419:     NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
        !           420:     NVRAM_set_word(nvram,   0x14, NVRAM_size);
        !           421:     NVRAM_set_string(nvram, 0x20, arch, 16);
        !           422:     NVRAM_set_lword(nvram,  0x30, RAM_size);
        !           423:     NVRAM_set_byte(nvram,   0x34, boot_device);
        !           424:     NVRAM_set_lword(nvram,  0x38, kernel_image);
        !           425:     NVRAM_set_lword(nvram,  0x3C, kernel_size);
        !           426:     if (cmdline) {
        !           427:         /* XXX: put the cmdline in NVRAM too ? */
        !           428:         strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
        !           429:         NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
        !           430:         NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
        !           431:     } else {
        !           432:         NVRAM_set_lword(nvram,  0x40, 0);
        !           433:         NVRAM_set_lword(nvram,  0x44, 0);
        !           434:     }
        !           435:     NVRAM_set_lword(nvram,  0x48, initrd_image);
        !           436:     NVRAM_set_lword(nvram,  0x4C, initrd_size);
        !           437:     NVRAM_set_lword(nvram,  0x50, NVRAM_image);
        !           438: 
        !           439:     NVRAM_set_word(nvram,   0x54, width);
        !           440:     NVRAM_set_word(nvram,   0x56, height);
        !           441:     NVRAM_set_word(nvram,   0x58, depth);
        !           442:     crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
        !           443:     NVRAM_set_word(nvram,  0xFC, crc);
        !           444: 
        !           445:     return 0;
        !           446: }

unix.superglobalmegacorp.com

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