Page 1 of 2

L0 & WTF can someone help me?

Posted: Wed Jan 11, 2012 6:42 pm
by SoulofDeity
Hi, I'm Sod. 19 and have been programming for various consoles (TI83+, GBA, PSP, PC) for almost 10 years
(I know some may say WTF or yeah right but lets just say I'm a bit of an enthusiast and leave it at that)
My first language was z80 assembly with which and I have prior experience developing os's and shells for
the TI83+. Programming-wise, I'm fluent in z80 assembly, x86 assembly, C, C++, and Python. General-wise,
I'm also fluent in HTML, Javascript, GML (Game Maker Language, for those who don't know, it's much like
Javascript), DOS, and TI-Basic. My weakpoints (languages I know a little bit about by having made an
attempt to learn and either quit or have yet to master) include Java, Bash, Makefile scripts (really need to
learn this...), and C#. Hardware experience, I built my first pc from scrap when I was 8 and know the
names and purposes of everything, however I admit complete ignorance of circuitry. Personal life? None.
PC = Windows 7 and the sun since...god I can't remember when.
Hobbies: Watching / reading Naruto, Bleach, Death Note, and FullMetal Alchemist; 3d modelling (Blender
fanatic ^_^), game making (usually written in C using OpenGL or in Javascript with Unity), Youtube
surfing, watching House and the Big Bang Theory, and degrading the director of Two and a Half men for
killing Charlie Sheen.


Anyway, I started a project about 2 months ago and here my basic setup:

Code: Select all

	- 2 stage floppy bootloader
	- Stage 1 copies stage 2 (BOOTF2.BIN) to 0x7E00 and KERNEL.BIN to 0x100000 (0x1000:0x0000)
	- Stage 2 enables the a20 line and graphics mode and is 'supposed' to setup the GDT and paging
	  before jumping to the kernel
I chose this setup with the idea that (when installed to the hd) stage 2 would search a specific directory
for real mode modules that would be executed before switching to protected mode. But back to the issue,
I've read over every bit of documentation I could find and compared my source code with John S. Fine's
bootloader and the MenuetOS kernel and can't figure out why the following code refuses to work:

Code: Select all

	setupGDT:
	   cli
	   cld
	   lgdt [cs:gdt]
	   mov eax, cr0
	   or eax, 0x00000001
	   mov cr0, eax
           jmp $+2
	   mov ax, 10h
	   mov ds, ax
	   mov es, ax
	   mov fs, ax
	   mov gs, ax
	   mov ss, ax
						; I've also tried setting esp here,
						; but no cookie
	   jmp pword 8:0x100000	; have also tried 0x10000 and jumping
						; to a label directly after, all fail
	gdt:	dw gdt_end-$-1
		dd gdt
		dw 0
	.kcode:	dw 0xFFFF, 0x0000
		db 0x00, 0x9A, 0xCF, 0x00
	.kdata:	dw 0xFFFF, 0x0000
		db 0x00, 0x92, 0xCF, 0x00
	gdt_end equ $
I feel like an idiot getting stuck at something like this, but I don't know what else to do. I know that
it's not my kernel or stage 1 of the loader, they've both been tested without any problems.
I don't want to use GRUB because

Code: Select all

    1. I don't want menus and crap at startup. I want my os to selected the
       best configuration at boot and hide the confusing crap
    2. In case I develop something that's worth something, I don't want to get
       get caught in legal crap
    3. I don't plan on my os being open-source.
    4. I just don't want to use GRUB. It makes me think of bugs...and I don't
        like bugs...
Additionally, can someone explain to me the purpose and how to use the TSS descriptor? The only
info about it on the entire osdev wiki is:

Code: Select all

  "A TSS segment descriptor (trust me, keep a place for at least one)"
and

Code: Select all

  "GDT[3] = {.base=&myTss, .limit=sizeof(myTss), .type=0x89};  // You can use LTR(0x18)"
How in the hell am I supposed to know where to place it or how big it should be from these vague
details? And what is "LTR"?

Sorry if I'm coming off as rude, I'm just frustrated that I haven't gotten anywhere in 2 months.
I'm figuratively hemorrhaging! Thanks ahead of time :)

