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

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: {
1.1.1.2 ! root      286:     m48t59_write(nvram, addr, value);
1.1       root      287: }
                    288: 
                    289: uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
                    290: {
1.1.1.2 ! root      291:     return m48t59_read(nvram, addr);
1.1       root      292: }
                    293: 
                    294: void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
                    295: {
1.1.1.2 ! root      296:     m48t59_write(nvram, addr, value >> 8);
        !           297:     m48t59_write(nvram, addr + 1, value & 0xFF);
1.1       root      298: }
                    299: 
                    300: uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
                    301: {
                    302:     uint16_t tmp;
                    303: 
1.1.1.2 ! root      304:     tmp = m48t59_read(nvram, addr) << 8;
        !           305:     tmp |= m48t59_read(nvram, addr + 1);
1.1       root      306:     return tmp;
                    307: }
                    308: 
                    309: void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
                    310: {
1.1.1.2 ! root      311:     m48t59_write(nvram, addr, value >> 24);
        !           312:     m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
        !           313:     m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
        !           314:     m48t59_write(nvram, addr + 3, value & 0xFF);
1.1       root      315: }
                    316: 
                    317: uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
                    318: {
                    319:     uint32_t tmp;
                    320: 
1.1.1.2 ! root      321:     tmp = m48t59_read(nvram, addr) << 24;
        !           322:     tmp |= m48t59_read(nvram, addr + 1) << 16;
        !           323:     tmp |= m48t59_read(nvram, addr + 2) << 8;
        !           324:     tmp |= m48t59_read(nvram, addr + 3);
1.1       root      325:     return tmp;
                    326: }
                    327: 
                    328: void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
                    329:                        const unsigned char *str, uint32_t max)
                    330: {
                    331:     int i;
                    332: 
                    333:     for (i = 0; i < max && str[i] != '\0'; i++) {
1.1.1.2 ! root      334:         m48t59_write(nvram, addr + i, str[i]);
1.1       root      335:     }
1.1.1.2 ! root      336:     m48t59_write(nvram, addr + max - 1, '\0');
1.1       root      337: }
                    338: 
                    339: int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
                    340: {
                    341:     int i;
                    342: 
                    343:     memset(dst, 0, max);
                    344:     for (i = 0; i < max; i++) {
                    345:         dst[i] = NVRAM_get_byte(nvram, addr + i);
                    346:         if (dst[i] == '\0')
                    347:             break;
                    348:     }
                    349: 
                    350:     return i;
                    351: }
                    352: 
                    353: static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
                    354: {
                    355:     uint16_t tmp;
                    356:     uint16_t pd, pd1, pd2;
                    357: 
                    358:     tmp = prev >> 8;
                    359:     pd = prev ^ value;
                    360:     pd1 = pd & 0x000F;
                    361:     pd2 = ((pd >> 4) & 0x000F) ^ pd1;
                    362:     tmp ^= (pd1 << 3) | (pd1 << 8);
                    363:     tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
                    364: 
                    365:     return tmp;
                    366: }
                    367: 
                    368: uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
                    369: {
                    370:     uint32_t i;
                    371:     uint16_t crc = 0xFFFF;
                    372:     int odd;
                    373: 
                    374:     odd = count & 1;
                    375:     count &= ~1;
                    376:     for (i = 0; i != count; i++) {
                    377:        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
                    378:     }
                    379:     if (odd) {
                    380:        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
                    381:     }
                    382: 
                    383:     return crc;
                    384: }
                    385: 
                    386: #define CMDLINE_ADDR 0x017ff000
                    387: 
                    388: int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
                    389:                           const unsigned char *arch,
                    390:                           uint32_t RAM_size, int boot_device,
                    391:                           uint32_t kernel_image, uint32_t kernel_size,
                    392:                           const char *cmdline,
                    393:                           uint32_t initrd_image, uint32_t initrd_size,
                    394:                           uint32_t NVRAM_image,
                    395:                           int width, int height, int depth)
                    396: {
                    397:     uint16_t crc;
                    398: 
                    399:     /* Set parameters for Open Hack'Ware BIOS */
                    400:     NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
                    401:     NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
                    402:     NVRAM_set_word(nvram,   0x14, NVRAM_size);
                    403:     NVRAM_set_string(nvram, 0x20, arch, 16);
                    404:     NVRAM_set_lword(nvram,  0x30, RAM_size);
                    405:     NVRAM_set_byte(nvram,   0x34, boot_device);
                    406:     NVRAM_set_lword(nvram,  0x38, kernel_image);
                    407:     NVRAM_set_lword(nvram,  0x3C, kernel_size);
                    408:     if (cmdline) {
                    409:         /* XXX: put the cmdline in NVRAM too ? */
                    410:         strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
                    411:         NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
                    412:         NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
                    413:     } else {
                    414:         NVRAM_set_lword(nvram,  0x40, 0);
                    415:         NVRAM_set_lword(nvram,  0x44, 0);
                    416:     }
                    417:     NVRAM_set_lword(nvram,  0x48, initrd_image);
                    418:     NVRAM_set_lword(nvram,  0x4C, initrd_size);
                    419:     NVRAM_set_lword(nvram,  0x50, NVRAM_image);
                    420: 
                    421:     NVRAM_set_word(nvram,   0x54, width);
                    422:     NVRAM_set_word(nvram,   0x56, height);
                    423:     NVRAM_set_word(nvram,   0x58, depth);
                    424:     crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
                    425:     NVRAM_set_word(nvram,  0xFC, crc);
                    426: 
                    427:     return 0;
                    428: }

unix.superglobalmegacorp.com

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