Menu

#1021 APIC IRR bits not set while interrupts disabled

fixed_in_SVN
closed
CPU model (187)
5
2012-10-15
2006-05-31
Anonymous
No

In bochs 2.2.6, setting interrupts off and setting the
APIC timer to trigger a one-shot interrupt does not
correctly set the bits in the Interrupt Request
Register of the APIC device.

Conditions:

  1. Interrupts disabled.
  2. Set APIC timer to one-shot and interrupt 0x50 and
    divide by 16
  3. Set task priority to 0.
  4. Set APIC Initial Count register to some value
  5. Poll the IRR register, waiting for the bit to be set.

You'll note that the Current Count does reach 0 but
nothing is registered.

Discussion

  • Stanislav Shwartsman

    Logged In: YES
    user_id=487634

    Do use have any testing example that I could run and
    reproduce the problem ?
    How did you seen that the problem actually exists ?
    According to the code everything should work fine.
    Most likely it looks like use problem. The timer interrupt
    (periodic or one-shot) will not be delivered to IRR if
    timer LVT is masked. I guess this is the problem in your
    code. Did you check that ?

    Pay attention that if you not software enabled APIC before
    using it, all the LVT entries are masked, including timer
    interrupt and any attempt to unmask them will me silently
    ignored by hardware.

    Thanks,
    Stanislav

     
  • Nobody/Anonymous

    Logged In: NO

    I've uploaded a floppy image, bochs cfg and the source to:
    http://www.djm.co.za/spoon/apic-irr.zip

    I was trying to debug some problems I'm having with the APIC
    and so I was printing everything out when I noticed that the
    IRR bits weren't being set in this situation.

    The floppy image boots up and sets all APIC timers to count
    down to zero, one-shot. While this is happening, all
    information is printed to screen included the contents of
    the IRR and ISR for each CPU.

    The code that is running is in spoon/kernel/apic.c and is
    test(unsigned int, unsigned int).

    I've moved the call of this test function to before and
    after everything is setup and ready to run but the same
    behaviour occurs.

    Perhaps you can see what is going on?

     
  • Nobody/Anonymous

    Logged In: NO

    Compilation of bochs was done using:

    --prefix=$INSTALLPATH --enable-sep --enable-smp
    --enable-apic --enable-vbe --enable-4meg-pages
    --enable-global-pages --enable-cpu-level=6

     
  • Stanislav Shwartsman

    Logged In: YES
    user_id=487634

    BTW, you also could look that is going on in your case.
    In this specific floppy image everything is very simple.
    You could go to the menu
    config->log options->specify log option per device,
    select device apic 0
    and choose debug events->log.

    Yes, use set APIC timer to count down to zero, one shot but
    you didn't wait enough to reach this zero point.
    According to log:

    00380111384d[APIC0] CPU 0: read from APIC address fee00020
    = 00000000
    00380203715d[CPU0 ] MOV_RdCd: read of CR4
    00380203726d[APIC0] CPU 0: read from APIC address fee000f0
    = 000000ff
    00380203730d[APIC0] CPU 0: write 0x000001ff to APIC address
    fee000f0
    00380203730d[APIC0] write 000001ff to spurious interrupt
    register
    00380203731d[APIC0] CPU 0: write 0x00000050 to APIC address
    fee00320
    00380203732d[APIC0] CPU 0: write 0x00000003 to APIC address
    fee003e0
    00380203732i[APIC0] CPU 0: set timer divide factor to 16
    00380203733d[APIC0] CPU 0: write 0xffffffff to APIC address
    fee00380
    00380203733d[APIC0] APIC: Initial Timer Count Register =
    4294967295
    00380203753d[APIC0] CPU 0: read from APIC address fee00020
    = 00000000
    00380203789d[APIC0] CPU 0: read from APIC address fee00390
    = fffffffc

    Read the log, it shows that you count toward zero from
    0xffffffff * 16 tics, which equal to 2^36 (if divide count
    eq to 16). With Bochs speed 10MIPS it means that you will
    wait for ~1.9 hours until timer will be triggerd at first
    time.

    Stanislav

     
  • Nobody/Anonymous

    Logged In: NO

    Hi!

    That's the initial timing of the APIC bus. That isn't
    supposed to reach 0. :)

    After that, (after setting the task priority to 0), the
    whole testing process begins..

     
  • Stanislav Shwartsman

    Logged In: YES
    user_id=487634

    So may be it is best for you to explain me how the APIC
    timer should behave.

    We have 3 timer registers:

    1. timer_current
    2. timer_initial
    3. timer_divide

    I understand it in following way. At least it seems to
    match the desctiption in intel PRM:
    ======
    User set some value "T" into timer_initial register and
    when coundown begins. This initial value "T" written into
    timer_current register and starts to decrement once every
    timer_divide bus clocks. When the timer_current reaches
    zero, interrupts occurs. If timer configured for one-shot,
    the timer_current remains zero. In periodic mode the
    timer_initial value "T" automatically copied into
    timer_current values and countdown begins again.
    I am only not sure about timer_divide, but I think Bochs
    implementation correct for this case too.

    You set timer_initial values to 2^32 so you have to wait
    for long time until countdown reaches zero ;)

    Stanislav

     
  • Nobody/Anonymous

    Logged In: NO

    Hi,

    That sounds pretty much right but please look past the
    initial timing of the APIC bus where I set it to 0xFFFFFFFF.

    After about a few milliseconds (200, i think), it should be
    set to 0 again and a few more APIC registers are modified.
    Then the APIC Task Priority is set to 0 and the real testing
    begins..

    For this real testing, the Initial Count is set to some
    value (for approx 10 seconds count down) and I start an
    infinite loop which prints out the values of the:

    1) Current Count
    2) ISR
    3) IRR

    ... for each cpu.

    On a real CPU and VMWare, the IRR bits are set correctly
    once the Current Count reaches 0. On Bochs, it remains unset.

    By the way, I don't see the APIC in the bochs configuration
    menu to do individual logging... i don't know why.

     
  • Stanislav Shwartsman

    Logged In: YES
    user_id=487634

    Might be it should, but it doesn't ;)
    I don't know how you define this 200ms but this is the
    debug log I got. Again, you just not wait enough for IRR to
    be set and you NEVER overwrite this 0xffffffff value for
    Initial Count register.

    =========
    00385951318d[APIC0] CPU 0: read from APIC address fee00020
    = 00000000
    00386043671d[APIC0] CPU 0: read from APIC address fee00020
    = 00000000
    00386043913d[APIC0] CPU 0: read from APIC address fee00020
    = 00000000
    00386136255d[APIC0] CPU 0: read from APIC address fee000f0
    = 000000ff
    00386136259d[APIC0] CPU 0: write 0x000001ff to APIC address
    fee000f0
    00386136259d[APIC0] write 000001ff to spurious interrupt
    register
    00386136260d[APIC0] CPU 0: write 0x00000050 to APIC address
    fee00320
    00386136261d[APIC0] CPU 0: write 0x00000003 to APIC address
    fee003e0
    00386136261i[APIC0] CPU 0: set timer divide factor to 16
    00386136262d[APIC0] CPU 0: write 0xffffffff to APIC address
    fee00380
    00386136262d[APIC0] APIC: Initial Timer Count Register =
    4294967295
    00386136282d[APIC0] CPU 0: read from APIC address fee00020
    = 00000000
    00386136318d[APIC0] CPU 0: read from APIC address fee00390
    = fffffffc
    00386136320d[APIC0] CPU 0: write 0x00000000 to APIC address
    fee00380
    00386136329d[APIC0] CPU 0: write 0x0000000a to APIC address
    fee003e0
    00386136329i[APIC0] CPU 0: set timer divide factor to 128
    00386139024d[APIC0] CPU 0: write 0x00000051 to APIC address
    fee00330
    00386139025d[APIC0] CPU 0: write 0x00000052 to APIC address
    fee00340
    00386139026d[APIC0] CPU 0: write 0x00000753 to APIC address
    fee00350
    00386139027d[APIC0] CPU 0: write 0x00000454 to APIC address
    fee00360
    00386139028d[APIC0] CPU 0: write 0x00000055 to APIC address
    fee00370

    HERE you write 0x0 to TPR

    00386139029d[APIC0] CPU 0: write 0x00000000 to APIC address
    fee00080
    00386139048d[APIC0] CPU 0: write 0x00000050 to APIC address
    fee00320
    00386139050d[APIC0] CPU 0: write 0x00000000 to APIC address
    fee00380
    00386139051d[APIC0] CPU 0: read from APIC address fee00120
    = 00000000
    00386139058d[APIC0] CPU 0: read from APIC address fee00220
    = 00000000
    00386139065d[APIC0] CPU 0: read from APIC address fee00390
    = 00000000
    00386146876d[APIC0] CPU 0: read from APIC address fee00170
    = 00000000
    00386146878d[APIC0] CPU 0: read from APIC address fee00160
    = 00000000
    00386146880d[APIC0] CPU 0: read from APIC address fee00150
    = 00000000
    00386146882d[APIC0] CPU 0: read from APIC address fee00140
    = 00000000
    00386146884d[APIC0] CPU 0: read from APIC address fee00130
    = 00000000
    00386146886d[APIC0] CPU 0: read from APIC address fee00120
    = 00000000
    00386146888d[APIC0] CPU 0: read from APIC address fee00110
    = 00000000
    00386146890d[APIC0] CPU 0: read from APIC address fee00100
    = 00000000
    00386152108d[APIC0] CPU 0: read from APIC address fee00270
    = 00000000
    00386152110d[APIC0] CPU 0: read from APIC address fee00260
    = 00000000
    00386152112d[APIC0] CPU 0: read from APIC address fee00250
    = 00000000
    00386152114d[APIC0] CPU 0: read from APIC address fee00240
    = 00000000
    00386152116d[APIC0] CPU 0: read from APIC address fee00230
    = 00000000
    00386152118d[APIC0] CPU 0: read from APIC address fee00220
    = 00000000
    00386152120d[APIC0] CPU 0: read from APIC address fee00210
    = 00000000
    00386152122d[APIC0] CPU 0: read from APIC address fee00200
    = 00000000
    00386157341d[APIC0] CPU 0: read from APIC address fee00120
    = 00000000
    00386157348d[APIC0] CPU 0: read from APIC address fee00220
    = 00000000
    00386157355d[APIC0] CPU 0: read from APIC address fee00390
    = 00000000
    00386165166d[APIC0] CPU 0: read from APIC address fee00170
    = 00000000
    00386165168d[APIC0] CPU 0: read from APIC address fee00160
    = 00000000

    The individual logging for devices available only at
    runtime. The dialog could be accessed if you press config
    button in runtime Bochs window.

    ....

    Ok, I see something different now. What do you expect for
    APIC timer after setting timer_inital to 0 ?
    I see you overwrite Timer Intial Count register with 0.
    Bochs starts to count from new Timer Intial Count value
    after the value has been written. It cannot of course to
    count from 0 so writing of zero to Timer Intial Count only
    switches existent counting off and nothing more. This is
    exactly that you do.

    Do you know smth different that should be done in this
    case ?

    BTW, you could write me directly to stl AT fidonet.org.il

    Stanislav

     
  • Nobody/Anonymous

    Logged In: NO

    Thanks! I've sent you an email with debug output from my
    log file. It clearly shows the steps that it takes and it
    also clearly shows that the IRR bit is not set.

    Maybe you can see something in it..

     
  • Stanislav Shwartsman

    Logged In: YES
    user_id=487634

    Ok, finally I see a problem !
    The problem is not in the IRR itself, the IRR bit set
    correctly (I even see the bit in save/restore tree in
    recent release). Bit if you read the IRR register Bochs
    wrongly collects IRR bits to 32-bit register.

    Here is the fix for IRR/ISR/TMR reading in cpu/apic.cc
    Replace the code in read_aligned method with the following:

    case 0x100: case 0x110:
    case 0x120: case 0x130:
    case 0x140: case 0x150:
    case 0x160: case 0x170:
    {
    unsigned index = (addr2 - 0x100) << 1; <<<
    here changed
    Bit32u value = 0, mask = 1;
    for(int i=0;i<32;i++) {
    if(isr[index+i]) value |= mask;
    mask <<= 1;
    }
    data = value;
    }
    break;
    case 0x180: case 0x190:
    case 0x1a0: case 0x1b0:
    case 0x1c0: case 0x1d0:
    case 0x1e0: case 0x1f0:
    {
    unsigned index = (addr2 - 0x180) << 1; <<<
    here changed
    Bit32u value = 0, mask = 1;
    for(int i=0;i<32;i++) {
    if(tmr[index+i]) value |= mask;
    mask <<= 1;
    }
    data = value;
    }
    break;
    case 0x200: case 0x210:
    case 0x220: case 0x230:
    case 0x240: case 0x250:
    case 0x260: case 0x270:
    {
    unsigned index = (addr2 - 0x200) << 1; <<<
    here changed
    Bit32u value = 0, mask = 1;
    for(int i=0;i<32;i++) {
    if(irr[index+i]) value |= mask;
    mask <<= 1;
    }
    *data = value;
    }
    break;

    Stanislav

     

Log in to post a comment.

MongoDB Logo MongoDB