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:
You'll note that the Current Count does reach 0 but
nothing is registered.
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
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?
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
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
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..
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:
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
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.
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
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
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..
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