OSDev.org https://forum.osdev.org/ |
|
[x64] can not switch from ring3 to ring0 by call gate https://forum.osdev.org/viewtopic.php?f=13&t=33006 |
Page 1 of 1 |
Author: | CandyMan [ Thu Jun 14, 2018 1:41 pm ] |
Post subject: | [x64] can not switch from ring3 to ring0 by call gate |
can not switch from ring3 to ring0 by call gate, code below generating invlid TSS exception, but via syscall switch works fine. where is bug? Code: use64
call [PL3toPL0] NextPL3PL0: ... PL3toPL0 dp Gate386-GDT+3:0 GDT: dq 0 ; 32-bit code descriptor 0x08 Code32 dw 0xFFFF ; limit low dw 0 ; base low db 0 ; base middle db 10011010b ; access db 11001111b ; flags and limit high db 0 ; base high ; 32-bit data descriptor 0x10 Data32: dw 0xFFFF dw 0 db 0 db 10010010b db 11001111b db 0 ; 16-bit code descriptor 0x18 Code16 dw 0xFFFF dw 0 db 0 db 10011010b db 10001111b db 0 ; 16-bit data descriptor 0x20 Data16 dw 0xFFFF dw 0 db 0 db 10010010b db 10001111b db 0 ; 64-bit kernel code descriptor 0x28 Code64 dw 0xFFFF dw 0 db 0 db 10011010b db 10101111b db 0 ; 64-bit kernel data descriptor 0x30 Data64 dw 0xFFFF dw 0 db 0 db 10010010b db 11001111b db 0 ; Usermode code descriptor 0x38 Code643 dw 0xFFFF dw 0 db 0 db 11111010b db 10101111b db 0 ; Usermode data descriptor 0x40 Data643 dw $FFFF dw 0 db 0 db 11110010b db 11001111b db 0 ; Usermode code descriptor 0x48 Code64X dw 0xFFFF dw 0 db 0 db 11111010b db 10101111b db 0 ; TSS descriptor 0x50-0x58 Tss64 dw 68h+IOLIMIT dw (TSS64 and 0xFFFF) db (TSS64 shr 16)and 0xFF db 11101001b db 00100000b db (TSS64 shr 24)and 0xFF dd (TSS64 shr 32) dd 0 ; 32-bit user descriptor 0x60 Code323 dw 0xFFFF dw 0 db 0 db 11111010b db 11001111b db 0 Gate386 dw (NextPL3PL0 and 0xFFFF) dw Code64-GDT db 0 db 11101100b dw (NextPL3PL0 shr 16)and 0xFFFF dd (NextPL3PL0 shr 32) dd 0 |
Author: | simeonz [ Thu Jun 14, 2018 6:24 pm ] |
Post subject: | Re: [x64] can not switch from ring3 to ring0 by call gate |
db 00100000b, should be db 00010000b or db 00000000b. You are setting the long mode flag for the TSS, but it needs to be always cleared (even for 64-bit TSS) |
Author: | Schol-R-LEA [ Thu Jun 14, 2018 7:18 pm ] |
Post subject: | Re: [x64] can not switch from ring3 to ring0 by call gate |
TBH, I am not quite certain why you are having this specific issue, but I'll dig deeper shortly. Having said that: I know that this has been said to you before, but I think it needs to be reiterated that the Duct von Tape approach to writing programs is not a viable strategy in OS dev. This problem, or rather the several problems I see in your GDT, is a good example of why this is the case. I am not sure how much of this code you wrote yourself, if any, but I can say for certain that you haven't understood all of it. The reason I say this is because
The implications of these facts are left as an exercise for the reader. |
Author: | Schol-R-LEA [ Thu Jun 14, 2018 7:21 pm ] |
Post subject: | Re: [x64] can not switch from ring3 to ring0 by call gate |
simeonz wrote: db 00100000b, should be db 00010000b or db 00000000b. You are setting the long mode flag for the TSS, but it needs to be always cleared (even for 64-bit TSS) OK, that would probably do it. There may be other issues as well, but that alone would be a showstopper. I will add something that occurred to me earlier: the OP would do well to look at the macro and structure-definition features of their assembler (I am guessing it is NASM, but I am not sure) as a way of simplifying these declarations, both for avoiding repetition (by using the default initializations, if it allows them) and for making the setting process more meaningful by giving names to the fields and so forth. You could, for example, have a struct definition like this NASM version: Code: struc GDT_Entry .limit_0_15 resw 1 .base_0_15 resw 1 .base_16_23 resb 1 .access resb 1 .flags_limit_16_19 resb 1 .base_24_31 resb 1 endstruc Which would at least let you then do this: Code: Pr_Shift equ 7 DPL_Shift equ 5 ST_Shift equ 4 Ex_Shift equ 3 DC_Shift equ 2 RW_Shift equ 1 Ac_Shift equ 0 G_Shift equ 7 DB_Shift equ 6 L_Shift equ 5 istruc GDT_Entry at .limit_0_15, dw 0xFFFF at .base_0_15, dw 0x0000 at .base_16_23, db 0x00 at .access, db (1 << Pr_Shift) & (0 << DPL_Shift) & (1 << ST_Shift) & (1 << Ex-Shift) & (0 << DC_Shift) & (1 << RW_Shift) & (0 << Ac_Shift) at .flags_limit_16_19, db 0x0F & (1 << G_Shift) & (1 << DB_Shift) & (0 << L_Shift) at .base_24_31, db 0x00 iend And then have a macro that takes the actual values you want by name, rather than the byte and bit values, and automagically combine them into the fields for you: Code: %macro Make_GDT_Entry 0-10 0, 1, 1, 0, 1, 0, 1, 1, 0, 0x00000000, 0x00FFFFFF istruc GDT_Entry at .limit_0_15, dw (%9 & 0x000FFFF) at .base_0_15, dw (%10 & 0x0000FFFF) at .base_16_23, db ((%9 & 0x00FF0000) >> 16) at .access, db 0x80 & (%0 << DPL_Shift) & (%1 << ST_Shift) & ((%2 & %0) << Ex-Shift) & ((%3 & %0) << DC_Shift) & ((%4 & %0) << RW_Shift) & ((%5 & %0) << Ac_Shift) at .flags_limit_16_19, db ((%10 & 0x00FF0000) >> 16) & (%6 << G_Shift) & (%7 << DB_Shift) & (%8 << L_Shift) at .base_24_31, db ((%9 & 0xFF000000) >> 24) iend %endmacro Which, if used with just the defaults, Code: GDT: NULL_Descriptor: dq 0 ; 32-bit code segment descriptor Code32: Make_GDT_Entry would give you the descriptor you were using. For a System segment, you could use, Code: ; 32-bit kernel segment descriptor Kernel32: Make_GEDT_Entry 0 which would be the same, except it would leave S, X, DC, RW, and Ac cleared. (Note that this isn't tested code, so I may have some mistakes in it.) You could, of course, make more specialized macros at your discretion. You would naturally need to adjust these to fit you assembler. |
Author: | simeonz [ Fri Jun 15, 2018 3:20 am ] |
Post subject: | Re: [x64] can not switch from ring3 to ring0 by call gate |
Schol-R-LEA wrote: I will add something that occurred to me earlier: the OP would do well to look at the macro and structure-definition features of their assembler (I am guessing it is NASM, but I am not sure) as a way of simplifying these declarations, both for avoiding repetition (by using the default initializations, if it allows them) and for making the setting process more meaningful by giving names to the fields and so forth. True. I was thinking the same thing while counting the bit positions. The error may not have occurred, assuming this is the error, if the data was more "literate". Since I am not myself an avid assembler enthusiast, I am curious. Macros are somewhat less expressive then structures/records, so may we assume that the advice is to use NASM (for portability sake)? Or is using gas with a stronger preprocessor (like m4) a better option? Or NASM with m4? Or C/C++ with mostly inline assembler?
|
Author: | Schol-R-LEA [ Fri Jun 15, 2018 10:16 am ] |
Post subject: | Re: [x64] can not switch from ring3 to ring0 by call gate |
BTW, I noticed a mistake in the earlier post, which I've now corrected; I had the last part of base field declared as word, when it should be byte. simeonz wrote: Schol-R-LEA wrote: I will add something that occurred to me earlier: the OP would do well to look at the macro and structure-definition features of their assembler (I am guessing it is NASM, but I am not sure) as a way of simplifying these declarations, both for avoiding repetition (by using the default initializations, if it allows them) and for making the setting process more meaningful by giving names to the fields and so forth. True. I was thinking the same thing while counting the bit positions. The error may not have occurred, assuming this is the error, if the data was more "literate". Since I am not myself an avid assembler enthusiast, I am curious. Macros are somewhat less expressive then structures/records, so may we assume that the advice is to use NASM (for portability sake)? Or is using gas with a stronger preprocessor (like m4) a better option? Or NASM with m4? Or C/C++ with mostly inline assembler?I wasn't really trying to make a recommendation, and honestly, I agree that NASM macros are less expressive than NASM structs, or for that matter, macros for other assemblers. I was using NASM because it seems to be the one most often used for x86 OS dev, and I am more familiar with it than, say, FASM. A stronger macro preprocessor would definitely be a good idea; I've used m4 to good effect in the past myself (though it was an odd situationĀ¹ and I misused it somewhat), and have even tried using the stand-alone version of cpp (it works, but it isn't terribly well suited for assembly work). I would be hesitant to suggest using C, simply because I don't know what CandyMan's goals and intentions are - if they are planning to use assembly across the board, the recommendation probably wouldn't go over terribly well. In any case, I wouldn't recommend using inline assembly extensively or exclusively for large amounts of assembly work. However, for the GDT and related system data structures, there's no reason C can't be used directly for a large part of it so long as you remember to set the alignments and packing using the GCC attribute pragma or the equivalent thereof for the given compiler. For GCC, this would be Code: typedef struct { uint16_t limit_0_15, base_0_15; uint8_t base_16_23; uint8_t access; uint8_t flags_limit_16_19; uint8_t base_24_31; endstruc } __attribute__ ((aligned(8), packed )) GDT_Entry; I am pretty sure that the alignment should be 8 for both 32-bit and 64-bit modes, but if anyone can confirm or refute this I would appreciate it. Also, I separated the declarations of the access and flags_limit_16_19 bytes, rather than lumping all the uint8_t declarations together, in case someone wants to try messing about with bit fields (which can be dicey in general, WRT differences in compilers, but if you are sticking to a specific compiler with a known bit ordering and implementation of the bit accesses, it would make working with the individual fields much easier). While the wiki's GDT Tutorial doesn't have an example of this (even though it uses C for most of the example code), there are several threads in the forum where that approach is discussed. Footnote 1. It was for an assembly language course that used MIPS as the target, and SPIM as the emulator. SPIM's built in assembler is severely limited, lacking even the most rudimentary extra features such as structures, macros, or even support for multiple source files, so when I had a large-ish final project - a Sudoku solver - I convinced my lab partner to use m4 to make the work easier. It was still a hassle - we had to manually preprocess the macro-fied source file separately into a final source file, which made it a bit annoying to test the code - but it worked well, or would have if I hadn't started overdoing things with the macrology to the point where it started getting more confusing rather than less. |
Author: | Schol-R-LEA [ Mon Jun 18, 2018 8:05 am ] |
Post subject: | Re: [x64] can not switch from ring3 to ring0 by call gate |
Sorry for the sequential posts, but I just want to clarify a point: if my reading of the segment descriptors earlier was correct, and the code isn't changing them or a adding any new ones, then it shouldn't be possible for you to be running anything in ring 3 to begin with - I am pretty sure that a DPL of 00 across the board means those segments are all set to ring 0 only access. Can anyone confirm or refute this? Have I missed any details on that? As I've mentioned before, this is an area I have not really delved into. @CandyMan: Could you provide a link to your offsite repo so we can see the whole code if we need to? If you don't have any offsite repo... well, in that case, you don't want do anything else on your OS until you've set one up. Trust me on this; they are too darn useful not to have for even a small project. |
Author: | simeonz [ Mon Jun 18, 2018 10:14 am ] |
Post subject: | Re: [x64] can not switch from ring3 to ring0 by call gate |
Schol-R-LEA wrote: I am pretty sure that a DPL of 00 across the board means those segments are all set to ring 0 only access. I actually see a lot of DPL 3 segment descriptors. Also, your breakdown of the bits was correct, but if you go to Code643, the flags are 11111010b, which means present, DPL = 11b, etc. I am not sure what the 64-bit data segment descriptors are for, but may be unused.
|
Author: | Schol-R-LEA [ Mon Jun 18, 2018 10:29 am ] |
Post subject: | Re: [x64] can not switch from ring3 to ring0 by call gate |
simeonz wrote: Schol-R-LEA wrote: I am pretty sure that a DPL of 00 across the board means those segments are all set to ring 0 only access. I actually see a lot of DPL 3 segment descriptors. Also, your breakdown of the bits was correct, but if you go to Code643, the flags are 11111010b, which means present, DPL = 11b, etc. I am not sure what the 64-bit data segment descriptors are for, but may be unused.facepalm I could have sworn I had checked all of them and that they were all identical. .. that was careless of me. |
Author: | simeonz [ Mon Jun 18, 2018 10:47 am ] |
Post subject: | Re: [x64] can not switch from ring3 to ring0 by call gate |
Schol-R-LEA wrote: facepalm I could have sworn I had checked all of them and that they were all identical. .. that was careless of me. There are a lot of numbers, and little text. I am not attacking the OP or anything, but indeed, it is hard not to miss a thing or two, as they themselves have discovered, I think.
|
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |