flat assembler
Message board for the users of flat assembler.
![]() Goto page Previous 1, 2, 3, 4, 5, 6, 7 Next |
Author |
|
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. |
|||
![]() |
|
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 ![]() _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug |
|||
![]() |
|
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. |
|||
![]() |
|
Teehee 25 May 2010, 12:35
Hey edfed, i will do that! THanks.
|
|||
![]() |
|
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?
|
|||
![]() |
|
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? 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? |
|||
![]() |
|
Teehee 25 May 2010, 21:19
5.
![]() (Will the boot sector keep in memory after the boot?) |
|||
![]() |
|
baldr 25 May 2010, 23:06
Teehee wrote: Will the boot sector keep in memory after the boot? 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. |
|||
![]() |
|
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
![]() ![]() ![]() ![]() ![]() 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 ![]() 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 ![]() I dont know build the GDT ![]() I need a step-by-step, explaining everything slowly (i'm dumb ![]() (i already did read this, and this and the intel manual ![]() Thanks and sorry ![]() _________________ Sorry if bad english. |
|||
![]() |
|
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:
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. |
|||
![]() |
|
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). |
|||
![]() |
|
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. |
|||
![]() |
|
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 ![]() |
|||
![]() |
|
Teehee 29 May 2010, 21:17
ohhh pretty good
![]() 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)? |
|||
![]() |
|
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 ![]() Last edited by cod3b453 on 30 May 2010, 09:52; edited 1 time in total |
|||
![]() |
|
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. ![]() ManOfSteel wrote: Of course. In this case it's missing a dw... ----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 } 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 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). cod3b453 wrote: The 16 bit IDT… ----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). |
|||
![]() |
|
cod3b453 30 May 2010, 11:38
I'm not a particular C fan actually but that is a handy macro nonetheless
![]() 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. |
|||
![]() |
|
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] |
|||
![]() |
|
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). ![]() _________________ Sorry if bad english. |
|||
![]() |
|
Goto page Previous 1, 2, 3, 4, 5, 6, 7 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.