I use to think that interrupt stubs should just push registers, push segments, and jmp to the interrupt handler and then just pop everything else
but really there is more to it but I'm not for sure what all, I want to be able to have interrupts in interrupts and I want to be able use a different code, data and stack segment for interrupt handlers
Also I will be doing code "templating" like I will copy 1 template 256 times(for each interrupt) and then just replace a dword(which is after call) so that it will call the appropriate interrupt handler
and one more thing I want to be able to do is be able to access everything that is saved(on the stack) in the interrupt handler(just push the stack pointer..)
right now I have
;stuff pushed by int is eip,flags, and CS, user_esp, and SS
push_segments
pusha
well..bout here I can't figure out a half good method for saving segments..
What to do on interrupt stubs?
ok, well i don't need help any more(I hope)
I haven't been able to test it yet, but it does compile:
I will copy the template 256 times and then just modify it(runtime modified code..) to install an interrupt handler..
and the final interrupt handler will just be void MyInterrupt(regs *r);
with regs being...very simple for the interrupt handler, very complicated for me..
I haven't been able to test it yet, but it does compile:
I will copy the template 256 times and then just modify it(runtime modified code..) to install an interrupt handler..
and the final interrupt handler will just be void MyInterrupt(regs *r);
with regs being...very simple for the interrupt handler, very complicated for me..
Code: Select all
typedef struct
{
unsigned int ds, es, fs, gs; /* pushed the segs last */
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; /* pushed by 'pusha' */
unsigned int int_no, err_code; /* our 'push byte #' and ecodes do this */
unsigned int eip, cs, eflags, useresp, ss; /* pushed by the processor automatically */
}
regs;
Code: Select all
far_template:
mov ebp,esp
add ebp,12 ;skip the pushed ip and cs and then it's where we pushed esp
mov eax,[ss:ebp]
push eax ;push the stack pointer again..
mov eax,0x20000000 ;the value is at offset 0xE
call eax ;this is templated! 0x200 should be what the interrupt handler is ;this is templated! 0x200 should be what the interrupt handler is
pop eax
retf ;<--end total size of far_template is 22 bytes
int_template:
cli
push eax
mov al,0 ;this is templated! this should be 0 for most interrupts, or 1 if a value is already pushed.. -at 0x3
cmp al,1
jz no_pushing
jmp pushing
no_pushing:
jmp continue_1
pushing:
push 0 ;this is for a dummy error code..
continue_1:
pop eax
push 20 ;this is templated! 20 should be replaced with the interrupt number -at 0x19
pusha
push ds
push es
push fs
push gs
mov ecx,0
mov cx,ss
mov edx,esp ;store them for a bit..
mov ax,0x8 ;this is templated! 0x8 should be replaced with interrupt stack segment -0x30
mov ss,ax
mov esp,0x100 ;this is templated! 0x100 should be replaced with interrupt stack offset -at 0x35
push ecx ;push our saved ss
push edx ;push our saved esp
mov ax,0x08 ;this is templated! 0x08 should be replaced with interrupt data segment -at 0x3D
mov ds,ax ;setup data segments..
mov fs,ax
mov gs,ax
mov ax,cx
add edx,21*4 ;increment stack ptr to the first part of our interrupt..
mov es,ax ;set our es to the old ss
mov ecx,21
copy_loop: ;copy the data in the application stack to our interrupt stack
mov ebx,edx
mov esi,[es:ebx]
push esi
sub edx,4
loop copy_loop
ending_:
mov ax,ds
mov es,ax
mov eax,esp
push eax ;push the stack pointer so we can use it as an argument in our called function
;mov ebx,0x20 ;This is templated! 0x20 should be replaced with interrupt code offset
;crap...we have to have a far ret..hmmm
;only good solution I can think of is you have to tell a spot of memory in the segment(address space) that we can load a far ret capable thing..
;and just have to write something like push esp+8(I think)\ncall int_handler\n retf\n ..or something to deal with that call..
call 0x10:0x14000 ;This is templated! 0x10 should be replaced with interrupt code segment and 0x200 should be replaced with the farcall stub
;offset is at 0x6C, segment at 0x70
pop eax ;trash from the argument
pop edx ;our earlier pushed esp
pop esi ;our earlier pushed SS
mov ss,si
mov edx,esp
pop gs
pop fs
pop es
pop ds
mov al,0 ;this is templated! this should be 0(or anything) for normal interrupt, 1 for master irq, 2 for slave irq -at 0x80
cmp al,1
jz master_irq
cmp al,2
jz slave_irq
return_here:
popa
add esp,8 ;we do this cause we can't use a temp register basically it's just pop [temp] and pop [temp] again
iret
master_irq:
mov al,0x20
out 0x20, al
jmp return_here
slave_irq:
mov al,0x20
out 0xA0, al
out 0x20, al
jmp return_here
hlt ;<--End template size is 160 bytes
Hi,
Hmm - 160 bytes that are repeated 256 times adds up to 40 KB of stubs!
Some questions:
Followed by some "once only" code like this:
Then, all you'd need to do is construct the IDT using offsets in the table at "interrupt_setup_table" in the data section (plus add an IDT entry for the kernel API), and then provide C functions for "_kernel_API_entry_in_C_code(<lots>)", "_exception_handler_in_C_code(<lots>)" and "_IRQ_handler_in_C_code(<lots>)".
Just some thoughts...
BTW if an IRQ interrupts the kernel's code, there will be no userSS and userESP pushed on the stack by the CPU.
Cheers,
Brendan
Hmm - 160 bytes that are repeated 256 times adds up to 40 KB of stubs!
Some questions:
- - do you actually need 256 stubs, or is 49 enough (32 for exceptions, 16 for IRQs and one for the kernel API)?
- can you use 4 different stub types (one for exceptions without error codes, one for exceptions with error codes, one for IRQs and the last for the kernel API)?
- would it be better to send the EOI to the PIC in C code, so that it's easier to support APICs later?
- can you recycle code, so that the entry code just pushes some info onto the stack and jumps to generic exit code?
- do you need templates, or are macros easier?
Code: Select all
%macro EXCEPTION_STUB_NO_ERROR_CODE 1
section .text
align 4
%%1:
push 0x00000000 ;Put a fake error code on the stack
push %1 ;Put the exception number on the stack
jmp GENERIC_EXCEPTION_STUB
section .data
dd %%1
section .text
%endmacro
%macro EXCEPTION_STUB_WITH_ERROR_CODE 1
section .text
align 4
%%1:
push %1 ;Put the exception number on the stack
jmp GENERIC_EXCEPTION_STUB
section .data
dd %%1
section .text
%endmacro
%macro IRQ_STUB 1
section .text
align 4
%%1:
push 0x00000000 ;Put a fake error code on the stack
push %1 ;Put the IRQ number on the stack
jmp GENERIC_IRQ_STUB
section .data
dd %%1
section .text
%endmacro
Code: Select all
section .data
align 4
interrupt_setup_table:
EXCEPTION_STUB_NO_ERROR_CODE 0
EXCEPTION_STUB_NO_ERROR_CODE 1
EXCEPTION_STUB_NO_ERROR_CODE 2
EXCEPTION_STUB_NO_ERROR_CODE 3
EXCEPTION_STUB_NO_ERROR_CODE 4
EXCEPTION_STUB_NO_ERROR_CODE 5
EXCEPTION_STUB_NO_ERROR_CODE 6
EXCEPTION_STUB_NO_ERROR_CODE 7
EXCEPTION_STUB_WITH_ERROR_CODE 8
EXCEPTION_STUB_NO_ERROR_CODE 9
EXCEPTION_STUB_NO_ERROR_CODE 10
EXCEPTION_STUB_NO_ERROR_CODE 11
EXCEPTION_STUB_NO_ERROR_CODE 12
EXCEPTION_STUB_WITH_ERROR_CODE 13
EXCEPTION_STUB_WITH_ERROR_CODE 14
EXCEPTION_STUB_NO_ERROR_CODE 15
EXCEPTION_STUB_NO_ERROR_CODE 16
EXCEPTION_STUB_WITH_ERROR_CODE 17
EXCEPTION_STUB_NO_ERROR_CODE 18
EXCEPTION_STUB_NO_ERROR_CODE 19
EXCEPTION_STUB_NO_ERROR_CODE 20
EXCEPTION_STUB_NO_ERROR_CODE 21
EXCEPTION_STUB_NO_ERROR_CODE 22
EXCEPTION_STUB_NO_ERROR_CODE 23
EXCEPTION_STUB_NO_ERROR_CODE 24
EXCEPTION_STUB_NO_ERROR_CODE 25
EXCEPTION_STUB_NO_ERROR_CODE 26
EXCEPTION_STUB_NO_ERROR_CODE 27
EXCEPTION_STUB_NO_ERROR_CODE 28
EXCEPTION_STUB_NO_ERROR_CODE 29
EXCEPTION_STUB_NO_ERROR_CODE 30
EXCEPTION_STUB_NO_ERROR_CODE 31
IRQ_STUB 0
IRQ_STUB 1
IRQ_STUB 2
IRQ_STUB 3
IRQ_STUB 4
IRQ_STUB 5
IRQ_STUB 6
IRQ_STUB 7
IRQ_STUB 8
IRQ_STUB 9
IRQ_STUB 10
IRQ_STUB 11
IRQ_STUB 12
IRQ_STUB 13
IRQ_STUB 14
IRQ_STUB 15
align 4
KERNEL_API_STUB:
sub esp,8 ;Make stack frame same as other interrupt sources
pusha
push ds
push es
push fs
push gs
call _kernel_API_entry_in_C_code
pop gs
pop fs
pop es
pop ds
popa
add esp,8
iret
align 4
GENERIC_EXCEPTION_STUB:
pusha
push ds
push es
push fs
push gs
call _exception_handler_in_C_code
pop gs
pop fs
pop es
pop ds
popa
add esp,8
iret
align 4
GENERIC_IRQ_STUB:
pusha
push ds
push es
push fs
push gs
call _IRQ_handler_in_C_code
pop gs
pop fs
pop es
pop ds
popa
add esp,8
iret
Just some thoughts...
BTW if an IRQ interrupts the kernel's code, there will be no userSS and userESP pushed on the stack by the CPU.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.