flat assembler
Message board for the users of flat assembler.
Index
> OS Construction > Review my loader... Goto page 1, 2 Next |
Author |
|
kohlrak 22 Oct 2009, 00:29
Just being picky but, honestly i'd suggest writing a hlt loop instead. Something else to point out, you're initializing everything twice, once in the kernel and in the boot loader. This isn't a real big problem though. Only certain things need to be initialized (for instance, not all the segment registers are a problem on most machines). Are you planning on sticking with real mode or are you planning on going into pmode? I forget if it affects 16bit stuff or not, but you might want to consider looking into the A20 gate. It's something quite silly that could get in your way later on.
|
|||
22 Oct 2009, 00:29 |
|
bitshifter 22 Oct 2009, 03:47
Yeah, I just figured out how to get it into pmode today
I had to tweak my GDT a bit to get the RM/PM segments to agree. And yes, i will enable the a20, i want a big 'ol 4gb in flat land. I did setup everything twice so it was clear what is on both ends. Once room starts to get tight i will chop the extra stuff out. First to make it work, then to make it work better. |
|||
22 Oct 2009, 03:47 |
|
revolution 22 Oct 2009, 04:38
bitshifter wrote: First to make it work, then to make it work better. |
|||
22 Oct 2009, 04:38 |
|
kohlrak 22 Oct 2009, 11:52
Chances are, you won't have to worry about room getting tight unless you're going into vesa or something and are storing images or waveforms in your kernel. Though if you want another bit of criticism, the RM/PM segment agreement is really only good for making the interrupts work. However, if you're using 32bit stuff, you'll run into problems because the bios stuff will only be able to work with addresses under 0xFFFF, unless you find a way to tweek them using the gdt and some more fancy stuff. Though really, depending on what you plan on doing, you may just as easily write your own routines instead of using the bios routines. Usually it's safe to do a bunch of setting things up (video mode, loading kernel, etc) before jumping into pmode and then simply coding basic input and output routines and then doing all the hardware drivers that you'd inevitably have to do anyway (usb, mouse, etc).
|
|||
22 Oct 2009, 11:52 |
|
bitshifter 22 Oct 2009, 12:23
I used descriptors for null,linear32,code32,data32,code16,data16.
Now i can simply select a descriptor and switch between modes. The GDT is tweaked at runtime to adjust the addressing spaces. I am now writing a VGA driver first so i can make a debugger Then a keyboard driver would be the next thing to do. And then i need to make a very simple file system for it. My goal is to make a 32bit game engine operating system. |
|||
22 Oct 2009, 12:23 |
|
kohlrak 22 Oct 2009, 13:06
I'm going to warn you ahead of time that it's not going to be nearly as easy as you may expect it to be... IMO, VGA and VESA are slow for most games. I get flicker just clearing my screen all at once (then again, my resolution is very high and i'm using string functions for copying memory, but still). You may want to consider compatibility with or conversion of linux modules if you want anything super fast, ESPECIALLY if you're considering 3d.
|
|||
22 Oct 2009, 13:06 |
|
bitshifter 22 Oct 2009, 20:18
Initially im going to use my mode-x library.
I have the 3D part mostly all roughed out already. Ultimately i would like to have an 82845G driver. Edit: This is what i came up with to get into little 32bit mode... I can be used with my previous booter code in this thread. This is my first time being in protected mode all by myself... Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; 16-Bit (Real Mode) Kernel Entry Point. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; use16 ; Eat some code to show we loaded multiple sectors. jmp .AfterFakeCode times 512*8 db 0 ; 8 sectors of fake code. .AfterFakeCode: ; Disable any interruptions. cli ; Setup a data segment so we can access our data. mov ax,cs mov ds,ax ; Adjust the GDT and apply it. shl ax,4 ; DS * 16 = Linear address of segment base. mov bp,ax ; Put it in the pointer register. lea dx,[gdt+bp] ; Get physical address of GDT. mov [gdt_TableHeader+2],dx mov [gdt_CodeDescriptor+2],ax mov [gdt_DataDescriptor+2],ax shr ax,16 ; Linear address / (2^16=65536) mov [gdt_CodeDescriptor+4],al mov [gdt_DataDescriptor+4],al mov [gdt_CodeDescriptor+7],ah mov [gdt_DataDescriptor+7],ah lgdt [gdt_TableHeader] ; Set the protected mode bit. smsw ax ; Store Machine Status Word into AX. or ax,1 ; Set the first bit. lmsw ax ; Load Machine Status Word from AX. ; Jump far into 32-Bit code. (flushes pipeline) jmp gdt_CodeSelector:Enter32BitCode ; CS is then gdt_CodeSelector ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; 32-Bit (Protected Mode) Kernel Entry Point. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; use32 Enter32BitCode: ; Setup data and stack segments. mov ax,gdt_DataSelector mov ds,ax mov ss,ax ; Setup linear destination segment for printing. mov ax,gdt_LinearSelector mov es,ax ; Print that we are here in 32-Bit land. mov esi,g_HelloWorldMessage mov ecx,c_HelloWorldMessage_size call PrintBuffer ; Enter the main loop. MainLoop: hlt jmp MainLoop ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; PrintBuffer ; ; Input: DS:ESI -> Buffer ; ECX = Size ; ; Assumes ES = Linear base selector of GDT. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PrintBuffer: pusha ; Get current caret offset. mov ax,0x0F0E mov dx,0x03D4 out dx,al inc dx in al,dx xchg ah,al dec dx out dx,al inc dx in al,dx movzx ebx,ax ; Set a color attribute. mov ah,0x0F ; White on black. .PrintBufferLoop: ; Load a byte and process it. lodsb cmp al,10 ; Ignore the LINE-FEED character. je .CharacterProcessed cmp al,13 ; Handle the CARRIAGE-RETURN character. je .AdvanceCaretNewLine ; Write character and attribute to video memory. mov [es:(ebx*2+0xB8000)],ax ; Increase the offset value and continue. ; TODO: Add bounds checking here... inc bx jmp .CharacterProcessed .AdvanceCaretNewLine: ; TODO: Add code here... .CharacterProcessed: loop .PrintBufferLoop ; Loop through buffer. ; Set new caret offset. mov al,0x0E mov ah,bh mov dx,0x03D4 out dx,ax inc ax mov ah,bl out dx,ax ; Were outta here. popa ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Kernel data. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; gdt: dw 0 dw 0 db 0 db 0 db 0 db 0 gdt_LinearDescriptor: gdt_LinearSelector = $ - gdt dw 0xFFFF dw 0 db 0 db 10010010b db 11001111b db 0 gdt_CodeDescriptor: gdt_CodeSelector = $ - gdt dw 0xFFFF dw 0 db 0 db 10011010b db 11001111b db 0 gdt_DataDescriptor: gdt_DataSelector = $ - gdt dw 0xFFFF dw 0 db 0 db 10010010b db 11001111b db 0 gdt_TableHeader: dw $ - gdt - 1 dd gdt g_HelloWorldMessage db 'Hello from 32-Bit land!' c_HelloWorldMessage_size = $ - g_HelloWorldMessage times 512*16-($-$$) db 0 ; Padd out to 16 sectors. |
|||
22 Oct 2009, 20:18 |
|
kohlrak 23 Oct 2009, 09:44
Never make the computer do what can be done by the assembler itself. Since the main site for the project we've been working on is down, i'll just upload a zip release (i'll have to tell wolf when he gets back that the move to mercurial isn't entirely finished yet, since the site for it used to work, but one of his servers could be down too since he's been away for a few weeks). I'll upload it until the site at the end of this link is working right again. You'll find gdt.asm to be really helpful here, but feel free to peek at the rest of it.
I'd give you some more code (a printf-like routine [even called printf, but doesn't comes with all the features]) that i've done on my own for another text mode kernel (also under-developed), but that'd ruin the fun of making your own kernel from scratch.
|
|||||||||||
23 Oct 2009, 09:44 |
|
bitshifter 23 Oct 2009, 12:14
Im not sure what you mean?
Maybe to hardcode the GDT? By doing that i can ditch the setup hack. Plus i can park it in with all my other data. This works, but is it correctly implemented? Note: 0x0050 is the 16-Bit kernel entry segment. Code: gdt: dw 0 dw 0 db 0 db 0 db 0 db 0 gdt_LinearSelector = $ - gdt dw 0xFFFF dw 0 db 0 db 10010010b db 11001111b db 0 gdt_CodeSelector = $ - gdt dw 0xFFFF dw 0x0050*16 db 0 ; LOBYTE(0x0050*16/65536) db 10011010b db 11001111b db 0 ; HIBYTE(0x0050*16/65536) gdt_DataSelector = $ - gdt dw 0xFFFF dw 0x0050*16 db 0 ; LOBYTE(0x0050*16/65536) db 10010010b db 11001111b db 0 ; HIBYTE(0x0050*16/65536) gdt_TableHeader: dw $ - gdt - 1 dd gdt + 0x0050*16 _________________ Coding a 3D game engine with fasm is like trying to eat an elephant, you just have to keep focused and take it one 'byte' at a time. |
|||
23 Oct 2009, 12:14 |
|
cod3b453 23 Oct 2009, 16:58
Out of sheer paranoia, the first thing I do is cli and store dl before the sti, in case the BIOS trashes it in an interrupt - so something like this:
Code: ;... cli ; <<< jmp 0x07C0:BooterEntry ; Portability hack. BooterEntry: ; Setup segments and stack. mov ax,cs mov ds,ax mov es,ax mov fs,ax mov gs,ax mov ss,ax mov sp,0xFFFF ; Store boot drive passed from BIOS. mov [g_BootDriveNumber],dl add dl,'A' mov [g_BootDriveLetter],dl sti ; <<< ;... If you're looking to add multi- core/processor (or ACPI) you will also want these areas of memory: Code: ; 0x9FC0:0x0000 - 0x9FC0:0x03FF EBDA ; 0xE000:0x0000 - 0xE000:0xFFFF ROM Hope that helps and it goes well |
|||
23 Oct 2009, 16:58 |
|
kohlrak 24 Oct 2009, 01:16
Quote: Im not sure what you mean? Exactly my point. If it can be hardcoded without loosing functionality of the program, why not hardcode it? It saves the computer lots of time. And it might help yourself to use macros (change them if you want of course) since it's easier to read and manage and it doesn't really change the output at all. It's helpful later because then you can add segments for special data sections you find you end up wanting to constantly manipulate (like you'll notice the code i uploaded likes to keep a segment register reserved for the video lfb). |
|||
24 Oct 2009, 01:16 |
|
bitshifter 24 Oct 2009, 01:24
Thanks for the tips guys
I think i will have an equates file visible by booter and kernel which defines the kernel entry segment like c_ImageLoadSegment = 0x0050 Then if i ever decide to change my mind i only need to change one value. I dont have any books besides RBIL and Intel manuals so everything i learn is either from them or code i see on the net, im kinda shooting from the hip. |
|||
24 Oct 2009, 01:24 |
|
kohlrak 24 Oct 2009, 01:38
Quote: I dont have any books besides RBIL and Intel manuals so everything welcome to the club =p |
|||
24 Oct 2009, 01:38 |
|
edfed 24 Oct 2009, 13:28
what is boring with IA32 is:
the format of GDT entries. why the help didn't they made it easy to modify like: Code: mov dword[GDT+entry+base],base mov dword[GDT+entry+limit],size mov dword[GDT+entry+attributes],attributes mov dword[GDT+entry+pagetable],0 ;if = 0, then, no paging. WHY? |
|||
24 Oct 2009, 13:28 |
|
Dex4u 24 Oct 2009, 13:47
kohlrak wrote:
I disagree, in this case eg: if you hard coded it, you would not be able to say let Dos load your kernel, but if you left it as it was you could use a mz exe as a kernel and just as easy load it from dos from hdd, usb, floppy, cd etc plus your boot loader. PS: vesa + pmode can be very smalL, i fited vesa high res, pmode, gui, vesa font, cdplayer in less than 512bytes |
|||
24 Oct 2009, 13:47 |
|
revolution 24 Oct 2009, 13:53
edfed wrote: WHY? |
|||
24 Oct 2009, 13:53 |
|
kohlrak 24 Oct 2009, 14:36
Quote: I disagree, in this case eg: if you hard coded it, you would not be able to say let Dos load your kernel, but if you left it as it was you could use a mz exe as a kernel and just as easy load it from dos from hdd, usb, floppy, cd etc plus your boot loader. If you're going down that route instead of using your own boot loader, even easier to use grub for most people. Quote: PS: vesa + pmode can be very smalL, i fited vesa high res, pmode, gui, vesa font, cdplayer in less than 512bytes Laughing If you read the source i posted, you'd find that your examples (especially the ones on OSDev) were alot of help (commented a few times i think). So i know what you can do (If only we could convince you to write tutorials for most common hardware as clean as your PMode example), but for whatever reason, vesa still feels slow, even if it is small. Quote: Legacy. The old '286 supports paging. It all started from there and they had to keep it all backwards compatible. Wouldn't the smaller size cause problems with the GDTR? It could always, naturally, figure out based on a few flags here and there whether it's 80286 or 80386 or not, but wouldn't that be a problem for the CPU? Better to just scrap and start over... Because seriously, who's going to want to mix entry types like that? If someone throws a 386 entry on a 286 machine, they deserve what they get. I don't see why backwards compatibility would be a problem (since it could assume it's a 286 until it has reason to believe otherwise). |
|||
24 Oct 2009, 14:36 |
|
bitshifter 24 Oct 2009, 14:55
Yeah, i understand that it locks me in at 0x0050 like an MZ.
Im going to hardcode it since it will only use my own bootloader. Also, i have made my first pmode string printing routine, yay :) It only took me two days to get it working, pretty sad i might say... The nice thing is it works in linear space and does wraparound and scrolling. I tried hardware scrolling but it kept moving the base address on me :( Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; PrintString ; ; Input: DS:ESI -> String (NULL Terminated) ; ; Assumes ES = Linear base selector of GDT. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PrintString: pusha ; Get current caret offset. mov ax,0x0F0E mov dx,0x03D4 out dx,al inc dx ; 0x03D5 in al,dx xchg ah,al dec dx ; 0x03D4 out dx,al inc dx ; 0x03D5 in al,dx movzx ebx,ax ; EBX = Linear offset. .PrintLoop: ; Load a byte and process it. lodsb cmp al,0 ; Terminate upon NULL character. je .Finished cmp al,10 ; Ignore the LINE-FEED character. je .PrintLoop cmp al,13 ; Handle the CARRIAGE-RETURN character. je .NewLine ; Write character and attribute to video memory. mov ah,0x0F ; Color attribute. (White on Black) mov [es:(ebx*2+0xB8000)],ax ; Ooh, thats fancy :) ; Increase the offset value and continue. inc bx cmp bx,80*25 jl .PrintLoop ; We can safely fall through into the NewLine handler. ; We already know we are out of range and we just want to scroll up. ; I guess we could do a jump to just before the (mov bx,80*25-80). ; Do a CR/LF and scroll up if needed. .NewLine: ; x = p % 80 ; y = p / 80 ; p = p + (80 - x) Add remaining chars to position to get to next row. mov ax,bx ; Linear caret position. mov cx,80 ; Screen is 80 columns wide. xor dx,dx ; Clear DX for DIV instruction. div cx ; AX = p / 80, DX = p % 80 sub cx,dx ; remaining = 80 - (p % 80) add bx,cx ; p = p + (80 - (p % 80)) cmp bx,80*25-80 jle .PrintLoop mov bx,80*25-80 mov edx,80*2 ; Head starts at x(0), y(1) and tail is behind it at x(0), y(0) .ScrollLoop: mov eax,dword[es:(edx+0xB8000)] ; Read two characters and their attributes from the head. mov dword[es:(edx+0xB8000-80*2)],eax ; Write two characters and their attributes into the tail. add edx,4 cmp edx,80*2*25 +80*2 ; This extra (+80*2) pulls in an offscreen line into the last line :S jl .ScrollLoop jmp .PrintLoop .Finished: ; Set new caret offset. mov al,0x0E mov ah,bh mov dx,0x03D4 out dx,ax inc al ; 0x0F mov ah,bl out dx,ax ; Were outta here. popa ret Edit: Ok, now that its up and running i need to think about a file system. I have read EVERY post in the OS construction area and still need ideas. After playing with FAT12 i thought it was a bit more than it needed to be. I am thinking using LFB is the hardest to use but the most efficient... And maybe i should have some type of header since the block size is not 512 bytes on all of my floppy drives, some say they are 128 byte blocks. Boy, since 512 was so common people started using the word blocks interchangibly with the word sectors, now that will confuse a beginner. So, what would the simplest and most efficient file system be, is it FAT12? |
|||
24 Oct 2009, 14:55 |
|
Alphonso 25 Nov 2009, 12:52
bitshifter wrote: I think i should max out the kernels SP to 0xFFFF so if the kernel code was big enough it would not get trashed by the stack pointer. |
|||
25 Nov 2009, 12:52 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.