[Closed]Interrupt 14 when executing first assembly instruction in ring 3.

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.
Post Reply
stskyblade
Posts: 17
Joined: Sun Jul 28, 2024 9:56 pm

[Closed]Interrupt 14 when executing first assembly instruction in ring 3.

Post by stskyblade »

I'm trying to load and execute user level program in my kernel code. I use an "iret" to jump from my kernel code to user level program. The first assembly instruction is "mov $1, %eax". I got an interrupt 13 when executing this simple instruction.

What I saw in Gdbgui:
After "iret", CS, EIP, SS, ESP contain the value I give. Then, execute one machine instruction, which is "movl $1, %eax". Control flow transfered to interrupt handler 13.

Guess:
My context switching code is not right. But I can't figure it out.
https://wiki.osdev.org/Getting_to_Ring_3

My project can be found here:
https://github.com/stskyblade/StarOS/tr ... ocess-soft
At git branch: dev-process-soft

How to build:

Code: Select all

git clone -b dev-process-soft https://github.com/stskyblade/StarOS.git
cd StarOS
mkdir build
cd build
cmake ..
cmake --build . --target qemu
cmake --build . --target debug # for gdb debug
cd <Project_root>
gdbgui .  # start a gui gdb

Explanation of my code: https://github.com/stskyblade/StarOS/bl ... s.cpp#L123
- set up a new page directory for the process
- add ring 3 data segment and code segment to GDT
- set DS, ES, FS, GS with ring 3 data segment
- push SS, ESP, EFLAGS, CS, IP. These value will be used by "iret". I don't know what value should EFLAGS be, I tried 0, or current ESP.
- change CR3
- iret

Here is the program I try to load: https://github.com/stskyblade/StarOS/bl ... add.cpp#L3
For debugging, I jump over the function prologue. Just start with the first inline assembly code.

Memory config:
I enable both segmentation and paging. Every segment starts at address 0x0. Kernel and User program have different segment and page directory.
Kernel code and data are mapped to high address. You can find it here: https://github.com/stskyblade/StarOS/bl ... rnel.h#L31
In kernel, virtual address = linear address = physical address.
User program uses a different page directory. Kernel code has been mapped to same address in user program space as kernel space.
Last edited by stskyblade on Wed Jan 08, 2025 6:23 pm, edited 2 times in total.
Octocontrabass
Member
Member
Posts: 5623
Joined: Mon Mar 25, 2013 7:01 pm

Re: Interrupt 13 when executing first assembly instruction in ring 3.

Post by Octocontrabass »

What's the error code?

Better yet, what does QEMU's "-d int" log say?
stskyblade
Posts: 17
Joined: Sun Jul 28, 2024 9:56 pm

Re: Interrupt 13 when executing first assembly instruction in ring 3.

Post by stskyblade »

Octocontrabass wrote: Sun Jan 05, 2025 7:04 pm What's the error code?

Better yet, what does QEMU's "-d int" log say?
Do you mean the error code of Interrupt 13? It's 0x00000005.

Here is the output of qemu:

Code: Select all

check_exception old: 0xffffffff new 0xe                                                                                                 
     1: v=0e e=0005 i=0 cpl=3 IP=0023:10000006 pc=10000006 SP=002b:0feffffc CR2=10000006
EAX=78503000 EBX=590060a0 ECX=00000018 EDX=00000018                 
ESI=78504000 EDI=0000aa85 EBP=52d07fe4 ESP=0feffffc                 
EIP=10000006 EFL=00000206 [-----P-] CPL=3 II=0 A20=1 SMM=0 HLT=0    
ES =002b 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]                
CS =0023 00000000 ffffffff 00cffa00 DPL=3 CS32 [-R-]                
SS =002b 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]                
DS =002b 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]                
FS =002b 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]                
GS =002b 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]                
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT                       
TR =0018 59005000 00000068 00008900 DPL=0 TSS32-avl                 
GDT=     52c06000 00001000        
IDT=     52d08020 000007ff        
CR0=80000011 CR2=10000006 CR3=78503000 CR4=00000000                 
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000                 
DR6=ffff0ff0 DR7=00000400         
CCS=00000004 CCD=10000006 CCO=EFLAGS                                
EFER=0000000000000000 
old: 0xffffffff new 0xe
1: v=0e e=0005 i=0
are what I don't know.
IP=0023:10000006 pc=10000006 SP=002b:0feffffc
are what I set.
CR2=10000006
I haven't modify this.

General registers are not changed in this context switch.

User code segment has index 4. User Data segment has index 5. CS, DS, ES, FS, GS, SS are what I set.
Task state segment has index 3. TR is what I set.

GDT, IDT have correct value. LDT is not used.
CR3 has the value I set.

For other registers, I haven't change the value of them and don't know what do them mean.
MichaelPetch
Member
Member
Posts: 801
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Interrupt 13 when executing first assembly instruction in ring 3.

Post by MichaelPetch »

1: v=0e e=0005 i=0
v=0e is page fault exception. e= is the error code. e=0005 Is a page protection violation when performing a read while in user mode (cpl=3). Information on decoding the page fault error code can be found here: https://wiki.osdev.org/Exceptions#Page_Fault . Given that CR2 (the memory address that caused the fault) and your EIP are the same address I'll assume that the instruction couldn't be fetched. A couple of possibilities. Have you properly marked the pages to allow execution and set the user bit?

Edit: Interrupt v=0e (hex) is interrupt 14 (decimal), not 13.
User avatar
iansjack
Member
Member
Posts: 4716
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Interrupt 13 when executing first assembly instruction in ring 3.

Post by iansjack »

You can use the

Code: Select all

info mem
command in Qemu's monitor to check your memory mapping. As Michael said, it's pretty clear that the address being executed is not properly mapped.
stskyblade
Posts: 17
Joined: Sun Jul 28, 2024 9:56 pm

Re: Interrupt 13 when executing first assembly instruction in ring 3.

Post by stskyblade »

Yes, it's an interrupt 14 due to page protection violation. The "user or supervisor" bit in page directory entry is "supervisor". But my code want to access it in CPL 3. So it's wrong. After I change this bit, my program works well. Thank you everyone! :) This is really an exciting moment. I finally understand how a user level program run. Memory, paging, process, context, all these terms comes to reality.



Interrupt 13 or 14:
I've test it by executing "int $14". My kernel code outputs interrupt 13, but Qemu outputs interrupt 14. So my code is not right. But I just don't understand.
IDT is an array of 256 entries, indexed from 0 to 255. My interrupt handler assign a number to each entry. Numbers counts from 0 to 255. Why does "int $14" calls the 14th handler which has index 13? I thought handler 0 is for "int $0", handler 1 for "int $1"... handler 14 for "int $14".
Octocontrabass
Member
Member
Posts: 5623
Joined: Mon Mar 25, 2013 7:01 pm

Re: Interrupt 13 when executing first assembly instruction in ring 3.

Post by Octocontrabass »

stskyblade wrote: Mon Jan 06, 2025 8:43 pmWhy does "int $14" calls the 14th handler which has index 13?
It doesn't. You installed the handler for interrupt 13 at index 14 by mistake. All of your handlers are installed at the wrong index. The problem is in this loop.
Post Reply