Re: L0 & WTF can someone help me?

Posted: Wed Jan 11, 2012 7:10 pm
by NickJohnson
SoulofDeity wrote:I don't want to use GRUB because

Code: Select all

    1. I don't want menus and crap at startup. I want my os to selected the
       best configuration at boot and hide the confusing crap
    2. In case I develop something that's worth something, I don't want to get
       get caught in legal crap
    3. I don't plan on my os being open-source.
    4. I just don't want to use GRUB. It makes me think of bugs...and I don't
        like bugs...
You know that you can set GRUB to boot without showing a menu by setting the timeout to 0, right? There are also no license issues booting a closed source kernel with GRUB, regardless of the fact that GRUB is GPL, because you don't link anything with it. Finally, GRUB is probably the most used bootloader for the PC, making it one of the least likely to have bugs.

Re: L0 & WTF can someone help me?

Posted: Wed Jan 11, 2012 7:54 pm
by raghuk
SoulofDeity wrote: But back to the issue, I've read over every bit of documentation I could find and compared my source code with John S. Fine's bootloader and the MenuetOS kernel and can't figure out why the following code refuses to work:
Hmm... you didn't tell us what happens. Your code does not compile? It triple faults?
SoulofDeity wrote: Additionally, can someone explain to me the purpose and how to use the TSS descriptor? The only
info about it on the entire osdev wiki is:
SoulofDeity wrote: How in the hell am I supposed to know where to place it or how big it should be from these vague
details? And what is "LTR"?
You should read Intel manuals for the IA-32 platform.

Re: L0 & WTF can someone help me?

Posted: Wed Jan 11, 2012 7:55 pm
by evoex
What's the alignment of the GDT? I believe it should be dword aligned. Also, why the "jmp $+2". Depending on how the mov after is encoded (it might store "10h" as "10 00", I believe nasm does that for some instructions, at least for 32 bits instructions), it might jump somewhere in the middle of the instruction, causing Bad Things.

Re: L0 & WTF can someone help me?

Posted: Thu Jan 12, 2012 4:13 pm
by DavidCooper

Code: Select all

	   lgdt [cs:gdt]

...

	gdt:	dw gdt_end-$-1
		dd gdt
		dw 0
	.kcode:	dw 0xFFFF, 0x0000
		db 0x00, 0x9A, 0xCF, 0x00
	.kdata:	dw 0xFFFF, 0x0000
		db 0x00, 0x92, 0xCF, 0x00
	gdt_end equ $
I'm not good at reading assembler, but this doesn't look right to me. It looks as if you don't have a null descriptor, and you've tried to build the structure that points to the GDT into the GDT itself. I don't like the look of the use of cs in cs:gdt at the top of that either, nor the use of gdt in it.

Code: Select all

           jmp $+2
I don't understand what that does, but what you actually want is a far jump to the following byte so that CS is loaded from the GDT [correction: so that hidden registers can be loaded from the GDT according to the value loaded into CS by the far jump].

Re: L0 & WTF can someone help me?

Posted: Fri Jan 13, 2012 9:53 am
by DLBuunk
SoulofDeity wrote:Additionally, can someone explain to me the purpose and how to use the TSS descriptor? The only
info about it on the entire osdev wiki is:
Have you tried searching TSS on the wiki?

As was already suggested, you should make sure your GDT is qword-aligned.

It seems that you have the order of doing things mixed up, first you load cs by doing a far jump, then you set the other segment registers. Something like:

Code: Select all

      mov eax, cr0
      or al, 0x01
      mov cr0, eax
      jmp 0x0008:pmode_entry
pmode_entry:
      [bits 32]
      mov ax, 10h
      mov ds, ax
      mov es, ax
      mov fs, ax
      mov gs, ax
      mov ss, ax
      ; setup the stack
There is nothing wrong with "lidt [cs:gdt]" per se, but is a hint that your realmode segments are not setup properly.

Re: L0 & WTF can someone help me?

