flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Help to start my own OS

Goto page Previous  1, 2, 3, 4, 5, 6, 7  Next
Author
Thread Post new topic Reply to topic
Teehee



Joined: 05 Aug 2009
Posts: 570
Location: Brazil
Teehee 23 May 2010, 16:21
ok, I think i understand the theory around VBE (bank, window, etc). But my problem is how to put that all in the code. Remembering i'm in PM.

_________________
Sorry if bad english.
Post 23 May 2010, 16:21
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20513
Location: In your JS exploiting you and your system
revolution 23 May 2010, 16:39
Teehee wrote:
ok, I think i understand the theory around VBE (bank, window, etc). But my problem is how to put that all in the code. Remembering i'm in PM.
See here. All video cards/chips are different. There are some pseudo-standards among all cards but it is not guaranteed. There is no shortcut here, you have to know what your card does internally.
Post 23 May 2010, 16:39
View user's profile Send private message Visit poster's website Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1905
DOS386 24 May 2010, 04:27
revolution wrote:
All video cards/chips are different.


Right ... nevertheless ...

Quote:
There are some pseudo-standards among all cards but it is not guaranteed.


All cards have VESA (as undocumented feature ...)

Quote:
There is no shortcut here, you have to know what your card does internally.


NO. Use VESA. Even Windaube can (ME (needs unofficial driver) or XP (built-in) ...).

Quote:
the theory around VBE (bank, window, etc). But my problem is how to put that all in the code. Remembering i'm in PM.


Forget bank's and use the LFB Wink

_________________
Bug Nr.: 12345

Title: Hello World program compiles to 100 KB !!!

Status: Closed: NOT a Bug
Post 24 May 2010, 04:27
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4354
Location: Now
edfed 24 May 2010, 22:08
coding this kind of code is not so easy... even try to modify or simplify a still existing source is not a simple thing.

then, i think you should write step by step.

1/ boot
2/ load sectors
3/ jump or call to it
4/ switch to protected mode
5/ add pm irq
6/ add real mode return
7/ add real mode interrupts from protected mode
and finally:
8/ set vesa mode and play with frame buffer in protected mode.

each of theses steps should be fully understood and implemented before to take next step.
Post 24 May 2010, 22:08
View user's profile Send private message Visit poster's website Reply with quote
Teehee



Joined: 05 Aug 2009
Posts: 570
Location: Brazil
Teehee 25 May 2010, 12:35
Hey edfed, i will do that! THanks.
Post 25 May 2010, 12:35
View user's profile Send private message Reply with quote
Teehee



Joined: 05 Aug 2009
Posts: 570
Location: Brazil
Teehee 25 May 2010, 20:38
what is better, and why: make a boot file only to load the kernel and into kernel set up A20, PM, etc. or to put that all into boot file?
Post 25 May 2010, 20:38
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20513
Location: In your JS exploiting you and your system
revolution 25 May 2010, 21:02
Teehee wrote:
what is better, and why: make a boot file only to load the kernel and into kernel set up A20, PM, etc. or to put that all into boot file?
"better" in what way?

It depends upon what you are doing and how you are doing it.

"better" means ...
1) smaller code size?
2) smaller source size?
3) easier for you to comprehend?
4) easier for you to type?
5) more flexible for porting?
6) something else?
Post 25 May 2010, 21:02
View user's profile Send private message Visit poster's website Reply with quote
Teehee



Joined: 05 Aug 2009
Posts: 570
Location: Brazil
Teehee 25 May 2010, 21:19
5. Smile bc i was wondering to reuse "set PM routine" later, if needed.

(Will the boot sector keep in memory after the boot?)
Post 25 May 2010, 21:19
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 25 May 2010, 23:06
Teehee wrote:
Will the boot sector keep in memory after the boot?
You decide it. While portions of boot sector can be useful later, consider the following: in order to fit code in tight space, you obviously trade flexibility for compactness, hence code becomes straightforward.

