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.
Hey guys, well I spent the last two months of my life writing an 8086 Emulator for my Os so I could run Bios calls (Shudder), it works but doesn't run very fast and has a lot of flaws. So I decided to try another approach, I know you all told me to try this first but, oh well. I'm stubborn
Ok so I read the wiki on V86 mode and I know that you have to set a flag when do an iret. Now I don't use Rings. There is no real protection in my os. If I am right everything runs in Ring 0. So here is my current IRQ code that gets called when an interrupt occurs:
irq_int: dd 0
irq_end: dd 0
irq_common_stub:
pop dword[irq_int]
;Save all the registers
;to the stack
;pushad
push eax
push ebx
push ecx
push edx
push ebp
push edi
push esi
;Prevent interrupts from being
;started again
call Thread_Ignore
;Try to save the current stack
;to the thread running
mov eax, esp
push eax
call iPear.Multitasking.Core.SaveStack_U32
;Now try to run Masked IRQ's
push dword[irq_int]
call iPear.Hardware.IRQ.Invoke_U32
;Now attempt to switch threads
;if we can.
call iPear.Multitasking.Core.Switch
pop eax
cmp eax, 0
je .End ;Not a valid stack
;Otherwise set our new stack
mov esp, eax
.End:
;Now send our end of interrupt
mov eax, dword[irq_int]
add eax, 32
push eax
call PIC_EOI
;Now unignore threads
call Thread_UnIgnore
;Ok now we have to restore all the registers.
;popad
pop esi
pop edi
pop ebp
pop edx
pop ecx
pop ebx
pop eax
;Restore interrupts.
;sti
;Now just return.
iret
This supports Multitasking already, but how would I go about creating a VM task? What's the best approach with what I have? I don't have paging setup or enabled either.
Just read the VM86 chapter in the Intel manual, it is quite readable and contains everything you need to know. If you don't have good reasons, ignore the hardware task switching part and use iret with the eflags.VM set.
It boils down to creating a ring 3 task (sorry, you'll have to introduce this) with eflags.VM set, and extending the interrupt stack frame with the real mode segment registers (they are automatically pushed when an interrupt occurs in VM86, and popped when you iret into VM86). A few instructions will cause a GPF and you'll have to emulate them in the GPF handler.
Kevin wrote:Just read the VM86 chapter in the Intel manual, it is quite readable and contains everything you need to know. If you don't have good reasons, ignore the hardware task switching part and use iret with the eflags.VM set.
It boils down to creating a ring 3 task (sorry, you'll have to introduce this) with eflags.VM set, and extending the interrupt stack frame with the real mode segment registers (they are automatically pushed when an interrupt occurs in VM86, and popped when you iret into VM86). A few instructions will cause a GPF and you'll have to emulate them in the GPF handler.
Ok thanks I tried to find it in the intel manual but I didn't see it. Could you please provide a link? Do you have to have ring 3? Couldn't you just setup a 8086 tss and then set the vm bit in the eflags pushed onto the stack and do a iret like I would with a task?
PearOs wrote:Ok thanks I tried to find it in the intel manual but I didn't see it. Could you please provide a link?
Not sure if it has changed in the most recent revision, but in my copy it's chapter 15 "8086 emulation" in volume 3A.
Do you have to have ring 3? Couldn't you just setup a 8086 tss and then set the vm bit in the eflags pushed onto the stack and do a iret like I would with a task?
VM86 tasks are ring 3 tasks by definition. I don't think you actually need ring 3 segments in your GDT because you're using RM segment registers in VM86, but the permissions of ring 3 apply for any code running in VM86 (most importantly, for paging and I/O).
You need a 32-bit TSS for switching into VM86 (well, actually just for switching out of it if you use iret with eflags.VM set on the stack to switch into VM86). If you had ring 3 tasks, I would say that you can probably reuse the same TSS, but why do you even have a TSS for ring 0 tasks? Or do you mean, like you would do if you had ring 3 tasks?
PearOs wrote:Ok thanks I tried to find it in the intel manual but I didn't see it. Could you please provide a link?
Not sure if it has changed in the most recent revision, but in my copy it's chapter 15 "8086 emulation" in volume 3A.
Do you have to have ring 3? Couldn't you just setup a 8086 tss and then set the vm bit in the eflags pushed onto the stack and do a iret like I would with a task?
VM86 tasks are ring 3 tasks by definition. I don't think you actually need ring 3 segments in your GDT because you're using RM segment registers in VM86, but the permissions of ring 3 apply for any code running in VM86 (most importantly, for paging and I/O).
You need a 32-bit TSS for switching into VM86 (well, actually just for switching out of it if you use iret with eflags.VM set on the stack to switch into VM86). If you had ring 3 tasks, I would say that you can probably reuse the same TSS, but why do you even have a TSS for ring 0 tasks? Or do you mean, like you would do if you had ring 3 tasks?
I don't even use a TSS lol. For my multitasking I simply push the registers, the flags, and a few other things and then when that task runs for the first time it switches stacks and then that task is running and then next it comes around that stack is saved into that task and then its just a matter of save/load each time.
I understand how to get into User Mode, but How do I get back into Ring0? That's my only question. I will never use User Mode other than to run a V8086 task.
BMW wrote:I understand how to get into User Mode, but How do I get back into Ring0?[
Because the second line I quoted is the answer to your question.
Oh... Well wait though, that article states Sysenter/Sysexit are the way to get from Usermode to Ring 0 but I want to get back to Ring 0 and stay there again until I have to get back to usermode. Or am I understanding this entirely wrong? Thanks a ton, Matt
PearOs wrote:Oh... Well wait though, that article states Sysenter/Sysexit are the way to get from Usermode to Ring 0 but I want to get back to Ring 0 and stay there again until I have to get back to usermode. Or am I understanding this entirely wrong? Thanks a ton, Matt
No I was meaning the interrupt method... simply call a designated interrupt number from ring 3 which will call the interrupt handler in ring 0, and bingo! you are back in ring 0. It's a bit like a system call, except you don't return to usermode.
PearOs wrote:Oh... Well wait though, that article states Sysenter/Sysexit are the way to get from Usermode to Ring 0 but I want to get back to Ring 0 and stay there again until I have to get back to usermode. Or am I understanding this entirely wrong? Thanks a ton, Matt
No I was meaning the interrupt method... simply call a designated interrupt number from ring 3 which will call the interrupt handler in ring 0, and bingo! you are back in ring 0. It's a bit like a system call, except you don't return to usermode.
Oh! I see so if I jump to Usermode and then do lets say INT 50 it would call my Kernel IRQ handler and when I do a IRET I would be back into Ring 0 in the code that was just in User mode?
PearOs wrote:Oh! I see so if I jump to Usermode and then do lets say INT 50 it would call my Kernel IRQ handler and when I do a IRET I would be back into Ring 0 in the code that was just in User mode?
Oh, so you want to be back in the same code, but in ring 0. Yes, that method you described should work, as long as you set the pushed segment registers up so that IRET returns to ring 0.
PearOs wrote:Oh! I see so if I jump to Usermode and then do lets say INT 50 it would call my Kernel IRQ handler and when I do a IRET I would be back into Ring 0 in the code that was just in User mode?
Oh, so you want to be back in the same code, but in ring 0. Yes, that method you described should work, as long as you set the pushed segment registers up so that IRET returns to ring 0.
Ok let me explain a little better. I am trying to implement V8086 mode. I do not have any Rings setup except for Ring0 which is my default in my IRQ Handler which is posted in my first post above. From what I understand the V8086 task has to run in Ring3 so I need to write code to create a V8086 task in Ring3, run whatever code I want in there to set a video mode, and return back to where my Kernel last was before calling the SetVideo mode function for V8086.
Ok, the INT/IRET should work. When an interrupt occurs, the segment registers are pushed onto the stack, and popped when IRET is called. You will have to modify the values of the segment registers on the stack so that when IRET is called, the values for the segment registers have a requested privilege level (RPL) of 0 (ring 0), in order to return in ring 0.