Posted: Fri Jan 13, 2012 2:41 pm
by DavidCooper
berkus wrote:
DavidCooper wrote:I'm not good at reading assembler, but this doesn't look right to me. It looks as if you don't have a null descriptor, and you've tried to build the structure that points to the GDT into the GDT itself.
It's a well-known space-saving trick.
I've tried putting things in there to see if it caused a crash, and it didn't, but I didn't know it was guaranteed to work. Does anyone know what the null descriptor was originally for?

Re: L0 & WTF can someone help me?

Posted: Wed Feb 01, 2012 2:20 pm
by SoulofDeity
Thank for the replies and sorry for not responding sooner. I sorta have limited internet access (I use public wifi)

Anyway, the details of the crash are simply that code stops executing when I attempt to jump to the 32-bit part of my kernel afters setting the GDT. As for the jmp $+2, was added shortly after comparison with John S. Fine's bootloader where he made a comment about some sort of delay. I'd already tried everything else so I figured, why not.

I haven't tried qword-aligning the GDT but I have tried dword aligning the label I jump to when entering protected mode. The reason I use CS:GDT is because I figured its most dependent. If the command is executed, then CS obviously has to be pointing at the correct segment.


THANKYOUSOMUCHDLBUUNK!!! It didn't even occur to me until now that the p-mode segment registers are different from real mode segment registers. You'd think after reading that they store pointers to GDT descriptors in p-mode instead of segment addresses and reading the Unreal Mode tutorial about 20 times that it would have hit me :lol: I'll try it the second I get home and increase your karma for decreasing my headache if it's a success :D

I admit it...I'm a make-my-own-everything kinda guy. I feel naughty when I use other peoples software. Naughty...


EDIT:
And yet I feel even MORE stupid...how did I not realize that you can't jump to a label after changing the value of DS? HAVE I BEEN BRAINDEAD THE PAST FEW WEEKS?

Re: L0 & WTF can someone help me?

Posted: Thu Feb 02, 2012 12:18 pm
by AJ
SoulofDeity wrote:Thank for the replies and sorry for not responding sooner. I sorta have limited internet access (I use public wifi)
Congratulations for managing to crack their new WEP key :twisted:

Re: L0 & WTF can someone help me?

Posted: Sat Feb 04, 2012 5:23 pm
by sounds
berkus wrote:
DavidCooper wrote:I'm not good at reading assembler, but this doesn't look right to me. It looks as if you don't have a null descriptor, and you've tried to build the structure that points to the GDT into the GDT itself.
It's a well-known space-saving trick.
I admit, it's a 64-bit GDT but here's how my OS does it in 19 bytes, versus 22 bytes for the baby GDT you linked to:

Code: Select all

	mov  di, GDT_ADDRESS + GDTR_OFFSET
	mov  word [di + 0x08 + 5 - GDTR_OFFSET], 0x2098
	mov  byte [di + 0x10 + 5 - GDTR_OFFSET], 0x92

	; assumption: GDT_ADDRESS is only a 16 bit number
	mov  dword [di], (GDT_ADDRESS << 16) | 0x1d	; GDT address and limit
I bet it can be done even smaller... I wonder how?

By the way, the boot sector does zero out the region to set up the PML4, etc. The other bytes are really zero, that's not assumed but actually zero. But I guess in fairness the rep stosd loop should be counted in the total number of bytes.

The OS itself is based on the concept of a hand magnifier.

Re: L0 & WTF can someone help me?

Posted: Sun Feb 05, 2012 10:53 pm
by sounds
berkus wrote:Well, yes, it can be done in less number of bytes perhaps if I build it inside bss section. There's quite a bit of repetitive bytes.
Could you demonstrate how?

I thought SoulofDeity was doing it in his stage2 (BOOTF2.BIN). I'm creating my GDT right in the bootloader. So how does a bss section get in there? (I'm assuming you're referring to ELF sections.)

Re: L0 & WTF can someone help me?

Posted: Sat Jul 14, 2012 2:23 pm
by SoulofDeity
*bump* I got busy and stopped osdev'ing for a while, but have still yet to figure this out.


Now, I completely understand the GDT, its purpose, its format, and how to load it, but for some reason it still fails to work. Explaining my new process:

