Usermode GPF

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.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Usermode Triple Fault

Post by Octacone »

crunch wrote:
octacone wrote:I have no idea what is going on. I checked everything twice. I just don't get it. Other people have entered user mode without any problem, every tutorial I've ever seen just magically works.
I understand the feeling. Took me about 5 days of banging my head on the wall to get it working. And it was because I wasn't using a separate user-access paged stack.

Code: Select all

enter_usermode:
	;push ebp
	mov ebp, esp
	cli

	mov ax, 0x20 | 3
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax

	push 0x20 | 3	; push ss3

	mov ecx, [ebp+8]
	push ecx ; push esp3

	pushf  ; push flags onto stack
	pop eax ; pop into eax
	or eax, 0x200 ; set IF (enable interrupts)
	push eax ; push eflags
	push 0x18 | 3 ; push CS, requested priv. level = 3

	xor eax, eax  ; Clear eax
	mov eax, [ebp+4] ; Load new IP into eax
	push eax ; Push EIP onto stack

	iret

To use this, allocate a new physical page for the user-level stack. Map that physical page to some address and make sure that you set the user-accessible flag in the page table entry. enter_usermode(address_of_function, user_stack). Remember that the stack grows down, so if for instance, you chose to map 0x0-0x1000 for your user stack, pass the function 0xF00 as a test.
I have never heard of this concept before. I am still getting triple faults. What am I doing wrong?

Code: Select all

uint32_t user_stack;
Map_Physical_Virtual(user_stack, 0x1000, 4096, Page_Writeable | Page_Present | Page_User);
Enter_User_Mode(0xF00, user_stack);
Bochs log: (unk. ctxt): mov eax, dword ptr ds:0xcf1f0013 ; a113001fcf
Also why did you uncomment "push ebp"?
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Ch4ozz
Member
Member
Posts: 170
Joined: Mon Jul 18, 2016 2:46 pm
Libera.chat IRC: esi

Re: Usermode GPF

Post by Ch4ozz »

He just told you that a stack is growing downwards (in terms of addresses)
Your func even only accepts 1 parameter, how do you expect this to work?

Code: Select all

Enter_User_Mode(user_stack + 0xFFC);
This is what he told you to do.

Push EBP is useless since you dont restore it anyways.
Anyways you should use a location which is greater then 0x1000 for the stack.
Pick some random one but dont be too low or too high

Also whats user_stack for in your example? Its some random uninitialized stack data.

TIP: Download IDA and reverse your own binary
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Usermode GPF

Post by Octacone »

Ch4ozz wrote:He just told you that a stack is growing downwards (in terms of addresses)
Your func even only accepts 1 parameter, how do you expect this to work?

Code: Select all

Enter_User_Mode(user_stack + 0xFFC);
This is what he told you to do.

Push EBP is useless since you dont restore it anyways.
Anyways you should use a location which is greater then 0x1000 for the stack.
Pick some random one but dont be too low or too high

Also whats user_stack for in your example? Its some random uninitialized stack data.

TIP: Download IDA and reverse your own binary
I know... Assembly is not my language...
When I use values greater than 0x1000 my restarts are very rapid, when I use something like 0x900 for e.g, restarts are really space out like every 2-4 seconds. user_stack is something random that I have no use for since it was suggested to me. :|

Also, nothing has changed.

Code: Select all

Map_Physical_Virtual(& user_stack, 0x2000, 16384, Page_Writeable | Page_Present | Page_User);
Enter_User_Mode(user_stack + 0xFFC);
Bochs keeps reporting: (unk. ctxt): add byte ptr ds:[eax], al ; 0000
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Ch4ozz
Member
Member
Posts: 170
Joined: Mon Jul 18, 2016 2:46 pm
Libera.chat IRC: esi

Re: Usermode GPF

Post by Ch4ozz »

Code: Select all

add byte ptr ds:[eax], al ; 0000
That means the code you executed was just a bunch of zeros.
Use Qemu, log the values on triple fault, download IDA and start understanding the code your compiler generated.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Usermode GPF

Post by Octacone »

Ch4ozz wrote:

Code: Select all

