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

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: /*****************************************************************************/
                    205: /* Debug port */
                    206: void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
                    207: {
                    208:     addr &= 0xF;
                    209:     switch (addr) {
                    210:     case 0:
                    211:         printf("%c", val);
                    212:         break;
                    213:     case 1:
                    214:         printf("\n");
                    215:         fflush(stdout);
                    216:         break;
                    217:     case 2:
                    218:         printf("Set loglevel to %04x\n", val);
                    219:         cpu_set_log(val | 0x100);
                    220:         break;
                    221:     }
                    222: }
                    223: 
                    224: /*****************************************************************************/
                    225: /* NVRAM helpers */
                    226: void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
                    227: {
1.1.1.2   root      228:     m48t59_write(nvram, addr, value);
1.1       root      229: }
                    230: 
                    231: uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
                    232: {
1.1.1.2   root      233:     return m48t59_read(nvram, addr);
1.1       root      234: }
                    235: 
                    236: void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
                    237: {
1.1.1.2   root      238:     m48t59_write(nvram, addr, value >> 8);
                    239:     m48t59_write(nvram, addr + 1, value & 0xFF);
1.1       root      240: }
                    241: 
                    242: uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
                    243: {
                    244:     uint16_t tmp;
                    245: 
1.1.1.2   root      246:     tmp = m48t59_read(nvram, addr) << 8;
                    247:     tmp |= m48t59_read(nvram, addr + 1);
1.1       root      248:     return tmp;
                    249: }
                    250: 
                    251: void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
                    252: {
1.1.1.2   root      253:     m48t59_write(nvram, addr, value >> 24);
                    254:     m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
                    255:     m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
                    256:     m48t59_write(nvram, addr + 3, value & 0xFF);
1.1       root      257: }
                    258: 
                    259: uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
                    260: {
                    261:     uint32_t tmp;
                    262: 
1.1.1.2   root      263:     tmp = m48t59_read(nvram, addr) << 24;
                    264:     tmp |= m48t59_read(nvram, addr + 1) << 16;
                    265:     tmp |= m48t59_read(nvram, addr + 2) << 8;
                    266:     tmp |= m48t59_read(nvram, addr + 3);
1.1       root      267:     return tmp;
                    268: }
                    269: 
                    270: void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
                    271:                        const unsigned char *str, uint32_t max)
                    272: {
                    273:     int i;
                    274: 
                    275:     for (i = 0; i < max && str[i] != '\0'; i++) {
1.1.1.2   root      276:         m48t59_write(nvram, addr + i, str[i]);
1.1       root      277:     }
1.1.1.2   root      278:     m48t59_write(nvram, addr + max - 1, '\0');
1.1       root      279: }
                    280: 
                    281: int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
                    282: {
                    283:     int i;
                    284: 
                    285:     memset(dst, 0, max);
                    286:     for (i = 0; i < max; i++) {
                    287:         dst[i] = NVRAM_get_byte(nvram, addr + i);
                    288:         if (dst[i] == '\0')
                    289:             break;
                    290:     }
                    291: 
                    292:     return i;
                    293: }
                    294: 
                    295: static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
                    296: {
                    297:     uint16_t tmp;
                    298:     uint16_t pd, pd1, pd2;
                    299: 
                    300:     tmp = prev >> 8;
                    301:     pd = prev ^ value;
                    302:     pd1 = pd & 0x000F;
                    303:     pd2 = ((pd >> 4) & 0x000F) ^ pd1;
                    304:     tmp ^= (pd1 << 3) | (pd1 << 8);
                    305:     tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
                    306: 
                    307:     return tmp;
                    308: }
                    309: 
                    310: uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
                    311: {
                    312:     uint32_t i;
                    313:     uint16_t crc = 0xFFFF;
                    314:     int odd;
                    315: 
                    316:     odd = count & 1;
                    317:     count &= ~1;
                    318:     for (i = 0; i != count; i++) {
                    319:        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
                    320:     }
                    321:     if (odd) {
                    322:        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
                    323:     }
                    324: 
                    325:     return crc;
                    326: }
                    327: 
                    328: #define CMDLINE_ADDR 0x017ff000
                    329: 
                    330: int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
                    331:                           const unsigned char *arch,
                    332:                           uint32_t RAM_size, int boot_device,
                    333:                           uint32_t kernel_image, uint32_t kernel_size,
                    334:                           const char *cmdline,
                    335:                           uint32_t initrd_image, uint32_t initrd_size,
                    336:                           uint32_t NVRAM_image,
                    337:                           int width, int height, int depth)
                    338: {
                    339:     uint16_t crc;
                    340: 
                    341:     /* Set parameters for Open Hack'Ware BIOS */
                    342:     NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
                    343:     NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
                    344:     NVRAM_set_word(nvram,   0x14, NVRAM_size);
                    345:     NVRAM_set_string(nvram, 0x20, arch, 16);
                    346:     NVRAM_set_lword(nvram,  0x30, RAM_size);
                    347:     NVRAM_set_byte(nvram,   0x34, boot_device);
                    348:     NVRAM_set_lword(nvram,  0x38, kernel_image);
                    349:     NVRAM_set_lword(nvram,  0x3C, kernel_size);
                    350:     if (cmdline) {
                    351:         /* XXX: put the cmdline in NVRAM too ? */
                    352:         strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
                    353:         NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
                    354:         NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
                    355:     } else {
                    356:         NVRAM_set_lword(nvram,  0x40, 0);
                    357:         NVRAM_set_lword(nvram,  0x44, 0);
                    358:     }
                    359:     NVRAM_set_lword(nvram,  0x48, initrd_image);
                    360:     NVRAM_set_lword(nvram,  0x4C, initrd_size);
                    361:     NVRAM_set_lword(nvram,  0x50, NVRAM_image);
                    362: 
                    363:     NVRAM_set_word(nvram,   0x54, width);
                    364:     NVRAM_set_word(nvram,   0x56, height);
                    365:     NVRAM_set_word(nvram,   0x58, depth);
                    366:     crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
                    367:     NVRAM_set_word(nvram,  0xFC, crc);
                    368: 
                    369:     return 0;
                    370: }

unix.superglobalmegacorp.com

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