cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

adlib.c (7952B)


      1/*
      2 * QEMU Proxy for OPL2/3 emulation by MAME team
      3 *
      4 * Copyright (c) 2004-2005 Vassili Karpov (malc)
      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
     25#include "qemu/osdep.h"
     26#include "qapi/error.h"
     27#include "qemu/module.h"
     28#include "hw/audio/soundhw.h"
     29#include "audio/audio.h"
     30#include "hw/isa/isa.h"
     31#include "hw/qdev-properties.h"
     32#include "qom/object.h"
     33
     34//#define DEBUG
     35
     36#define ADLIB_KILL_TIMERS 1
     37
     38#define ADLIB_DESC "Yamaha YM3812 (OPL2)"
     39
     40#ifdef DEBUG
     41#include "qemu/timer.h"
     42#endif
     43
     44#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
     45#ifdef DEBUG
     46#define ldebug(...) dolog (__VA_ARGS__)
     47#else
     48#define ldebug(...)
     49#endif
     50
     51#include "fmopl.h"
     52#define SHIFT 1
     53
     54#define TYPE_ADLIB "adlib"
     55OBJECT_DECLARE_SIMPLE_TYPE(AdlibState, ADLIB)
     56
     57struct AdlibState {
     58    ISADevice parent_obj;
     59
     60    QEMUSoundCard card;
     61    uint32_t freq;
     62    uint32_t port;
     63    int ticking[2];
     64    int enabled;
     65    int active;
     66    int bufpos;
     67#ifdef DEBUG
     68    int64_t exp[2];
     69#endif
     70    int16_t *mixbuf;
     71    uint64_t dexp[2];
     72    SWVoiceOut *voice;
     73    int left, pos, samples;
     74    QEMUAudioTimeStamp ats;
     75    FM_OPL *opl;
     76    PortioList port_list;
     77};
     78
     79static void adlib_stop_opl_timer (AdlibState *s, size_t n)
     80{
     81    OPLTimerOver (s->opl, n);
     82    s->ticking[n] = 0;
     83}
     84
     85static void adlib_kill_timers (AdlibState *s)
     86{
     87    size_t i;
     88
     89    for (i = 0; i < 2; ++i) {
     90        if (s->ticking[i]) {
     91            uint64_t delta;
     92
     93            delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
     94            ldebug (
     95                "delta = %f dexp = %f expired => %d\n",
     96                delta / 1000000.0,
     97                s->dexp[i] / 1000000.0,
     98                delta >= s->dexp[i]
     99                );
    100            if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
    101                adlib_stop_opl_timer (s, i);
    102                AUD_init_time_stamp_out (s->voice, &s->ats);
    103            }
    104        }
    105    }
    106}
    107
    108static void adlib_write(void *opaque, uint32_t nport, uint32_t val)
    109{
    110    AdlibState *s = opaque;
    111    int a = nport & 3;
    112
    113    s->active = 1;
    114    AUD_set_active_out (s->voice, 1);
    115
    116    adlib_kill_timers (s);
    117
    118    OPLWrite (s->opl, a, val);
    119}
    120
    121static uint32_t adlib_read(void *opaque, uint32_t nport)
    122{
    123    AdlibState *s = opaque;
    124    int a = nport & 3;
    125
    126    adlib_kill_timers (s);
    127    return OPLRead (s->opl, a);
    128}
    129
    130static void timer_handler (void *opaque, int c, double interval_Sec)
    131{
    132    AdlibState *s = opaque;
    133    unsigned n = c & 1;
    134#ifdef DEBUG
    135    double interval;
    136    int64_t exp;
    137#endif
    138
    139    if (interval_Sec == 0.0) {
    140        s->ticking[n] = 0;
    141        return;
    142    }
    143
    144    s->ticking[n] = 1;
    145#ifdef DEBUG
    146    interval = NANOSECONDS_PER_SECOND * interval_Sec;
    147    exp = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + interval;
    148    s->exp[n] = exp;
    149#endif
    150
    151    s->dexp[n] = interval_Sec * 1000000.0;
    152    AUD_init_time_stamp_out (s->voice, &s->ats);
    153}
    154
    155static int write_audio (AdlibState *s, int samples)
    156{
    157    int net = 0;
    158    int pos = s->pos;
    159
    160    while (samples) {
    161        int nbytes, wbytes, wsampl;
    162
    163        nbytes = samples << SHIFT;
    164        wbytes = AUD_write (
    165            s->voice,
    166            s->mixbuf + (pos << (SHIFT - 1)),
    167            nbytes
    168            );
    169
    170        if (wbytes) {
    171            wsampl = wbytes >> SHIFT;
    172
    173            samples -= wsampl;
    174            pos = (pos + wsampl) % s->samples;
    175
    176            net += wsampl;
    177        }
    178        else {
    179            break;
    180        }
    181    }
    182
    183    return net;
    184}
    185
    186static void adlib_callback (void *opaque, int free)
    187{
    188    AdlibState *s = opaque;
    189    int samples, to_play, written;
    190
    191    samples = free >> SHIFT;
    192    if (!(s->active && s->enabled) || !samples) {
    193        return;
    194    }
    195
    196    to_play = MIN (s->left, samples);
    197    while (to_play) {
    198        written = write_audio (s, to_play);
    199
    200        if (written) {
    201            s->left -= written;
    202            samples -= written;
    203            to_play -= written;
    204            s->pos = (s->pos + written) % s->samples;
    205        }
    206        else {
    207            return;
    208        }
    209    }
    210
    211    samples = MIN (samples, s->samples - s->pos);
    212    if (!samples) {
    213        return;
    214    }
    215
    216    YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
    217
    218    while (samples) {
    219        written = write_audio (s, samples);
    220
    221        if (written) {
    222            samples -= written;
    223            s->pos = (s->pos + written) % s->samples;
    224        }
    225        else {
    226            s->left = samples;
    227            return;
    228        }
    229    }
    230}
    231
    232static void Adlib_fini (AdlibState *s)
    233{
    234    if (s->opl) {
    235        OPLDestroy (s->opl);
    236        s->opl = NULL;
    237    }
    238
    239    g_free(s->mixbuf);
    240
    241    s->active = 0;
    242    s->enabled = 0;
    243    AUD_remove_card (&s->card);
    244}
    245
    246static MemoryRegionPortio adlib_portio_list[] = {
    247    { 0, 4, 1, .read = adlib_read, .write = adlib_write, },
    248    { 0, 2, 1, .read = adlib_read, .write = adlib_write, },
    249    { 0x388, 4, 1, .read = adlib_read, .write = adlib_write, },
    250    PORTIO_END_OF_LIST(),
    251};
    252
    253static void adlib_realizefn (DeviceState *dev, Error **errp)
    254{
    255    AdlibState *s = ADLIB(dev);
    256    struct audsettings as;
    257
    258    s->opl = OPLCreate (3579545, s->freq);
    259    if (!s->opl) {
    260        error_setg (errp, "OPLCreate %d failed", s->freq);
    261        return;
    262    }
    263    else {
    264        OPLSetTimerHandler(s->opl, timer_handler, s);
    265        s->enabled = 1;
    266    }
    267
    268    as.freq = s->freq;
    269    as.nchannels = SHIFT;
    270    as.fmt = AUDIO_FORMAT_S16;
    271    as.endianness = AUDIO_HOST_ENDIANNESS;
    272
    273    AUD_register_card ("adlib", &s->card);
    274
    275    s->voice = AUD_open_out (
    276        &s->card,
    277        s->voice,
    278        "adlib",
    279        s,
    280        adlib_callback,
    281        &as
    282        );
    283    if (!s->voice) {
    284        Adlib_fini (s);
    285        error_setg (errp, "Initializing audio voice failed");
    286        return;
    287    }
    288
    289    s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
    290    s->mixbuf = g_malloc0 (s->samples << SHIFT);
    291
    292    adlib_portio_list[0].offset = s->port;
    293    adlib_portio_list[1].offset = s->port + 8;
    294    portio_list_init (&s->port_list, OBJECT(s), adlib_portio_list, s, "adlib");
    295    portio_list_add (&s->port_list, isa_address_space_io(&s->parent_obj), 0);
    296}
    297
    298static Property adlib_properties[] = {
    299    DEFINE_AUDIO_PROPERTIES(AdlibState, card),
    300    DEFINE_PROP_UINT32 ("iobase",  AdlibState, port, 0x220),
    301    DEFINE_PROP_UINT32 ("freq",    AdlibState, freq,  44100),
    302    DEFINE_PROP_END_OF_LIST (),
    303};
    304
    305static void adlib_class_initfn (ObjectClass *klass, void *data)
    306{
    307    DeviceClass *dc = DEVICE_CLASS (klass);
    308
    309    dc->realize = adlib_realizefn;
    310    set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
    311    dc->desc = ADLIB_DESC;
    312    device_class_set_props(dc, adlib_properties);
    313}
    314
    315static const TypeInfo adlib_info = {
    316    .name          = TYPE_ADLIB,
    317    .parent        = TYPE_ISA_DEVICE,
    318    .instance_size = sizeof (AdlibState),
    319    .class_init    = adlib_class_initfn,
    320};
    321
    322static void adlib_register_types (void)
    323{
    324    type_register_static (&adlib_info);
    325    deprecated_register_soundhw("adlib", ADLIB_DESC, 1, TYPE_ADLIB);
    326}
    327
    328type_init (adlib_register_types)