Probably you can even use some ready-made boot code that loads file from standard FAT12/16 volume to focus on real things in your kernel.
Post 25 May 2010, 23:06
View user's profile Send private message Reply with quote
Teehee



Joined: 05 Aug 2009
Posts: 570
Location: Brazil
Teehee 29 May 2010, 15:29
aww.. i read and read and read about GDT but i still can't to build it in the code Crying or Very sad Crying or Very sad Crying or Very sad Crying or Very sad Crying or Very sad

i understood why we need CLI, LGDT [gdtr], set PE flag:
Code:
    cli
    lgdt [gdtr]
    mov eax,cr0
    or  al, 1            ; enable PE flag (bit 0) in CR0
    mov cr0, eax    

but from here things are letting me crazy Mad
Code:
    jmp 8:@f
@@:
use32
    jmp 8000h            ; go to kernel

      align 8
gdtr: dw 23,gdtr-3
      db 0
      dw 0FFFFh,0,9A00h,0CFh
      dw 0FFFFh,0,9200h,0CFh    

1. The JMP 8:@f its here bc we need to go to next segment descriptor in GDT bc the first one is not used (null descriptor), right?
2. what does the align 8 do? ok, it align 8 bits, but what that mean!?
3. The worse step:
Code:
gdtr: dw 23,gdtr-3
      db 0
      dw 0FFFFh,0,9A00h,0CFh
      dw 0FFFFh,0,9200h,0CFh    

GEeeeeezzzzzz what they meannnnnnn Crying or Very sad

I dont know build the GDT Crying or Very sad

