Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
spectrum
Member
Posts: 37 Joined: Wed Jun 13, 2007 7:06 am
Post
by spectrum » Thu Jul 05, 2007 1:00 am
hi all,
i'm quite new in os developement, and need some help about enabling inerrupts on a little pm os i'm trying to develope. I'm trying to prepare the PM ivt, as specified in the intel manual, with just the int 0x80, but after enabling interrupts (lidt) and trying to call int 80h the system reset.
This is the bochs output:
Code: Select all
00001062423d[CPU0 ] interrupt(): vector = 128, INT = 1, EXT = 0
00001062423e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00001062423d[CPU0 ] exception(0x0D)
00001062423d[CPU0 ] interrupt(): vector = 13, INT = 0, EXT = 1
00001062423e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00001062423d[CPU0 ] exception(0x0D)
00001062423d[CPU0 ] interrupt(): vector = 8, INT = 0, EXT = 1
00001062423e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00001062423d[CPU0 ] exception(0x0D)
00001062423i[CPU0 ] protected mode
00001062423i[CPU0 ] CS.d_b = 32 bit
00001062423i[CPU0 ] SS.d_b = 32 bit
00001062423i[CPU0 ] EFER = 0x00000000
00001062423i[CPU0 ] | RAX=00000000000003f8 RBX=000000000000000e
00001062423i[CPU0 ] | RCX=0000000000000000 RDX=0000000000000400
00001062423i[CPU0 ] | RSP=000000000001ffdc RBP=000000000001ffe8
00001062423i[CPU0 ] | RSI=00000000000001ab RDI=00000000000001ab
00001062423i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
00001062423i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
00001062423i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
00001062423i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
00001062423i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00001062423i[CPU0 ] | SEG selector base limit G D
00001062423i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00001062423i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00001062423i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00001062423i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00001062423i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00001062423i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00001062423i[CPU0 ] | GS:0018( 0003| 0| 0) 000b8000 00000f9f 0 0
00001062423i[CPU0 ] | MSR_FS_BASE:0000000000000000
00001062423i[CPU0 ] | MSR_GS_BASE:00000000000b8000
00001062423i[CPU0 ] | RIP=00000000000085a3 (00000000000085a3)
00001062423i[CPU0 ] | CR0=0x00000011 CR1=0x0 CR2=0x0000000000000000
00001062423i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00001062423i[CPU0 ] >> int 0x80 : CD80
and thet is the involved part of my code
Code: Select all
#pragma pack(1)
struct _idt_reg {
ushort size;
ulong base;
} __attribute__ ((aligned(16)));
struct _idt_gate_desc {
ushort offset_procedure_0_15;
ushort segment_selector;
ushort zero:8;
ushort mask:8;
ushort offset_procedure_16_32;
};
#pragma pack()
struct _idt_reg idtr;
static void _fill_idt (ulong int_n, ulong linear_offset)
{
struct _idt_gate_desc igd;
kmemset ((unsigned char *)&igd, 0, sizeof(struct _idt_gate_desc));
igd.offset_procedure_0_15 = (ushort) linear_offset & 0xffff;
igd.segment_selector = (ushort) 0x08;
igd.zero = 0;
igd.mask = 0x8E;
igd.offset_procedure_16_32 = (ushort) ((linear_offset>>16) & 0xffff);
kmemcpy ( _idt_start + ((int_n-1) * 8),
(unsigned char *)&igd,
sizeof(struct _idt_gate_desc)
);
}
void k_load_ivt ()
{
_fill_idt (0x80, (unsigned long)&_int_0x80);
idtr.size = 255*8-1;
idtr.base = 0;
asm ("lidt idtr");
//asm ("sti");
__asm__ __volatile__
(
" pushl $0x01 \n"
" int $0x80 \n"
" addl $4, %esp \n"
);
for (;;);
}
every help or suggestion is very appreciated
many thanks,
angelo
AJ
Member
Posts: 2646 Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:
Post
by AJ » Thu Jul 05, 2007 1:20 am
Hi,
Where does _idt_start point to? Your idtr.base suggestst that it is at the start of memory. Shouldn't idtr.base be _idt_start?
Also, rather than the memory copy if you had _idt_start as type _idt_gate_desc *, you could just add a new entry by doing:
Code: Select all
_idt_start[offset].offset_procedure_0_15 = &whatever;
...
...
HTH,
Adam
Last edited by
AJ on Thu Jul 05, 2007 2:00 am, edited 1 time in total.
exkor
Member
Posts: 111 Joined: Wed May 23, 2007 9:38 pm
Post
by exkor » Thu Jul 05, 2007 1:54 am
Make sure you zero all 2KB of memory that your IDT takes.
idtr.base and _idt_start suppose to reference same memory,as far as I understand its where your IDT starts.
edited: Memory Mapped IO maybe located at 0 address even if RealMode IDT starts there.
spectrum
Member
Posts: 37 Joined: Wed Jun 13, 2007 7:06 am
Post
by spectrum » Thu Jul 05, 2007 2:22 am
thanks,
AJ,
for now i was planning to keep the idt starting just at 0, as done in real mode, but if you can suggest me a better offset, i will use it and,
fine, 've modified the gate table assignment way using the whole structure assignment.
exkor,
yes, idt start at 0, and _idt_start is at 0 too.
now i try to clean all the gates slots.
Thanks for now
spectrum
Member
Posts: 37 Joined: Wed Jun 13, 2007 7:06 am
Post
by spectrum » Thu Jul 05, 2007 2:28 am
nothing change after the table has been cleaned.
the error is always the same
00001072674e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
maybe there can be a problem on my kernel segment type (the 0x08 offset), that is not system type ? I attach the gdt.
Code: Select all
gdtinfo: .word (gdtend - gdt -1)
.long gdt
gdt: .long 0 /* null descriptor, as per convention gdt0 is 0 */
.long 0
.equ codesel, .- gdt
desc_code: /* 32bit Flat Data, 0-4GB Writable */
.word 0xFFFF /* segment limit 0:15 */
.word 0 /* base address 0:15 */
.byte 0 /* base address 16:23 */
.byte 0x9A /* 1xP|2xDPL|1xS|4xtype 0x9A = 1|0 0|1|1010 */
.byte 0xCF /* 1xG|1xD/B|1x0|1xAVL|4xlimit 0xCF = 1|1|0|0|1111 */
.byte 0 /* base address 24:31 */
.equ datasel, .- gdt
desc_data:
.word 0xFFFF /* segment limit 0:15 */
.word 0 /* base address 0:15 */
.byte 0 /* base address 16:23 */
.byte 0x92 /* 1xP|2xDPL|1xS|4xtype 0x92 = 1|0 0|1|0010 */
.byte 0xCF /* 1xG|1xD/B|1x0|1xAVL|4xlimit 0xCF = 1|1|0|0|1111 */
.byte 0 /* base address 24:31 */
gdtend:
angelo
exkor
Member
Posts: 111 Joined: Wed May 23, 2007 9:38 pm
Post
by exkor » Thu Jul 05, 2007 2:42 am
You could move your IDT in safer location such as after where BIOS loads the bootsector (7e00h) or above 1mb(you can do that from protected mode or maybe from unreal).
And set limit of IDT to 80 entries otherwise you may have problems if IDT located above 7c00h: idtr.size = 81*8-1;
You can some look examples at
http://www.osdever.net/tutorials.php?cat=0&sort=1
jnc100
Member
Posts: 775 Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:
Post
by jnc100 » Thu Jul 05, 2007 3:08 am
Spectrum wrote: Code: Select all
kmemcpy ( _idt_start + ((int_n-1) * 8),
I assume you're defining _idt_start to 0x0. By that logic, by calling this function with int_n as 0x80, you're actually setting entry 0x7F of the table, and 0x80 is still undefined. Get rid of the '-1' after int_n. If you're using bochs debugger, you can break on the int 0x80 call and check the output of 'info idt' there to make sure everything is set up properly.
As a side note, it probably isn't a good idea to overwrite your real mode idt because if you want to run v8086 services later, you're going to need it. Personally, I set up my idt above 1MB.
Regards,
John
spectrum
Member
Posts: 37 Joined: Wed Jun 13, 2007 7:06 am
Post
by spectrum » Thu Jul 05, 2007 3:11 am
jnc100,
that was the issue, infinite thanks and really congrats to have found it.
Was my stupid assumption, that interrupts start from integral 1, for this, 0x80 was condidered that had to stay at 0x7f position. Intel manual also show a picture where it puts "interupt #1" at position 0. That kept me out of the way.
Now works great.
Thanks all,
angelo