add byte ptr ds:[eax], al ; 0000
That means the code you executed was just a bunch of zeros.
Use Qemu, log the values on triple fault, download IDA and start understanding the code your compiler generated.
Qemu log:

Code: Select all

CPU Reset (CPU 0)
EAX=00000032 EBX=00000000 ECX=00000000 EDX=00000001
ESI=0000000a EDI=00100000 EBP=00000000 ESP=00000fc8
EIP=000f04ad EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6ae0 00000037
IDT=     000f6b1e 00000000
CR0=60000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000000 CCD=00000001 CCO=LOGICL  
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
I can't download IDA on Linux, there are bunch of dependencies missing and errors and such. Even if I manage to install a debugger what am I going to do with it? I do not understand machine language as you do. Btw, your all zero theory seems correct they are all bunch of zeros. Also why is DPL=0?

Update: I managed to run IDA and there are like 1000 million lines of something. What am I supposed to do with all that? There are like memory addresses and weird assembly instructions.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Usermode GPF

Post by iansjack »

octacone wrote:Even if I manage to install a debugger what am I going to do with it? I do not understand machine language as you do.
That's nature's way of telling you to do a little more studying before trying to write advanced code.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Usermode GPF

Post by Octacone »

iansjack wrote:
octacone wrote:Even if I manage to install a debugger what am I going to do with it? I do not understand machine language as you do.
That's nature's way of telling you to do a little more studying before trying to write advanced code.
It is easier to ask people that know the answer, than search yourself without knowing what to search for. Manuals are useless to me, they are overcomplicated. It is a lot easier when people try to describe you their experiences. This was a bit off-topic, anyways I am speechless. :| Do you think that user mode is something that I shouldn't do and is too complicated? If yes, I have an entire list of things that need to be done. :) Never quit, except when you have to.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Ch4ozz
Member
Member
Posts: 170
Joined: Mon Jul 18, 2016 2:46 pm
Libera.chat IRC: esi

Re: Usermode GPF

Post by Ch4ozz »

Qemu log gave you EIP (000f04ad) you simply go to that address now in IDA and check the assembly.
Honestly, if you cant read asm you wont get that far because you need to know atleast the basics to write some routines like the scheduler and (in your case now) the context switch.
Oh and btw, my bunch of zeros was no theory, I know most of the standard opcodes by heart ;)
Last edited by Ch4ozz on Mon Nov 28, 2016 2:09 pm, edited 1 time in total.
User avatar
crunch
Member
Member
Posts: 81
Joined: Wed Aug 31, 2016 9:53 pm
Libera.chat IRC: crunch
Location: San Diego, CA

Re: Usermode GPF

Post by crunch »

You should make sure that you understand what the code I gave you is doing. You need to pass the location of the instructions you want executed first, and then the stack location.
Open up the qemu console and make sure that the code is in the right location, and not just a bunch of 0's. Make sure that your code and data pages are in your page table, and mapped as user accessible.

I suggest just a simple jmp $ loop, so that you can look at the register states and verify that you're executing in Ring3. You could, for example do the following.. in psuedo code

Code: Select all

/* Allocate pages for code and stack */
uint32_t* address-of-user-code = map_page(allocate_physical_page(), virtual_address = 0x1000, PTE_PRESENT | PTE_WRITE | PTE_USER);
uint32_t* address-of-user-stack = map_page(allocate_physical_page(), virtual_address = 0x0000, PTE_PRESENT | PTE_WRITE | PTE_USER);

/* EBFE is the opcode for jmp $
address-of-user-code should point to the memory location 0x00001000 
and that memory location should now contain the instruction for jmp 0x1000 */
*address-of-user-code = 0x000FEEB

/* Remember that stack grows down, so we need to start somewhere above 0x0000 and somewhere below 0x1000 */
enter_usermode(address-of-user-code, address-of-user-stack + 0xF00);
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: Usermode GPF

Post by Octocontrabass »

octacone wrote:It is easier to ask people that know the answer, than search yourself without knowing what to search for. Manuals are useless to me, they are overcomplicated. It is a lot easier when people try to describe you their experiences.
Manuals are useless to you because you haven't narrowed down your problem to something that the manual can tell you how to solve. Right now, you only know that switching to user mode is failing, but not the specific point where the CPU stops doing what you think it should be doing. Once you have a specific problem, like "IRET jumps to the wrong location", then you can read the relevant parts of the manual (the section describing IRET) and see if what you're doing is correct (by checking the stack, GDT, page tables, etc. with your debugger).