I need a step-by-step, explaining everything slowly (i'm dumb Image)

(i already did read this, and this and the intel manual Crying or Very sad)

Thanks and sorry
Image

_________________
Sorry if bad english.
Post 29 May 2010, 15:29
View user's profile Send private message Reply with quote
ManOfSteel



Joined: 02 Feb 2005
Posts: 1154
ManOfSteel 29 May 2010, 16:02
Teehee wrote:
2. what does the align 8 do? ok, it align 8 bits, but what that mean!?

It's 8 bytes not bits. It aligns to 8 bytes so that the following structures (the GDTR and the GDT) are aligned to a memory address divisible by 8. It just optimizes the way the CPU handles data. Read this for more information about memory access granularity.

Teehee wrote:

3. The worse step:
Code:
gdtr: dw 23,gdtr-3
      db 0
      dw 0FFFFh,0,9A00h,0CFh
      dw 0FFFFh,0,9200h,0CFh    

GEeeeeezzzzzz what they meannnnnnn Crying or Very sad

The first word is the GDT limit, i.e. its size in bytes. Next comes the GDT base, i.e. where it starts in the memory. But this one should be a dword, not a word.
For the rest, basically you have 8 bytes for every entry (segment selector). It always starts with the null selector (8 bytes not 1 as in your case). Then, in your case you have 2 PM selectors, one for system code and the other for the system data.
You probably should check the third Intel manual (system programming) because it takes a few chapters to explain it in more details. Actually the document you used explains it quite well.
Post 29 May 2010, 16:02
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 29 May 2010, 16:44
Teehee,

The trick with pseudo-descriptor is to put it into unused GDT[0] entry (and gdtr-3 is due to difference between their sizes: 16-bit pseudo-descriptor is 5 bytes long, GDT entry — 8).

----8<----
ManOfSteel,

With such arrangement, align 8 makes GDT entries unaligned (they're at 8*n+5).
Post 29 May 2010, 16:44
View user's profile Send private message Reply with quote
ManOfSteel



Joined: 02 Feb 2005
Posts: 1154
ManOfSteel 29 May 2010, 19:18
baldr wrote:
The trick with pseudo-descriptor is to put it into unused GDT[0] entry (and gdtr-3 is due to difference between their sizes: 16-bit pseudo-descriptor is 5 bytes long, GDT entry — 8).

Saving 11 bytes is a matter of life and death, eh? This is a completely twisted and rather useless "trick". And it's definitely not the best way for a beginner to understand the already twisted Intel arch structures.

baldr wrote:
With such arrangement, align 8 makes GDT entries unaligned (they're at 8*n+5).

Of course. In this case it's missing a dw... when the rest is fixed and no "tricks" are used, that is.
Post 29 May 2010, 19:18
View user's profile Send private message Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 618
cod3b453 29 May 2010, 21:09
Teehee: I find it easier to use symbolic constants and let FASM do the work for me in constructing entries:

Header
Code:
        ; GDT Selector Rings
        GDT_RPL_RING0                                   equ 0x0000
        GDT_RPL_RING1                                   equ 0x0001
        GDT_RPL_RING2                                   equ 0x0002
        GDT_RPL_RING3                                   equ 0x0003
        GDT_RPL_MASK                                    equ 0x0003

        ; GDTENTRY.Access
        GDT_PRESENT                                     equ 0x80

        GDT_RING0                                       equ 0x00
        GDT_RING1                                       equ 0x20
        GDT_RING2                                       equ 0x40
        GDT_RING3                                       equ 0x60

        GDT_CODE                                        equ 0x10
        GDT_CODE_EXECUTE                                equ 0x08
        GDT_CODE_READ                                   equ 0x02

        GDT_DATA                                        equ 0x10
        GDT_DATA_WRITE                                  equ 0x02
        GDT_DATA_READ                                   equ 0x00

        GDT_STACK                                       equ 0x10
        GDT_STACK_WRITE                                 equ 0x02
        GDT_STACK_READ                                  equ 0x00
        GDT_STACK_EXPANDDOWN                            equ 0x04
        GDT_STACK_EXPANDUP                              equ 0x00

        GDT_SYSTEM                                      equ 0x00

        ; GDTENTRY.Flags
        GDT_GRANULARITY_BYTES                           equ 0x00
        GDT_GRANULARITY_PAGES                           equ 0x80

        GDT_16BIT                                       equ 0x00
        GDT_32BIT                                       equ 0x40
        GDT_64BIT                                       equ 0x20
        GDT_USER                                        equ 0x10


        GDT_ACCESS_MASK                                 equ (GDT_PRESENT or GDT_RING3 or GDT_DATA or GDT_CODE_EXECUTE or GDT_STACK_EXPANDDOWN or GDT_DATA_WRITE)
        GDT_FLAGS_MASK                                  equ (GDT_GRANULARITY_PAGES or GDT_32BIT or GDT_64BIT or GDT_USER)
        GDT_LIMITHI_MASK                                equ 0x0F


        struc GDTENTRY b,l,f,a
         {
                .LimitLo        dw (l and 0xFFFF)
                .BaseLo         dw (b and 0xFFFF)
                .BaseMi         db ((b shr 16) and 0xFF)
                .Access         db (a and GDT_ACCESS_MASK)
                .Flags_LimitHi  db ((f and GDT_FLAGS_MASK) or ((l shr 16) and GDT_LIMITHI_MASK))
                .BaseHi         db (b shr 24)
         }

        struc GDTR32ENTRY b,e
         {
                .Size           dw (e - b - 1)
                .Address        dd (b)
         }
              


Table Data
Code:
  gdtr32  GDTR32ENTRY gdt32.start,gdt32.end 

      align 8 ; important lower 3 bits are used for RPL

       gdt32: 
 .start: ;        base       limit      flag access 
     .null   GDTENTRY 0x00000000,0x00000000,0x00,0x00 
   .data   GDTENTRY 0x00000000,0x000FFFFF,(GDT_GRANULARITY_PAGES or GDT_32BIT),(GDT_PRESENT or GDT_RING0 or GDT_DATA or GDT_DATA_READ or GDT_DATA_WRITE) 
      .code   GDTENTRY 0x00000000,0x000FFFFF,(GDT_GRANULARITY_PAGES or GDT_32BIT),(GDT_PRESENT or GDT_RING0 or GDT_CODE or GDT_CODE_READ or GDT_CODE_EXECUTE) 
    .code64 GDTENTRY 0x00000000,0x000FFFFF,(GDT_GRANULARITY_PAGES or GDT_64BIT),(GDT_PRESENT or GDT_RING0 or GDT_CODE or GDT_CODE_READ or GDT_CODE_EXECUTE) 
    .stack  GDTENTRY 0x00000000,0x000FFFFF,(GDT_GRANULARITY_PAGES or GDT_32BIT),(GDT_PRESENT or GDT_RING0 or GDT_STACK or GDT_STACK_READ or GDT_STACK_WRITE or GDT_STACK_EXPANDUP) 
     .end:    


When you jump to protected mode:
Code:
        cli

     lgdt [gdtr32]

   mov eax,cr0
 or eax,1;CPU_CR0_PE
 mov cr0,eax 

    jmp pword ((gdt32.code - gdt32.start) or GDT_RPL_RING0):pmode
;                   ^this is the GDT offset^    ^set priv lvl^  ^code location
align 4
use32
pmode:     

you are setting the code selector with properties in the GDT entry, setting the actual (requested) priviledge level (RPL) and the code location to start executing. In this case code is 32 bit, may read or execute in the range 0x00000000-0xFFFFFFFF and operate in privilege level 0.

With any luck it nearly makes sense Razz
Post 29 May 2010, 21:09
View user's profile Send private message Reply with quote
Teehee



Joined: 05 Aug 2009
Posts: 570
Location: Brazil
Teehee 29 May 2010, 21:17
ohhh pretty good Very Happy

but the .code64 is optional, right?

***

about the boot:
it loads at 0:7C00h by default. So it starts with org 7c00h.
Which place should I put my kernel? org 0 (0000:0000)?
Post 29 May 2010, 21:17
View user's profile Send private message Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 618
cod3b453 29 May 2010, 21:36
Yes, sorry I literally tore this out of my own OS, you only need the null, data and code entries to have ring 0 protected mode (the stack and code64 are for multiprocessor booting and 64 bit in my own OS but I'll leave them there to show it doesn't matter and can be done). If you want to run 32 bit user programs, add another data and code entry with GDT_RING3 instead and then use jmp/iret to switch into user mode (interrupts/syscalls will later let you back to ring 0).

The 16 bit IVT is at 0x0000, so you can't do this unless you never use 16 bit interrupts during the kernel load or ever again. If you're loading the kernel in 16 bit mode, there are several safe regions: 0x1000-0x7BFF, 0x7E00-~0x90000, or in protected mode, use anything over 0x00100000 (1MB) and under 0x80000000 or the amount of available RAM, whichever is less.

edit: got my tables mixed up Razz


Last edited by cod3b453 on 30 May 2010, 09:52; edited 1 time in total
Post 29 May 2010, 21:36
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 30 May 2010, 08:57
ManOfSteel wrote:
Saving 11 bytes is a matter of life and death, eh? This is a completely twisted and rather useless "trick". And it's definitely not the best way for a beginner to understand the already twisted Intel arch structures.
Then I have to apologize to Teehee because I've proposed 16-bit ldtr in edfed's "minimal pm boot sector". Wink
ManOfSteel wrote:
Of course. In this case it's missing a dw...
Think again, pseudo-descriptor is 16-bit (5 bytes long). I'm not of rigorist type, but in this case you have to be exact: ±1 is not an option when you're explaining things to unaware reader. He's already taken not the easiest example of code to learn from (I'm talking about pseudo-descriptor/GDT overlap).

----8<----
cod3b453,

Looks like you're seasoned C coder. How about this, FASM-style: (slightly updated version from here)
Code:
struc descriptor [def] {
common
  local .base,.limit,.type
  .base = 0
  .type = 0x0010; defaults: byte-granularity 16-bit not-present DPL0 read-only not-accessed data
forward
  match =base==v, def \{ .base = v \}
  match =limit==v, def \{
    \local matched
    matched equ 0
    match vv*=4k,v \\{
      .limit = vv
      .type = .type or 0x8000
      restore matched
      matched equ 1
    \\}
    match =0, matched \\{
      .limit = v
    \\}
    restore matched
  \}
  match =a, def \{ .type = .type or 1 \}
  match =w, def \{ .type = .type or 2 \}
  match =e, def \{ .type = .type or 4 \}
  match =code, def \{ .type = .type or 8 \}
  match =r, def \{ .type = .type or 2 \}
  match =c, def \{ .type = .type or 4 \}
  match =dpl==.dpl, def \{ .type = .type and not 0x0060 or ((.dpl) and 3) shl 5 \}
  match =p, def \{ .type = .type or 0x80 \}
  match =avl==.avl, def \{ .type = .type and not 0x0100 or ((.avl) and 1) shl 12 \}
  match =64bit, def \{ .type = .type or 0x2000 \}
  match =32bit, def \{ .type = .type or 0x4000 \}
common
  if .type and 0x6008 = 0x6008
    display "Reserved combination of L and D bits in code segment descriptor", 13, 10
    err
  end if
  dw    .limit and 0xFFFF
  dw    .base and 0xFFFF
  db    .base shr 16 and 0xFF
  db    .type and 0xFF
  db    (.type shr 8 and 0xF0) or (.limit shr 16 and 0x0F)
  db    .base shr 24 and 0xFF
}

macro descriptor [def] {
common
  local .
  . descriptor def
}    
Usage:
Code:
align 8
gdt     dq  0
code0_selector = $-gdt
code3_selector = code0_selector+3
        descriptor code, 32bit, dpl=3, base=0, limit=0xFFFFFF*4k, p, r
data0_selector = $-gdt
data3_selector = data0_selector+3
        descriptor data, 32bit, dpl=3, base=0, limit=0xFFFFFF*4k, p, w    
While descriptor struc-macro looks convoluted, its usage isn't.
cod3b453 wrote:
If you want to run 32 bit user programs, add another data and code entry with GDT_RING3 instead and then use jmp/iret to switch into user mode (interrupts/syscalls will later let you back to ring 0).
Are separate PL0/3 descriptors necessary? In flat model two DPL3 descriptors seem to be enough.
cod3b453 wrote:
The 16 bit IDT…
IVT. I'm not nit-picking.

----8<----
Teehee,

Do you realise already that after you've switched CPU into PM, most of RM services are unavailable? There are VBE/PCIBIOS/PnP 32-bit interfaces, but you must implement keyboard/FDD/HDD access by yourself (or switch back to RM).
Post 30 May 2010, 08:57
View user's profile Send private message Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 618
cod3b453 30 May 2010, 11:38
I'm not a particular C fan actually but that is a handy macro nonetheless Cool

It's not necessary but will prevent system code entering a non-PL0 state from GDT misalignment, accidental switches or bad drivers.

Yep, IVT is what I meant to say.
Post 30 May 2010, 11:38
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4354
Location: Now
edfed 30 May 2010, 12:26
the pseudo descriptor is not 16 bits, and not 5 bytes.
i don't know where you found this false afirmation.

pseudo descriptor is:
one word and one dword, then, 6 bytes.

the word comes first.

then, to align pseudo descriptor on 8 bytes boundary, you should make this:
Code:
align 8
dw 0
gdtr:
dw gdtsize
dd gdtbase
    


after, you do this
Code:
lgdt [gdtr]
    
Post 30 May 2010, 12:26
View user's profile Send private message Visit poster's website Reply with quote
Teehee



Joined: 05 Aug 2009
Posts: 570
Location: Brazil
Teehee 30 May 2010, 12:32
baldr wrote:
Do you realise already that after you've switched CPU into PM, most of RM services are unavailable? There are VBE/PCIBIOS/PnP 32-bit interfaces, but you must implement keyboard/FDD/HDD access by yourself (or switch back to RM).
Yeah, i'm advised Smile

_________________
Sorry if bad english.
Post 30 May 2010, 12:32
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2, 3, 4, 5, 6, 7  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.