- bootloader copies KERNEL.BIN to physical address 0x00010000, log. 0x1000:0x0000 and far jumps to data

- kernel enables the A20 line

- kernel sets up a qword aligned flat gdt with 3 entries; (null slot), SYS_CODE_SEG[TYPE=0x9A, GRAN=KB, BASE=0x00000000, LIMIT=0x000FFFFF], SYS_DATA_SEG[TYPE=0x92, GRAN=KB, BASE=0x00000000, LIMIT=0x000FFFFF]

- kernel sets protected mode bit of CR0

- kernel sets all data segment registers to SYS_DATA_SEG (0x10)

- kernel far jumps to 'kernel32' (jmp SYS_CODE_SEG:kernel32)

The 32-bit part of the kernel comes after all 16-bit data, is qword aligned, and is simply 2 instructions:

Code: Select all

mov byte [0x000B8000], 'A'
jmp $
when tested, the character 'A' is never printed to the screen. (wish I could provide more details than that, but I'm using VirtualBox) I think that I may actually be doing this completely correct because alternate bootloaders written by other people have the same problem when I compile them. I figured it was probably how fasm handles the jmp instruction, but converting the instruction to raw data didn't work either.
Are there any known issues like this when using FASM for osdev? I don't know what else it could be.

Re: L0 & WTF can someone help me?

Posted: Sat Jul 14, 2012 3:27 pm
by Firestryke31
Does "kernel sets up a qword aligned flat gdt" include actually loading the GDTR with LGDT?

Re: L0 & WTF can someone help me?

Posted: Sat Jul 14, 2012 8:58 pm
by SoulofDeity
Firestryke31 wrote:Does "kernel sets up a qword aligned flat gdt" include actually loading the GDTR with LGDT?
yes. here's the source code itself:

Code: Select all

macro jmp32 seg, base {
   db 0x66, 0xEA
   dd base
   dw seg
}

org 0x0000
use16

   jmp kernel16

align 8
gdt:	dw gdt_end-gdt-1
	dd gdt
	dw 0x0000
SYS_CODE_SEG	equ $-gdt
	dd 0x0000FFFF, 0x00CF9A00
SYS_DATA_SEG	equ $-gdt
	dd 0x0000FFFF, 0x00CF9200
gdt_end:


kernel16:
   cli
   lgdt [cs:gdt]
   mov eax, cr0
   inc ax
   mov cr0, eax

; ---- this part was copied from John Fine's boot loader
; just so I could focus on debugging the GDT, I plan on
; changing this to FAST A20 in the future
.5:	in	al, 0x64		;Enable A20 {4A}
	test	al, 2
	jnz	.5
	mov	al, 0xD1
	out	0x64, al
.6:	in	al, 0x64
	and	ax, 2
	jnz	.6
	mov	al, 0xDF
	out	0x60, al
;----------------------------------------------------------

   mov ax, SYS_DATA_SEG
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax
   jmp32 SYS_CODE_SEG, kernel32 + 0x10000


align 8
use32

kernel32:
   mov byte [0xB8000], 'A'
   jmp $

Re: L0 & WTF can someone help me?

Posted: Sat Jul 14, 2012 11:16 pm
by egos
What asm compiler do you use? If it's fasm then "equ" defines a symbolic constants, not numeric. You can use "=" or "label" instead.

Code: Select all

GDT:
        dq 0

        set KCODE,$-GDT ; label KCODE at $-GDT
        desc 0,0FFFFFh,DF_CODE32

        set KDATA,$-GDT
        desc 0,0FFFFFh,DF_DATA32

        set GDT_SIZE,$-GDT
You didn't consider DLBuunk's and DavidCooper's remarks.

Because location of your kernel exceeds 0xFFFF and you use FLAT segments you should reset address counter using org directive.

Code: Select all

  jmp fword KCODE:@f ; "fword" allows to generate 32-bit instruction

  org $+10000h
  use32

@@:
  mov eax,KDATA
  mov ds,ax
  mov es,ax
  mov fs,ax
  mov gs,ax
  mov ss,ax
  mov esp,10000h

  mov word [0B8000h],"A" + 700h
  jmp $