Even if you can't figure out the problem that way, it'll give you more information you can include in your posts to get better answers from us.
octacone wrote:Do you think that user mode is something that I shouldn't do and is too complicated?
That's up to you. Do you think you should be able to do this? You can always work on something easier and come back once you have more debugging experience.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Usermode GPF

Post by iansjack »

octacone wrote:anyways I am speechless.
Not, I can assure you, as speechless as I was to see someone giving the fact that they don't understand assembler as an excuse to avoid debugging.
User avatar
MichaelFarthing
Member
Member
Posts: 167
Joined: Thu Mar 10, 2016 7:35 am
Location: Lancaster, England, Disunited Kingdom

Re: Usermode GPF

Post by MichaelFarthing »

OK. Here's a challenge.

Take a break.
Stay in Ring 0.

Have you written an assembler 'Hello World' program yet? This is the most sensible suggestion as a starting point ever made! Simple and satisfying.

When you've done that have a go at this:

Write a routine that is given an address in memory and then places on screen a representation of the 256 memory bytes starting at that address in 16 rows of 16 columns of hexadecimal representation of each successive byte. Each row could start with the address of the first byte being decoded in that row, but you might choose to add that feature as an enhancement. This actually replicates a well-known early MSDos program called 'debug' and will prove a useful routine in the future, but you will be using straightforward ordinary instructions to give you a feel for assembler and a confidence in its use.

Output might look something like this (for the first row starting at, say, address 00004000:

00004000 B7 01 B8 02 03 04 05 B6 06 B9 07 08 09 0A B5 0B

Total code length for the exercise (at a guess) about 128-256 bytes and may be 40-60 instructions.

The line shown above is actually a genuine sequence of machine code for 5 very simple assembler instructions (32 bit mode). So as a preliminary exercise you could have a go at working out what the 5 instructions are using a table of Intel opcodes. They are easy instructions to understand and the pattern of the bytes does give a pretty strong clue as to where one instruction ends and the next begins. The five instructions are very similar to each other.

From this you may take it that my belief is that unless you can work out how an assembler has produced the sequence of machine code bytes from the instruction you entered then you don't really understand assembler! The assembler is just a tool to save you flapping about with the tedious job of working out the numbers - rather like a chef having someone to wash up for him. But the point is that the chef does actually know how to wash up if he needs to.

If you manage the exercise you can then write a little extra code to call your routine asking it to to start display at the very start of the routine itself. Your routine will then have displayed on screen the machine code representation of itself.

I'm guessing that this is a challenging but not impossible problem. Difficult to know because I've been writing in assembler languages, on and off, since 1982 so a lot of stuff now seems fairly obvious to me. If you're up for it, share your progress here or PM me. If it's too hard or too easy I'd be happy to offer alternative problems. The secret to success is to try and break the problem down into the most minute stages, testing each one, however simple, one at a time. For example, start by testing that you can write the letter 'A' on screen wherever you want. Next, see if you can write byte values of 0 up to 15 on the screen in the standard hexadecimal symbols 0-9 and A-F. The second secret is not to give up. The third secret is that when it goes wrong spend time thinking how it could go wrong, then, if stuck, go to bed, then think again. The fourth secret is not to ask for help until you have been stuck for at least 8 hours, but you can be excused that one at present.
Kevin
Member
Member
Posts: 1071
Joined: Sun Feb 01, 2009 6:11 am
Location: Germany
Contact:

Re: Usermode GPF

Post by Kevin »

octacone wrote:It is easier to ask people that know the answer, than search yourself
Easier for you or easier for the people who you demand to teach you and all the other beginners for free?

Don't think it's their duty to debug your code for you, they probably have enough code of their own. Most of us are happy to help even though we don't have to, but most of us also don't like it if it becomes apparent that our time is wasted just because wasting it is the easier option for the lazy.
Developer of tyndur - community OS of Lowlevel (German)
Post Reply