putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]
kan niet, kijk maar wat een compiler/linker doet met segmenten, etc. Bovendien moet je ook onder het limiet blijven...Erg kewle tutorial... Maarruhhh, ik kan absoluut geen ASM, dus domme vraag: kun je een bootsector in C proggen? C kan ik wel
putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]
Waar heb je het over?Op dinsdag 31 juli 2001 13:19 schreef Infinitive het volgende:
[..]
kan niet, fopen is een functie uit een bibliotheek en aangezien je nog geef bibliotheken kan openen... en bovendien misschien het formaat van je lib niet in het zelfde formaat is als de layout die je zelf aan je lib wilt geven. Om nog maar te zwijgen over wat een compiler/linker doet met segmenten, etc. Bovendien moet je ook onder het limiet blijven...
Deze code wordt gewoon gebruikt onder (bijv.) windows om de bootsector op een disk te zetten
Verwijderd
Hij heeft het over het stukje code van 4of10. Correct me if I'm wrongOp dinsdag 31 juli 2001 13:19 schreef Infinitive het volgende:
[..]
kan niet, fopen is een functie uit een bibliotheek en aangezien je nog geef bibliotheken kan openen... en bovendien misschien het formaat van je lib niet in het zelfde formaat is als de layout die je zelf aan je lib wilt geven. Om nog maar te zwijgen over wat een compiler/linker doet met segmenten, etc. Bovendien moet je ook onder het limiet blijven...
Volgens mij haalt ie een paar dingen door elkaar, maar het kan aan mij liggenOp dinsdag 31 juli 2001 13:32 schreef CoDeR het volgende:
[..]
Hij heeft het over het stukje code van 4of10. Correct me if I'm wrong
Verwijderd
je mag er best een int main(int argv, char **argv) van jaOp dinsdag 31 juli 2001 13:17 schreef Rob2k het volgende:
Heb die code ook gebruikt om bootsector te schrijven. Maar misschien is het handig om het zo te doen:
int main (int argc, char *argv[]);
en dan ook:
bootsector=fopen(argv[1],"rb")
zit je niet meer vast aan dat boot.bin, gebruik zelf nl. andere namen...zoals velen zullen doen
Uhm volgens mij zie het een beetje verkeerd.kan niet, fopen is een functie uit een bibliotheek en aangezien je nog geef bibliotheken kan openen... en bovendien misschien het formaat van je lib niet in het zelfde formaat is als de layout die je zelf aan je lib wilt geven.
Die code is bedoeld om vanuit DOS de bootsector te schrijven (onder *NIX/*BSD kun he daar dus 'dd' voor gebruiken). Je hebt dus al _wel_ libraries en het is gewoon de DOS API hoor, want dit programma _is_ voor DOS/Win. Een bootsector schrijven vanuit je eigen OS is nog wel een paar tutorials verder hoor
Verwijderd
Nee een bootsector kan niet in C.Op dinsdag 31 juli 2001 12:53 schreef beelzebubu het volgende:
Erg kewle tutorial... Maarruhhh, ik kan absoluut geen ASM, dus domme vraag: kun je een bootsector in C proggen? C kan ik wel
Okay, tenzij je gaat EMITten en een C code vol met inline assembly maar dan heb je er ook vrij weinig aan
Ik wilde zeggen wat 4of10 hierboven net poste:
Nee een bootsector kan niet in C.
Okay, tenzij je gaat EMITten en een C code vol met inline assembly maar dan heb je er ook vrij weinig aan
putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]
Als je echt een revolutionair idee hebt voor een os zou ik de linux kernel gebruiken, het grootste werk is al voor je gedaan!
Ok, linux laat wat te wensen over wat betreft het geheugen management, en het is voor velen een ouderwetste monolitische kernel met een shell, maar wel erg stabiel en modulair.
Samengevat: als je een revolutionair idee hebt voor een os maakt dan niet een nieuw os maar implementeer het in linux(kernel)
| To acknowledge what is known as known and what is not known as known is knowledge. |
Ik zal zelf geen OS gaan schrijven, maar ik wil wel weten hoe het zo'n beetje zit.Ok, het is een goede oefening om je computer beter te leren kennen, en om je c/c++/java/assembler kennis te vergroten maar waarom zou je een os schrijven?
Dan kan het nog steeds geen kwaad om in ieder geval de beginselen te weten.Samengevat: als je een revolutionair idee hebt voor een os maakt dan niet een nieuw os maar implementeer het in linux(kernel)
putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]
| To acknowledge what is known as known and what is not known as known is knowledge. |
Verwijderd
1
2
3
| Bootterminator:
org 510
dw 0xAA55 |
lijkt mij genoeg. Het is zelfs gevaarlijk als de PC zomaar bij het einde komt (al weet ik niet wat xAA55 voor 'n opcode is). Als je echt een opvang wil hebben voor zoiets zou ik een errorroutine maken vlak voor 510 met de strekking dat je hier nooit had moeten komen. Een overflow in een textstring is easy (ja, ik praat uit ervaring). Vooral als je zin hebt om zelf te gaan kloten met allerlei ASM truukjes om je bootupsequence nog gafer te maken dan je medetweaker (hell, jij bent natuurlijk de uberkoning) is het debuggen wel een sportief.
Maar ehh, heb je ook een URL naar een andere locatie dan hier op GoT? Hier komen er ook veel andere teksten/opmerkingen tussendoor, die niet altijd tot de tekst zelf behoren.
Je hebt ook wel gelijk. Maar deze discussie is eigenlijk zinloos. Want je heb nog steeds dan wat basiskennis nodig, die je juist opdoet door te denken hoe je zelf een os zou opzetten. Ofwel, we kunnen betere deze discussie stoppen, net als de discussie of het wel zinvol is om een tutorial te schrijven als er al een aantal beschikbaar zijn... voor de mensen die het interessant vinden is het leuk dat JayTaph de moeite neemt om het te doen.nee ok. maar gevolg is dat er heel veel (kleine) osj'es komen, je kunt beter een al bestaand os verbeteren.
putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]
desnoods kan ik ze hosten als je geen ruime hebt
Een website waar je de tutorials verzameld zou idd ook wel leuk zijn, handiger dan alles in deze thread gooien of steeds een nieuwe thread aanmaken
>bij het einde komt (al weet ik niet wat
>xAA55 voor 'n opcode is). Als je echt een
>opvang wil hebben voor zoiets zou ik een
>errorroutine maken vlak voor 510 met de
>strekking dat je hier nooit had moeten
>komen.
Zet anders een JMP $ voor het einde neer. In plaats van NOP'jes kun je alles wat je maar wilt neerzetten.. De rede waarom het NOPjes zijn, is dat ik makkelijk in een hex-editor (MC in dit geval) kan zien hoe groot mijn bootsector-code is, en hoe groot de data is (die standaard op 00 staat). Als ik er 00'tjes neer zou zetten, dan zou ik dus niet meer kunnen zien wat data is, en wat opvulling is. Jouw manier werkt net zo goed.. TIMTOWTDI
De tutors mogen best ergens anders komen te staan, maar ik denk dat iemand anders dan maar van de HTML-opmaak en hosting moet regelen..
Ik weet niet wanneer het volgende deel komt, zeer binnenkort in ieder geval want hij is al bijna af. Daarna moet ik vanaf 0 weer gaan beginnen, en dat gaat langer duren, tenzij er mensen zijn die graag mee willen helpen.
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Ik heb ooit een stukkie van een ASM tutorial doorgebladerd, maar ik kan iem een goeie aangeven? Er zijn een paar codes die mij niet 100% duidelijk zijn. En, waar is die Interrupt list online te vinden?
|_____vakje______|
downloadable: http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
Reply op CyberSnooP
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Verwijderd
Verwijderd
Heb jij die boeken ook? Dolle boel hé!Op maandag 30 juli 2001 13:23 schreef Tsjipmanz het volgende:
Misschien dat Andrew S. Tanenbaum je wil helpen ( ast@cs.vu.nl )
Verwijderd
Kun je idd wel in je 2nd stage bootloader zetten (VOOR de protected mode code want video modes switchen is toch wel iets makkelijker in real modeOp dinsdag 31 juli 2001 23:42 schreef JayTaph het volgende:
Wat ik heel erg stoer vind, maar dat is niet echt de bootsector die dat doet, maar de kernel-loader, is om het beeld in grafische mode te zetten (standaard 320x200x256), en tijdens het booten een gave landscape-scroller laat zien.. (voor de oudjes onder ons: zoiets als MARS). Met daaronder een percentage met hoever hij nog moet... lijkt me echt super.. het schrijven van een scroller is niet moeilijk, ook niet als front-end dus misschien wel leuk als iemand zich geroepen voelt om dit te schrijven? (in asm, anders kan het feest niet doorgaan)
Ik heb vroeger nog wel menig voxel-scroller gecode, maar ik denk niet dat ik die nog terug kan vinden... Zo moeilijk waren ze nu ook weer niet..
Owja,.. volgend deeltje (fat12 lezen en laden van primary KERNEL.SYS) komt er binnenkort aan voor de geinteresseerden..
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Verwijderd
http://bochs.sourceforge.net/
Een OS emulator voor windows.
Je hoeft dus niet meer te rebooten en zo, superhandig!
Verwijderd
Is idd wel makkelijk. mov ax, 0x13 int 0x10 is veel minder werk dan VGA poorten of V86 tasksOp zondag 19 augustus 2001 20:05 schreef JayTaph het volgende:
Ik denk dat je dan het beste kunt switchen naar 320x200 en daarna een jump kan maken naar PM om de kernel te starten.
Misschien kun je beter eerst de IDT en GDT initializeren. Dan staan je offsets al goed en kun je interrupts enablen(is wel makkelijk als je gebruik wilt maken van de timerintOp dat moment kun je wel netjes van C gebruik maken en je voxel-scroller starten. Onder deze scroller door laad je je kernel in (zet je scroller op de PM timerint, genereer frame, plot frame, EOI) en laad ondertussen de rest in.. Je moet dan wel rekening houden met andere tijd-kritieke operaties zoals het kalibreren van je delay() (bogomips).
Ook zal het misschien wat lastiger worden met eventuele switches van IDT's en GDT's. Kwestie van eventjes goed uitdenken en dan kom je daar ook wel uit..
Verwijderd
Het werkt ook onder UNIX voor de *NIX/*BSD gebruikers hierOp zondag 19 augustus 2001 22:14 schreef ceidhof het volgende:
Dit is heel interessant:
http://bochs.sourceforge.net/
Een OS emulator voor windows.
Je hoeft dus niet meer te rebooten en zo, superhandig!
Verwijderd
Dit is een cpu emulator, geen OS emulator! Dit juweeltje emuleert een complete i386 cpu! (goed performance is ver te zoeken maar da geeft niet) dingen als dos draaien er prima op, net ff norton sysinfo installed toch nog 3.6 gescoord bij de cpu test wat net iets langzamer is dan 'n 8mhz 286Op zondag 19 augustus 2001 22:14 schreef ceidhof het volgende:
Dit is heel interessant:
http://bochs.sourceforge.net/
Een OS emulator voor windows.
Je hoeft dus niet meer te rebooten en zo, superhandig!
Verschrikkelijke bezigheid, zeker V86 tasks in een primaire omgeving.. ik raad het je niet aan in ieder geval en mijn bios weet veeeeel meer van VGA-poorten af dan ik, dus laat hem dat maar lekker regelenIs idd wel makkelijk. mov ax, 0x13 int 0x10 is veel minder werk dan VGA poorten of V86 tasks
Waar ik eigenlijk op doel is een beetje een probleem waar ik mee zit dat ik nooit heb weggewerkt in mijn eigen OS, namelijk dat de loader een temporary IDT en GDT maakt, en pas daarna alles goed gaat zetten voor de kernel. Dat is gewoon 1 manier van opzetten maar niet echt een optimale manier. Het probleem KAN onstaan dus dat je kromme omwegen moet gaan verzinnen om je voxel-scroller te laten werken in beide GDT/IDT's.Misschien kun je beter eerst de IDT en GDT initializeren. Dan staan je offsets al goed en kun je interrupts enablen(is wel makkelijk als je gebruik wilt maken van de timerint). IDT en GDT initen duurt toch maar een paar ms
. Bogomips berekenen is misschien wel een goed ID omdat ff niet te laten beinvloeden door een landscape scroller ja
. Maar sowieso, het booten op zich duurt niet zo lang. Disk I/O (en terminal) is nog het traagst van alles. Dus het nige wat echt lang gaat duren is files inladen. En het FS wordt eigenlijk toch pas geinitializeerd nadat je de 'standaard' system init hebt gedaan (zoals delay loops, protected mode stuff, enz.). Dus ff het systeem opzetten (duurt maar heel kort) en dan de scroller is denk ik het beste.
Als je een eigen OS aan het opzetten bent dan kan je hier natuurlijk rekening mee houden, en is het waarschijnlijk helemaal niet nodig om uberhaupt 2 keer te switchen van GDT's.
Het opstarten van het systeem tot aan de construct (dat is mijn kernel-loader waarin ik mijn kernel-configuratie kan editten) kost ongeveer 1 seconde.. da's ook zonde om daarvoor een scrollertje te bouwen
Het beste is inderdaad om na de initialisatie van kernel tot aan "prompt" zo'n voxel-scroller tevoorschijn te toveren.
Op zich hoort de delay-calibratie thuis in het opstarten van de feitelijke kernel. Aangezien deze een ongestoorde timer-int moet hebben zou de scroller dus eventjes gaan haperen op het moment dat je deze loskoppelt. Voor de rest zou disk-io en de hele reutemeteut geen tot weinig invloed moeten hebben over de scroller en zou het netjes moeten blijven werken. Een kwestie van implementeren om te zien of dat daadwerkelijk zo is
Ik gebruik zelf bochs ook voor development. Om precies te zijn, 2 versies. 1 normale versie en 1 debug versie. Uitermate handig, zeker met de uitgebreide logging die bochs meegeeft elke sessie, maar de debugger is nou niet echt vriendelijk te noemen. Ga niet alles puur compatible maken voor bochs, maar probeer je OS af en toe ook te booten vanaf verschillende systemen om te kijken of het wel echt overal werkt.
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Een vriend van me (drZymo) is begonnen met een OS, waar ik (samen met hem) de shell (inclusief een built-in interpreter voor een eigen scripttaal) voor ga maken.
De bedoeling is dan dat in feite alle proggels in dat taaltje gemaakt worden. (in eerste instantie alleen maar een filebrowser)
Ga zo door
4200Wp ZO + 840Wp ZW + 1680Wp NW | 14xIQ7+ + 1xDS3-L | MTVenusE | HWP1
Verwijderd
Tsja ik ben nu bijna klaar met mijn V86 tasks, moet nog wat virtual memory dingen verbeteren, maar het is idd wel veel werkOp maandag 20 augustus 2001 00:39 schreef JayTaph het volgende:
Verschrikkelijke bezigheid, zeker V86 tasks in een primaire omgeving.. ik raad het je niet aan in ieder geval en mijn bios weet veeeeel meer van VGA-poorten af dan ik, dus laat hem dat maar lekker regelen
[..]
Ja, vooral als je paging gebruikt met andere base adresses en zo. Maar een tijdelijke GDT heb je sowieso nodig om naar je pmode kernel te springen. IDT hoeft niet per se eigenlijk. Maar die voxel hoeft bij de temporary GDT (de bootsector waarschijnlijk) toch nog niet aan te staan en de GDT reloaden is een van de eerste dingen die mijn kernel file doetWaar ik eigenlijk op doel is een beetje een probleem waar ik mee zit dat ik nooit heb weggewerkt in mijn eigen OS, namelijk dat de loader een temporary IDT en GDT maakt, en pas daarna alles goed gaat zetten voor de kernel. Dat is gewoon 1 manier van opzetten maar niet echt een optimale manier. Het probleem KAN onstaan dus dat je kromme omwegen moet gaan verzinnen om je voxel-scroller te laten werken in beide GDT/IDT's.
Hehe ja eigenlijk wel .. de scroller is toch wel iets wat je beter wat later op kan doen jaOp zich hoort de delay-calibratie thuis in het opstarten van de feitelijke kernel. Aangezien deze een ongestoorde timer-int moet hebben zou de scroller dus eventjes gaan haperen op het moment dat je deze loskoppelt. Voor de rest zou disk-io en de hele reutemeteut geen tot weinig invloed moeten hebben over de scroller en zou het netjes moeten blijven werken. Een kwestie van implementeren om te zien of dat daadwerkelijk zo is(maar tegen de tijd dat je dat kan, heb je je OS al feitelijk af :-))
Mijn probleem is (ik heb gelukkig veel test bakken) dat mijn OS niet onder Bochs werkt. Maar veel OSsen out there werken WEL onder Bochs maar niet op alle 5 mijn test bakken, en mijn OS doet dat wel. Bochs geeft in de bootsector (!) al een error dus dat is er zo uit te halen neem ik aan, maar mijn test bakken gebruik ik eerder om te kijken of het ook op 'echte' computers werkt. Want onder Bochs laten draaien is one thing, op een echte bak another...Ik gebruik zelf bochs ook voor development. Om precies te zijn, 2 versies. 1 normale versie en 1 debug versie. Uitermate handig, zeker met de uitgebreide logging die bochs meegeeft elke sessie, maar de debugger is nou niet echt vriendelijk te noemen. Ga niet alles puur compatible maken voor bochs, maar probeer je OS af en toe ook te booten vanaf verschillende systemen om te kijken of het wel echt overal werkt.
Afgezien van de jump naar Pmode gebruik ik nog 1. In totaal doe ik dus 3 keer een GDTROp maandag 20 augustus 2001 02:33 schreef 4of10 het volgende:
Ja, vooral als je paging gebruikt met andere base adresses en zo. Maar een tijdelijke GDT heb je sowieso nodig om naar je pmode kernel te springen. IDT hoeft niet per se eigenlijk. Maar die voxel hoeft bij de temporary GDT (de bootsector waarschijnlijk) toch nog niet aan te staan en de GDT reloaden is een van de eerste dingen die mijn kernel file doet
Het grootste voordeel van bochs vind ik de sublieme logging, die echt letterlijk elke processortick laat zien. Ik heb daar zoveel geniepige foutjes mee kunnen traceren waar ik op een normale PC dagen over heb kunnen doen (de piepjes, de x'jes op het beeld, de deadlocks en de reboots).Mijn probleem is (ik heb gelukkig veel test bakken) dat mijn OS niet onder Bochs werkt. Maar veel OSsen out there werken WEL onder Bochs maar niet op alle 5 mijn test bakken, en mijn OS doet dat wel. Bochs geeft in de bootsector (!) al een error dus dat is er zo uit te halen neem ik aan, maar mijn test bakken gebruik ik eerder om te kijken of het ook op 'echte' computers werkt. Want onder Bochs laten draaien is one thing, op een echte bak another...
Maar zoals ik al zei: een OS draaien in bochs alleen is niet verstandig, af en toe checken of hij onder echte systemen (en liefst zoveel mogelijk verschillende) draait wel...
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Verwijderd
En voor dat GDT gebruik, 3 lijkt me wel een beetje veel ja
Ik doe het zo iig:
BootSector:
- Load Kernel (van disk)
- disable interrupts en NMI's
- een GDT (null, data en code, base = 0x0. limit = 4GIG)
- enable protected mode
- jump naar de kernel
Kernel:
- PIC remappen
- A20 enablen
- page tables setten
- paging enablen
- IDT opzetten
- nieuwe GDT opzetten
- jumpen naar het nieuwe segment
en dan komt de C code..
- Kernel
hieronder dan; processormanagement, memory-management
- User Interface
- IO systeem
File handling, printing, ...
https://fgheysels.github.io/
Verwijderd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| IDEAL ORG 0 mov ax, 07c0h mov ds, ax cli xor ax, ax mov ss, ax mov sp, 0FFFFh sti mov [drive],dl mov si, msg call print_string xor ah, ah int 16h int 19h PROC print_string string: cld lodsb cmp al, 0 jz eind_string call printchar jmp string eind_string: ret ENDP Print_string PROC printchar mov ah,eh int 10h ret endp printchar msg DB 'boot!',13,10,0 drive db 0 times 510-($-$$) db 9h dw aa55h |
Ik heb dat programma een beetje in gekort en vertaalt naar tasm.
Maar nu doet hij het niet.
wat is er fout?
Verwijderd
Geen ID .. wat GAAT er fout? De code werkt namelijk gewoon onder NASM en ik zie er zo niet iets fout in (niet dat ik nooit ergens overheen lees of zowOp maandag 20 augustus 2001 21:43 schreef M_KOS het volgende:
... code ...
Ik heb dat programma een beetje in gekort en vertaalt naar tasm.
Maar nu doet hij het niet.
wat is er fout?
Anders probeer NASM maar eens, werkt heel fijn en is gratiz
Volgens mij ben je het vergeten te vertalen naar tasm.Op maandag 20 augustus 2001 21:43 schreef M_KOS het volgende:
Ik heb dat programma een beetje in gekort en vertaalt naar tasm.
Maar nu doet hij het niet.
wat is er fout?
Probeer dit eens:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| text segment public use16 assume cs:text,ds:text org 0 start: push cs pop ds cli xor ax, ax mov ss, ax mov sp, 0FFFFh sti mov [drive],dl mov si, offset msg call string xor ah, ah int 16h int 19h string: cld lodsb cmp al, 0 jz eind_string call printchar jmp string eind_string: ret printchar: mov ah,00eh int 10h ret msg db 'boot!',13,10,0 drive db 0 org 510 dw 0aa55h text ends end |
Btw om de een of andere reden wil tlink geen com files maken. Los dit op door gewoon een exe file te maken en de eerste 512 bytes weg te knippen. De resterende 512 zet je dan in je bootsector neer.
"Ore wa bakemono? Che, ore wa akuma da!"
Verwijderd
thanks maar bij tlink geeft hij de volgende error:Op dinsdag 21 augustus 2001 19:44 schreef thrax het volgende:
[..]
Volgens mij ben je het vergeten te vertalen naar tasm.
Probeer dit eens:
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 text segment public use16 assume cs:text,ds:text org 0 start: push cs pop ds cli xor ax, ax mov ss, ax mov sp, 0FFFFh sti mov [drive],dl mov si, offset msg call string xor ah, ah int 16h int 19h string: cld lodsb cmp al, 0 jz eind_string call printchar jmp string eind_string: ret printchar: mov ah,00eh int 10h ret msg db 'boot!',13,10,0 drive db 0 org 510 dw 0aa55h text ends end
Btw om de een of andere reden wil tlink geen com files maken. Los dit op door gewoon een exe file te maken en de eerste 512 bytes weg te knippen. De resterende 512 zet je dan in je bootsector neer.
no program entry point
wat moet ik doen?
[edit]probleem opgelost je was end start vergeten{/edit]
Verwijderd
Ik kan je wel vertellen, dat het iets is wat je neit in een howto kunt uitleggen. Hoeft ook niet
Wat je nodig hebt is: "Linux 2.4 kernel internals", een hoop lef, en codeer-ervaring.
Ik heb geen windows-systeem op dit moment om tasm uit te proberen, maar waarschijnlijk link je het allemaal naar een exe toe in plaats van naar een raw binary (16bit BIN-file). Als het goed is kun je daar opties voor meegeven..Op dinsdag 21 augustus 2001 21:25 schreef M_KOS het volgende:
[..]
thanks maar bij tlink geeft hij de volgende error:
no program entry point
wat moet ik doen?
[edit]probleem opgelost je was end start vergeten{/edit]
als ik me nog goed kan herinneren is dat de optie /t:
1
2
| tasm boot.asm tlink /t boot.obj boot.com |
ofzoiets geloof ik...
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Verwijderd
keep up the good work
edit: nog een leuk boek over deze stof: "Het pc-hardwareboek" van Hans-Peter Messmer, uitgegeven op Addison-Wesley
De exe header bestaat uit de eerste 512 bytes van je programma. Als dit bovenstaande compile krijg je een .exe bestandje van 1024 bytes. De laatste 512 bytes is dan je bootsector. De eerste 512 bytes kun je makkelijk strippen als je bijvoorbeeld een hexeditor als 'psedit' hebt, maar met een andere zal het ook wel kunnen.
Overgens is op http://www.nondot.org/sabre/os/articles ook veel info over operating systems te vinden.
"Ore wa bakemono? Che, ore wa akuma da!"
Verwijderd
zoiets van
1. bootloader
1.1. blah
2. kernel
2.1 memory bla
2.1.1 flat memorie
...
slaat ff nergens op hoor, gaat om het idee...
maar dan is het wat duidelijker wat er allemaal komt kijken bij het bouwen van een OS
anyone? *liefaankijk*
zoiets eigenlijk dus idd, en dan misschien nog per onderdeel een tutor... (oei dit gaat veel werk wordenOp maandag 20 augustus 2001 19:17 schreef whoami het volgende:
Ik ben niet echt een goede schrijver, maar wel geïnteresseerd in zo'n tutor. Moest ik die tutorial echter schrijven, zou ik niet direct beginnen met de details uit te spitten en uit te leggen hoe je een boot-sector schrijft. Ik zou eerst het OS in een aantal grote stukken uit elkaar trekken;
- Kernel
hieronder dan; processormanagement, memory-management
- User Interface
- IO systeem
File handling, printing, ...
want hij is echt SUPER VET (oid
8<------------------------------------------------------------------------------------
Als ik zo door ga haal ik m'n dood niet. | ik hou van goeie muziek
geef anders aub links waarmee ik verder kan want dit vint ik SUPER
8<------------------------------------------------------------------------------------
Als ik zo door ga haal ik m'n dood niet. | ik hou van goeie muziek
keep up the good work
edit: ik moet toegeven dat het best een goed gevoel was om "hello bootsector!" te zien direct na het booten op een blauwe achtergrond, doet me denken aan heel lang geleden ...
Op dinsdag 31 juli 2001 15:53 schreef CBravo het volgende:
Het is zelfs gevaarlijk als de PC zomaar bij het einde komt (al weet ik niet wat xAA55 voor 'n opcode is).
1
2
| 000001FE 55 push bp 000001FF AA stosb |
Dan hangt het er maar net vanaf waar je ES:DI heenwijst of dat gevaarlijk is... maar handig is het niet iig.Op maandag 27 augustus 2001 01:53 schreef curry684 het volgende:
code:
1 2 000001FE 55 push bp 000001FF AA stosb
- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!
Programmer: red-eyed, mumbling mammal capable of conversing with inanimate objects.
De vraag was of het gevaarlijk was als de CPU op een onbewaakt moment tijdens het opstarten door al die NOP'jes zou jagen en bij de 55AA uit zou komen.Op maandag 27 augustus 2001 02:41 schreef Dawai het volgende:
Die 55AA is de mediacode, een soort handtekening, die vind je altijd op het einde van een DOS/Windows MBR of bootsector. Het is geen code die uitgevoerd wordt en is trouwens overbodig voor een eigen besturingssysteem. Als die code ontbreekt op een MS partitie zal Scandisk komen blaten
Dat zal wel ja, die 55AA op zich zal niet veel verkeerd doen maar dan gaat ie gewoon verder met de code voorbij die 55AA, en dat wordt gegarandeerd zooiOp maandag 27 augustus 2001 17:24 schreef curry684 het volgende:
De vraag was of het gevaarlijk was als de CPU op een onbewaakt moment tijdens het opstarten door al die NOP'jes zou jagen en bij de 55AA uit zou komen.
Programmer: red-eyed, mumbling mammal capable of conversing with inanimate objects.
Verwijderd
Ik keek bij bol.com en vond dit boek:
Assembler programmeren Grand Cru van EasyComputing en kost fl.79,50.
Weet iemand of dit een goed boek is?
Verwijderd
Het is niet off-topic hoor. De laatste opmerkingen gingen over de bootsector, en dat is waar het 1ste deel van de tutorial van Jay. over gingOp maandag 27 augustus 2001 20:29 schreef ACM het volgende:
*kuch*
Willen jullie weer richting topic gaan??
oops, iets te snel op verstuur geklikt
Wat ik dus wilde zeggen nog over die assembly, was dat je op die OS dev links ook veel voorbeelden vind van assembler bootloaders en dat je met google of zow best veel assembler tutorials kan vinden ...
Verwijderd
ik kan niet wachten...
Niet helemaal waar.. Er zijn bepaalde merken BIOS'en die gaan zeuren om deze 2 bytes waardoor "hardware-matig" er al niets wordt ingeladen. Veel programma's gebruiken deze 55AA om te kijken of iets daadwerkelijk een bootsector is (zoals dus scandisk). Terzijde: soms wordt ook de o-zo-foute E8/EB methode toegepast, dat wil zeggen dat je eerste instructie in de BS een JMP moet zijn.Op maandag 27 augustus 2001 02:41 schreef Dawai het volgende:
Die 55AA is de mediacode, een soort handtekening, die vind je altijd op het einde van een DOS/Windows MBR of bootsector. Het is geen code die uitgevoerd wordt en is trouwens overbodig voor een eigen besturingssysteem. Als die code ontbreekt op een MS partitie zal Scandisk komen blaten
Weglaten van deze signature zorgt er alleen maar voor dat je OS op een flink aantal (oude) systemen niet meer opstart. Ik denk dat op het moment dat je 510 bytes aan code in je BS hebt staan, je vast wel ergens 2 bytes kan optimizen
Maar ben weer net terug van "vakantie". Ik hoop volgende week een nieuw hoofdstuk af te hebben..
Yo dawg, I heard you like posts so I posted below your post so you can post again.
En misschien als ik me er in ge verdiepen, dat er nog een leuk OS-je uit komt.
ja, lijkt me heel leerzaam.
Is ie al af?? Kan niet wachtenOp zondag 02 september 2001 21:43 schreef JayTaph het volgende:
[..]
Ik hoop volgende week een nieuw hoofdstuk af te hebben..
8<------------------------------------------------------------------------------------
Als ik zo door ga haal ik m'n dood niet. | ik hou van goeie muziek
Schrödingers cat: In this case there are three determinate states the cat could be in: these being Alive, Dead, and Bloody Furious.
"Operating Systems: Design and Implementation - Andrew S. Tanenbaum / Albert S Woodhull"
Fijne 940 paginas over de interne werking van minix, plus source
er zijn mensen die hier veel aan hebben!
Schrödingers cat: In this case there are three determinate states the cat could be in: these being Alive, Dead, and Bloody Furious.
Waarom hoop ik nou dat jij minder fouten in je OS laat zittenOp maandag 30 juli 2001 12:04 schreef het_beest het volgende:
Ik wil best een 2e Bill Gates worden, COUNT ME IN!
Backup not found (R)etry (A)bort (P)anic<br\>AMD 3400+ 64, 2 GB DDR, 1,5 TB Raid5
Verwijderd
Dit naslag werkje niets voor jou dan?Op zondag 11 november 2001 18:08 schreef reddog33hummer het volgende:
het is wel jammer dat al die boeken of de unix/linux implementaties gaan. Ik ben benieuwd hoe NT in elkaar zit
http://www.sysinternals.com/insidew2k.shtml
Verwijderd
Dat boek heb ik ook gelezen en het is echt helemaal fantastischDit naslag werkje niets voor jou dan?
http://www.sysinternals.com/insidew2k.shtml
Een ander alternatief wat interessant is is 'Operating system concepts'. Dit boek gaat wel in op Linux EN NT(4) en behandelt verder algemene OS dingen. Het beschrijft zonder echt een oordeel te geven gewoon meerdere manieren om dingen aan te pakken en waarom je dat zo kan doen. Ook hier weer geen technisch verhaal; daarvoor heb je de programmeerhandleidingen van je PC (of andere veel 1337ere hardware
Hier had uw advertentie kunnen staan :).
Verwijderd
Als je eens de moeite leest om het topic door te lezen was je hem gewoon tegen gekomenOp donderdag 11 april 2002 21:18 schreef Molshoop het volgende:
Waar kan je eigenlijk de tutorial bekijken of downloaden?
Ik heb het hele topic gelezen, en ben alleen h1 tegengekomen, geen link of wat dan ook??Op donderdag 11 april 2002 21:22 schreef CoDeR het volgende:
[..]
Als je eens de moeite leest om het topic door te lezen was je hem gewoon tegen gekomen
Of kijk ik nou weer niet uit m'n doppen
Hier had uw advertentie kunnen staan :).
Maar ik geloof dat er ondertussen hier op GOT een aantal "gevorderde coders" erbij zijn gekomen die ook in staat zijn om een OS te schrijven.. misschien dat die zich geroepen voelen om verder dingetjes uit te leggen..
En anders staan er genoeg links her en der met verschrikkelijk veel info.
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Verwijderd
PardonOp donderdag 11 april 2002 21:47 schreef rjsomeone het volgende:
[..]
Ik heb het hele topic gelezen, en ben alleen h1 tegengekomen, geen link of wat dan ook??
Of kijk ik nou weer niet uit m'n doppen?
Verwijderd
Ik heb ze ook online gezet omdat er een flink aantal mensen dat graag wilde hebben: http://www.xs4all.nl/~joshua/tutorial/
En nu part chapter
Yo dawg, I heard you like posts so I posted below your post so you can post again.
----------------------------------------
Moeilijkheidsgraad: matig
Voorkennis: i386 assembly, FAT12
Referenties: Ralfs Brown Interrupt List
Tools: nasm
Zoals eerder gezegd gaan weg een MS-DOS compatible floppy maken met een eigen bootsector. Hierdoor is het mogelijk om onze schijfjes met eigen OS te voorzien onder windows, linux, DOS of praktisch elk ander OS. We gebruiken het FAT12 filesysteem, mede omdat het erg simpel is, en erg effectief (voor the time being in ieder geval). Praktisch bezwaar aan de FAT12 is natuurlijk de 8.3 bestandsnamen. Maar ik denk dat we daar in ieder geval ons niet druk over moeten maken. Zodra je je eigen OS gaat ontwerpen, ga je je daar natuurlijk wel druk over maken..
Ok, hoe ziet een FAT12-schijfje eruit?
Formateer een normale floppy onder linux, windows of DOS. Maar zorg er wel voor dat hij FAT12 formateerd (mkfs.msdos -F 12 /dev/fd0). Na het formateren hebben we een FAT12-schijfje, compleet met DOS-bootsector en FAT-blokken. Voor de complete layout van FAT12 moet je zelf eventjes de google gebruiken. Ik kan en ga zeker niet alles uitleggen (geld terug Bert!)
Let er op dat een FAT12-bootsector extra informatie heeft over het schijfje. Deze info wordt de BPB (BIOS Parameter Block) genoemd en ziet er zo uit:
1
2
3
4
5
6
7
8
9
10
11
12
| BytesPerSector dword
SectorsPerCluster dbyte
ReservedSectors dwword
NumberOfFATs dbyte
RootEntries dword
TotalSectors dword
Media dbyte
SectorsPerFAT dword
SectorsPerTrack dword
HeadsPerCylinder dword
HiddenSectors ddouble
TotalSectorsBig ddouble |
Deze BPB begint op offset 11 in de bootsector. De rest van de bootsector ziet er alsvolgt uit:
1
2
3
4
5
6
7
8
9
10
11
| 3-bytes jumpinstructie naar eigenlijke bootsector-code
8-bytes OEM Name
BPB structure
1-byte drive letter
1-byte ongebruikt
1-byte bootsignature
4-bytes serial number
11-bytes volume naam
8-bytes filesystem naam ("FAT12 ", of "MYOWNOS " ofzow)
448 bytes aan bootcode
2 bytes bootsector terminator (0xAA55) |
Zoals je ziet, heb je in een FAT12-schijfje al heel wat minder ruimte voor je bootsector code. Je snapt natuurlijk wel dat deze dus uitermate geoptimaliseerd moet zijn wil je alles voor elkaar krijgen wat je wilt doen in je bootsector. Een veelgebruikte truuk is om in de bootsector een soort van tweede (of zelfs derde) bootsector te laden, waardoor je ineens 1024 bytes (of zelfs nog meer) tot je beschikking krijgt. Veel OS'en waarin vaak veel moet gebeuren voordat de echte kernel geladen kan worden (zoals linux of windows) gebruiken deze truukjes volop.
Een bootsectortje die de naam van de schijf laat zien tijdens het opstarten. Het blijft simpele code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
| [bits 16] ; 16 bits code
org 0 ; We staan op offset 0
jmp End_Of_BootData
OEMName db "MyOwnOS "
BytesPerSector dw 0x0200
SectorsPerCluster db 0x01
ReservedSectors dw 0x01
NumberOfFATs db 0x02
RootEntries dw 224
TotalSectors dw 2880
Media db 0xF0
SectorsPerFAT dw 0x09
SectorsPerTrack dw 0x0012
HeadsPerCylinder dw 0x0002
HiddenSectors dd 0x00000000
TotalSectorsBig dd 0x00000000
DriveNumber db 0x00
db 0x00
ExtBootSignature db 0x00
SerialNumber dd 0x12345678
VolumeLabel db "BLAATAAP "
FileSystem db "FAT12 "
End_Of_BootData:
; We weten niet of we op 0000:7C00 of 07C0:0000 staan, daarom kiezen
; we er zelf een.
mov ax, 0x7C0 ; Segment 07C0
mov ds, ax ; Data staat op 07C0:0000 ipv 0000:7C00
xor ax, ax ; Stack Segment Goedzetten
mov ss, ax
mov sp, 0xFFFF
mov [bootdrive],dl ; Onthoud de bootdrive
; De volgende code maakt van het duffe zwarte achtergrond een
; mooi blauw kleurtje.
mov dx,0x3c8 ; VGA Palette register (werkt dus alleen
xor al,al ; op een VGA)
out dx,al ; We willen kleur 0 (background) instellen
inc dx ; VGA Data register (0x3c9)
mov al,8
out dx,al ; Output rood component
xor al,al
out dx,al ; Output groen component
mov al,32
out dx,al ; Output blauw component
dec dx ; En doe hetzelfde voor kleur 1
mov al,1
out dx,al
inc dx
mov al,48
out dx,al
out dx,al
mov al,48
out dx,al
; Nu hebben we een mooi kleurtje, print de string op
; het beeld.
mov si, msg ; Print bericht
mov cx, 0 ; 'oneindig' (max 65535) karakters
; maximaal
call PrintMsg
mov si, VolumeLabel ; Print string op het beeld
mov cx, 11 ; Maximaal 11 karakters
call PrintMsg
xor ah,ah ; Wacht op een toets
int 0x16
int 0x19 ; En reboot, de rest komt later...
; ------------------------------------------------------------------------
; Routine die een string in SI print die eindigt op een 0.
; In: CX = maximale lengte om af te drukken
PrintMsg:
cld
lodsb ; Laad uit DS:SI naar AL
cmp al,0
jz End_Of_String ; Is het een 0, dan einde
dec cx ; Maximaal aantal karakters geprint
jz End_Of_String
call PrintChar ; Print character
jmp PrintMsg ; En volgende character
End_Of_String:
ret
; -------------------------------------------------------------------------
; Routine die een karakter in AL op het scherm print. Deze routine maakt
; gebruik van BIOS-interrupt 0x10 om een karakter te plotten.
PrintChar:
mov ah,0x0E ; BIOS functie 15
mov bx,0x0001 ; Print op page 0 in kleur 1
int 0x10
ret
; -------------------------------------------------------------------------
; Data die we gebruiken in de bootsector
msg db 'hello bootsector. The volume name is: ',0
bootdrive db 0
times 510-($-$$) db 0x90 ; Opvullen met NOP (doet niets)
dw 0xAA55 ; En de boot terminator |
Veel is er ook weer niet veranderd. Eerst word over de data gesprongen, en vandaar uit is het allemaal eigenlijk hetzelfde. Het enige verschil is dat de PrintMsg routine nu in het CX-register een maximaal aantal tekens bevat die geprint wordt. Dit omdat de volumenaam niet op een 0 eindigd. Maar aangezien we weten dat de volnaam maximaal 11 characters groot kan zijn, printen we er ook maar maximaal 11 af.
Lezen van sectoren van schijf naar geheugen:
--------------------------------------------
Een stukje uit de Ralf Brown's Interrupt Lists:
Interrupt 13, functie 02
Read disk sectors into memory
AH = 02
AL = number of sectors to read (non-zero)
CH = low eight bits of cylinder
CL = sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer
Return: CF set on error
if AH=11h (corrected ECC error), AL = burst length
CF clear if successfull
AH = status
AL = number of sectors transferred
Deze functie gebruiken we om sectoren te lezen vanaf de schijf.
Uitlezen van de FAT12 root-directory.
-------------------------------------
Om een root-directory uit te lezen, moeten we eerst weten hoe deze precies is opgebouwd.
Hierna gaan we bekijken op welke sector op de schijf de root-directory begint. Dit is een beetje rekenwerk met de BPB informatie.
RootDirectoryStart = (TotalNrOfFATs * SectorsPerFAT) + ReservedSectors
Elke root-entry is 32 bytes groot. Een snelle rekensom leert ons dat we maximaal BPB.RootEntries * 32 / BPB.BytesPerSector moeten inlezen voordat de gehele root-directory in het geheugen staat. Een andere manier van oplossen, is om sector voor sector in te laden. Dit scheelt geheugen (aangezien we maar maximaal 1 sector tegelijkertijd in het geheugen hebben), en als we een file moeten laden en deze staat in de eerste rootentry-sector, dan hoeven we alle andere sectoren niet in te laden (wat weer een snelheidswinst is).
Zodra de rootentries zijn ingelezen gaan we ze allemaal af en drukken we ze af in een soort van directory-listen a la MS-DOS. Daarna wachten we weer netjes op een toets om vervolgens te rebooten.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
| [bits 16] ; 16 bits code
org 0 ; We staan op offset 0
jmp End_Of_BootData
OEMName db "MyOwnOS "
BytesPerSector dw 0x0200
SectorsPerCluster db 0x01
ReservedSectors dw 0x01
NumberOfFATs db 0x02
RootEntries dw 224
TotalSectors dw 2880
Media db 0xF0
SectorsPerFAT dw 0x09
SectorsPerTrack dw 0x0012
HeadsPerCylinder dw 0x0002
HiddenSectors dd 0x00000000
TotalSectorsBig dd 0x00000000
DriveNumber db 0x00
db 0x00
ExtBootSignature db 0x00
erialNumber dd 0x12345678
VolumeLabel db "BLAATAAP "
FileSystem db "FAT12 "
End_Of_BootData:
; We weten niet of we op 0000:7C00 of 07C0:0000 staan, daarom
; kiezen we er zelf een.
mov ax, 0x07C0 ; Segment 07C0
mov ds, ax ; Data staat op 07C0:0000
jmp 0x07C0:Relocation
Relocation: ; En de code nu ook
; Setup Stack
cli ; Geen interrupts
mov ax, 0x9000
mov ss,ax
mov sp, 0xFFFF
sti ; Nu mag het weer
; Onthoud de bootdrive
mov [bootdrive],dl
; Print a bootmessage
mov si, BootMsg
call PrintMsg
; Reset disk system
xor ah,ah
mov dl, [bootdrive]
int 0x13
; -------------------------------------------------------
; Lees all FAT sectoren in op 1000:0000
xor ax, ax
mov al, [NumberOfFATs]
mov cx, [SectorsPerFAT]
mul cx
mov cx, ax
mov bp, [ReservedSectors]
call ReadSectors
; -------------------------------------------------------
; Lees de root-entry in op 2000:0000
mov ax, 0x0000
mov [Cur_Off], ax
mov ax, 0x2000
mov [Cur_Seg], ax
xor dx, dx
mov ax, [RootEntries]
shl ax, 5 ; Maal 32
div word [BytesPerSector] ; ax = ax:dx / bytespersector
mov cx, ax ; Aantal sectoren
call ReadSectors ; BP already set correctly
mov [DataStartSector], bp
; -------------------------------------------------------
; Zoek naar een kernel.sys
mov bp, [RootEntries]
mov ax, 0x2000
mov es, ax
push ds
mov ds, ax
xor si, si
ShowNextEntry:
push si
push bp
xor al,al ; Niks laten zien als ie leeg is
cmp [es:si], al
je SkipEmptyEntry
cmp [es:si+0x1A], al ; Long File Name Entry
je SkipEmptyEntry
mov cx, 12 ; maximaal 11 karakters printen
call PrintMsg
mov al, 10 ; Linefeed
call PrintChar
mov al, 13 ; en carriage return
call PrintChar
SkipEmptyEntry:
pop bp
pop si
add si, 32
dec bp ; Alle entries al gehad?
jnz ShowNextEntry
pop ds
DeadLock:
jmp DeadLock
; ------------------------------------------------------------------------
; Routine die een string in DS:SI print die eindigt op een 0.
; In: CX = maximale lengte om af te drukken
PrintMsg:
cld
lodsb ; Laad uit DS:SI naar AL
cmp al,0
jz End_Of_String ; Is het een 0, dan einde
dec cx ; Maximaal aantal karakters geprint?
jz End_Of_String
call PrintChar ; Print character
jmp PrintMsg ; En volgende character
End_Of_String:
ret
; -------------------------------------------------------------------------
; Routine die een karakter in AL op het scherm print. Deze routine maakt
; gebruik van BIOS-interrupt 0x10 om een karakter te plotten.
PrintChar:
mov ah,0x0E ; BIOS functie 15
mov bx,0x000 ; Print op page 0 in kleur 7
int 0x10
ret
; -------------------------------------------------------------------------
; Routine die een of meerdere sectoren inleest
; CX = aantal sectoren
; BP = startsector (LBA)
ReadSectors:
push cx
mov di, 5
RS_Retry:
call ConvertLBA2CHS
mov dl, [bootdrive]
mov bx, [Cur_Seg] ; Data wordt in CurSeg:CurOff
mov es, bx ; geladen.
mov bx, [Cur_Off]
mov ax, 0x0201
int 0x13
jnc RS_GoodLoad
mov al, 'X' ; Niet goed? Print een X
call PrintChar
dec di ; Al 5 keer geprobeerd? Dan
jnz RS_Retry ; kappen we ermee...
mov al, '!'
call PrintChar
jmp $ ; Deadlock
RS_GoodLoad:
mov bx, [Cur_Off] ; Increase memory offset
add bx, 512
mov [Cur_Off], bx
inc bp ; Next LBA sector
pop cx
loop ReadSectors
ret
; -------------------------------------------------------------------------
; Convert LBA to CHS
; in : BP = LBA sector
; out: ch = cylinder
; dh = head
; cl = sector (high cylinder not used)
ConvertLBA2CHS:
mov ax, bp
xor dx, dx
div word [SectorsPerTrack]
inc dl ; Sectors starts at 1, not 0
mov bl, dl
xor dx, dx
div word [HeadsPerCylinder]
mov ch, al ; Cylinder
mov cl, bl ; Sectors
mov dh, dl ; Head
ret
; -------------------------------------------------------------------------
; Data die we gebruiken in de bootsector
BootMsg db 'Booting...', 0
ErrorMsg db 'Cannot find kernel.sys', 13, 10, 0
DoneMsg db 'done!',0
kernel db 'KERNEL SYS'
DataStartSector dw 0
bootdrive db 0
Cur_Seg dw 0x1000
Cur_Off dw 0x0000
times 510-($-$$) db 0x90 ; Opvullen met NOP (doet niets)
dw 0xAA55 ; En de boot terminator |
Schrijf de binary weg op een geformateerde floppy, zet er een aantal test-bestandjes en directories (bestanden IN die directories worden dus niet getoond, aangezien deze niet in de root-directory staan) en kijk hoe goed het (wel|niet) werkt..
Een leuke opdracht zou zijn om ervoor te zorgen dat ook lange bestandsnamen kunnen worden afgedrukt. Op http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/vfat.html vind je een hoop info om zelf hiermee aan de slag te gaan.
Lezen van een file vanaf schijf naar het geheugen
-------------------------------------------------
Dit is niet zo heel erg veel meer dan het lezen van de directory. Als eerste moeten we natuurlijk de rootdirectory lezen om te kijken of de file uberhaupt bestaat. Hebben we iets gevonden dat voldoet aan onze bestandsnaam (in ons geval: KERNEL.SYS), dan laden we deze file in door alle clusters van de file in te lezen. Voor info over het inlezen van clusters kun je het beste eventjes wat extra documentatie raadplegen (het stelt niet zo veel voor, het is eigenlijk een soort van linklist).
Onze "hello world" kernel
-------------------------
Als eerste gaan we even een simpele kernel bouwen. Schrik niet, want wat deze doet is niets meer dan wat text op het beeldscherm zetten op precies dezelfde manier als in de bootsector (met interrupt 10 dus). Ook zal deze kernel in assembler geschreven worden, aangezien we nog heeeeel veel moeten doen voordat we ook maar een C-kernel kunnen inladen.
Waarom kunnen we nog geen C-kernel inladen?
Dat heeft een paar redenen. De belangrijkste reden is wel dat onze compiler (gcc/djgpp) alle code in 32bit assembleerd, en wij in ons OS nog steeds in 16 bit werken. Verder heeft C de eigenschap dat veel functies (strcpy, printf, memcpy etc) specifieke functies zijn per OS, en dat deze worden opgeslagen in de C-lib. We moeten dus voordat we ook maar 1 printf'je kunnen gebruiken een compleet eigen C-library moeten schrijven. Gelukkig is dit niet zo heel moeilijk, maar het is wel een langdradig karwei (het leven van een OS-coder is niet altijd feest). Zodra we deze 2 "problemen" hebben opgelost, kunnen we beginnen met het schrijven van de eerste echte C-kernels.
Goed, de assembler-kernel dan maar voorlopig. Wat komt erin te staan?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
| [bits 16] ; 16 bits code
org 0 ; We staan op offset 0
mov ax, 0x0050
mov ds, ax
mov es, ax
mov si, msg
call PrintMsg
xor bx,bx ; BX houd de huidige kleur vast
NextLoop:
; Wacht op de monitor totdat deze klaar is met het maken
; van horizontale lijn. Dit is een soort van vertragings-lus
; die we inbouwen en hierdoor lijkt het alsof er allemaal kleine
; balkjes in de achtergrond liggen.
mov dx,0x3da
NHR:
in al,dx
test al,1
jne NHR
HR:
in al,dx
test al,1
je HR
mov dx,0x3c8 ; Achtergrond kleur veranderen
xor al,al
out dx,al
inc dx
mov al,[r]
out dx,al
mov al,[g]
out dx,al
mov al,[b]
out dx,al
add byte [r], 3
jmp NextLoop ; Dit gaan oneindig door... :)
; ------------------------------------------------------------------------
; Routine die een string in SI print die eindigt op een 0.
PrintMsg:
cld
lodsb ; Laad uit DS:SI naar AL
cmp al,0
jz End_Of_String ; Is het een 0, dan einde
call PrintChar ; Print character
jmp PrintMsg ; En volgende character
End_Of_String:
ret
; -------------------------------------------------------------------------
; Routine die een karakter in AL op het scherm print. Deze routine maakt
; gebruik van BIOS-interrupt 0x10 om een karakter te plotten.
PrintChar:
mov ah,0x0E ; BIOS functie 15
mov bx,0x0001 ; Print op page 0 in kleur 1
int 0x10
ret
; -------------------------------------------------------------------------
; Data die we gebruiken in de bootsector
msg db 13,10,13,10,"hallo! Dit is onze eerste kernel!",13,10
db 13,10
db "We doen hierin nog niet zo heel erg veel, behalve leuke",13,10
db "kleurtjes en deze text laten zien op het scherm.",13,10
db 13,10
db "Mocht je zelf nog leuke ideetjes hebben, dan mag je dat ",13,10
db "dat altijd zelf uitproberen...",13,10
db 13,10
db 0
; Rood, Groen en Blauw component
r db 0
g db 0
b db 0
; De kernel is niet gebonden aan een grootte. Zorg er alleen voor dat
; deze kernel niet boven de 64KB uitkomt ivm offset-wrapping tijdens
; het laden.
times 2345 db 0x90
db "blaat" |
Niet veel dus. Een simpel bericht op het beeldscherm en wat gepiel met kleurtjes. Als je echt teveel vrije tijd hebt, dan kan je hier vandaan een soort van bootloader in elkaar zetten: zorg dat de bootsector alle files in de root laat zien, en laat de gebruiker hieruit 1 kiezen. Mocht je dit niet halen qua code, dan kun je altijd nog een extra bootloader laden. Zorg dat je bootsector STAGE2.SYS laad, en je hebt in stage2 alle ruimte voor je loader (wat dacht je van een leuk plaatje op de achtergrond, scrollertje onderdoor etc).
ok, onze bootsector om KERNEL.SYS in te laden en uit te voeren:<blockquote><font size="1" face="verdana, arial, helvetica">code:</font><hr><font face="courier, fixedsys, lucida console"><nobr>[bits 16] ; 16 bits code
org 0 ; We staan op offset 0
jmp End_Of_BootData
OEMName db "MyOwnOS "
BytesPerSector dw 0x0200
SectorsPerCluster db 0x01
ReservedSectors dw 0x01
NumberOfFATs db 0x02
RootEntries dw 224
TotalSectors dw 2880
Media db 0xF0
SectorsPerFAT dw 0x09
SectorsPerTrack dw 0x0012
HeadsPerCylinder dw 0x0002
HiddenSectors dd 0x00000000
TotalSectorsBig dd 0x00000000
DriveNumber db 0x00
db 0x00
ExtBootSignature db 0x00
erialNumber dd 0x12345678
VolumeLabel db "BLAATAAP "
FileSystem db "FAT12 "
End_Of_BootData:
; We weten niet of we op 0000:7C00 of 07C0:0000 staan, daarom
; kiezen we er zelf een.
mov ax, 0x07C0 ; Segment 07C0
mov ds, ax ; Data staat op 07C0:0000
jmp 0x07C0:Relocation
Relocation: ; En de code nu ook
; Setup Stack
cli ; Geen interrupts
mov ax, 0x9000
mov ss,ax
mov sp, 0xFFFF
sti ; Nu mag het weer
; Onthoud de bootdrive
mov [bootdrive],dl
; Print a bootmessage
mov si, BootMsg
call PrintMsg
; Reset disk system
xor ah,ah
mov dl, [bootdrive]
int 0x13
; -------------------------------------------------------
; Lees all FAT sectoren in op 1000:0000
xor ax, ax
mov al, [NumberOfFATs]
mov cx, [SectorsPerFAT]
mul cx
mov cx, ax
mov bp, [ReservedSectors]
call ReadSectors
; -------------------------------------------------------
; Lees de root-entry in op 2000:0000
mov ax, 0x0000
mov [Cur_Off], ax
mov ax, 0x2000
mov [Cur_Seg], ax
xor dx, dx
mov ax, [RootEntries]
shl ax, 5 ; Maal 32
div word [BytesPerSector] ; ax = ax:dx / bytespersector
mov cx, ax ; Aantal sectoren
call ReadSectors ; BP already set correctly
mov [DataStartSector], bp
; -------------------------------------------------------
; Zoek naar een kernel.sys
mov bp, [RootEntries]
mov ax, 0x2000
mov es, ax
xor di, di
CheckNextEntry:
pusha
mov si, kernel ; check naar KERNEL SYS
&nb
Yo dawg, I heard you like posts so I posted below your post so you can post again.
btw: ik zal bij de volgende update je site in de faq opnemen
<edit>
gelijk maar ff gedaan
</edit>
Doet iets met Cloud (MS/IBM)
Deze zijn allemaal _zeer_ interessant
http://users.rcn.com/eaj.pizzi/asm/index.html
http://debs.future.easyspace.com/Programming/OS/bootsect.asm
http://www.nondot.org/sabre/os/files/Booting/BootSector.html
http://groups.google.com/groups?q=%22operating+system%22+group:comp.lang.asm.x86&start=100&hl=en&scoring=d&rnum=120&selm=sthe1kc59h4a7a%40corp.supernews.com
http://users.rcn.com/eaj.pizzi/pizzios/resources/index.html
Da's leuk, maar euh.. site wil ik het niet noemen. Het zijn alleen maar wat filetjes en no way dat ik hiervoor een site ga opzettenOp dinsdag 30 april 2002 22:07 schreef D2k het volgende:
JayTaph +1 behulpzaam
btw: ik zal bij de volgende update je site in de faq opnemen
<edit>
gelijk maar ff gedaanje staat erin
</edit>
Yo dawg, I heard you like posts so I posted below your post so you can post again.
ach je staat erinOp woensdag 01 mei 2002 09:24 schreef JayTaph het volgende:
[..]
Da's leuk, maar euh.. site wil ik het niet noemen. Het zijn alleen maar wat filetjes en no way dat ik hiervoor een site ga opzetten
Doet iets met Cloud (MS/IBM)
Dat wordt dus ook voor mij overnieuw beginnen
*help*
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Verwijderd
Even apeldoorn bellenOp woensdag 01 mei 2002 20:26 schreef JayTaph het volgende:
Fsck, I seemed to have misplaced my old OS(lees: ergens diep ver weg op een cdrommetje die waarschijnlijk niet meer leesbaar is door vuil en krassen)..
Dat wordt dus ook voor mij overnieuw beginnen
*help*
Ware het niet dat ik ook niet weet op *welke* cd het eventueel op kan staan (lange leve de eddingOp woensdag 01 mei 2002 20:37 schreef Grum het volgende:
Vuil & krassen zijn altijd wel weg te polijsten mits ze aan de 'data' kant zitten
Ach misschien kom ik em nog tegen... Maar ik denk dat ik weer aan de slag ga aan een eigen stdlib ofzo..
printf, here i come..
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Verwijderd
---------------------------------------
Moeilijkheidsgraad: moeilijk
Voorkennis: i386 assembly, protected mode
Referenties: Ralfs Brown Interrupt List, Intel x86 Docs
Tools: nasm
Note: ik ga *NIETS* uitleggen over protected mode. Niet alleen omdat dat veel werk is, maar ook omdat ik een redelijke kennis verwacht van de mensen die een OS willen bouwen. Het kan zijn dat je wat dingen mist, of dingen gewoon niet snapt (dat mag), en daarvoor staat vragen vrij. Maar termen zoals selectors, descriptors, granularity en de verschillen tussen logical, physical en virtual memory moeten duidelijk zijn (en is dat niet helemaal, dan mag je vast wel een of twee topics openen van de modjes alhier
Op dit moment hebben we een bootsector die een (willekeurige) file van een ms-dos schijfje leest. Alles in real mode natuurlijk, omdat een (intel) processor automatisch opstart in real mode, dus we hoeven hiervoor niets speciaals te doen, en bijkomend voordeel: we kunnen de BIOS functies gebruiken om van schijf te lezen, en op het beeld te schrijven.
Kan protected mode dat dan niet (leem hoor)? Jawel, alleen moeten wij daar zelf zorg voor dragen want de BIOS van een systeem (althans, de functies die wij gebruiken) is 16bit realmode code is en niet direct aanspreekbaar is vanuit protected mode.
What's next?
Nu moeten we overschakelen naar protected mode, zodat we onze 32bits kernel straks kunnen starten. Om over te schakelen hebben we nog een stukje assembler nodig, de zogenaamde head of trampoline-functies. Dit stukje code wordt (in dit voorbeeld) niet geplaatst in de boot-sector, aangezien daar geen plek meer vrij voor is, maar staat vooraan in de kernel.sys die we met de bootsector inladen.
De kernel.sys file bestaat dus uit 2 afzonderlijke delen die we aan elkaar plakken: de head en de echte kernel. Deze 2 file's assembleer/compile ik afzonderlijke van elkaar, en plak ze stomweg aan elkaar zodat 1 grote kernel.sys ontstaat.
(deze code vereist dat je de boot4.asm file gebruikt als bootsector, daar zijn ook meteen een paar lompe fouten mbt het inladen van clusters verholpen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
| ; This piece of code is the start of the kernel. It is a bit of ASM which sets
; up the whole system so the second part of the kernel (the C-bit), can start
; without problems. It's almost the same method used as in the linux kernel
; (head.s)
[bits 16]
org 0
mov ax, KERNEL_OFF ; Kernel starts at 0050:0000
shr ax, 4
mov ds, ax
mov es, ax
mov gs, ax
call DetectCPU
call EnableA20
; From here, we can use 386 code safely...
; Set up GDT
xor eax, eax ; Calculate address of the GDT on the fly
mov ax, ds
shl eax, 4
add [GDT+2], eax
cli ; Load the GDT
lgdt [GDT]
mov eax, cr0 ; Set PE bit in control register
or al, 1
mov cr0, eax
jmp ClearPreFetchQueue ; Jump to the next instruction
ClearPreFetchQueue: ; This flushes current realmode stuff
; Jump to the protected mode stuff
jmp 0x08:ProtectedMode+KERNEL_OFF
;----------------------------------------------------------
EnableA20:
cli
xor cx, cx
.loop1:
in al, 0x64 ; Get input from keyboard status port
test al, 0x02 ; Test buffer full flag
loopnz .loop1
mov al, 0xd1 ; Write to output port
out 0x64, al
.loop2: ; Wait until buffer is empty again
in al, 0x64
test al, 0x02
loopnz .loop2
mov al, 0xdf ; Set A20
out 0x60, al
mov cx, 0x14 ; This is approx a 25uS delay
.loop3: ; that is needed to let the
out 0xed, ax ; kb controller execute our A20
loop .loop3 ; command...
ret
;----------------------------------------------------------
; Detect CPU
DetectCPU:
; Check 8086
pushf ; save flags
xor ah, ah ; Make high part of flags zero
push ax
popf
pushf ; Check if the high bits are set
pop ax
cmp ah, 0xf0
je Noi386Found
; Check 80286
mov ah, 0xf0 ; Set the high bits of the flag
push ax
popf
pushf ; Are they cleared?
pop ax
and ah, 0xf0
jz Noi386Found
popf
i386Found:
ret
Noi386Found:
mov si, msg_no386
call WriteMsg
jmp $
; ------------------------------------------------
; write msg from ds:si on screen
WriteMsg:
lodsb
or al, al
jz Done
mov ah, 0x0e
mov bx, 0x0007
int 0x10
jmp WriteMsg
Done:
ret
; ------------------------------------------------
msg_no386 db "Error: 386 or better not found.", 13, 10, 0
GDT dw GDT_SIZE ; Some people place this structure
dd GDT_START ; inside the NULL descriptor, I don't...
GDT_START:
; Can't be used, (0x00)
null_desc dw 0x0000 ; Limit Low
dw 0x0000 ; Base Low
db 0x00 ; Base Mid + Accessed
db 0x00 ; Flagg stuff
db 0x00 ; More flag + Limit High
db 0x00 ; Base High
; 4gb flat code descriptor (0x08)
code4gb_desc dw 0x0000 ; Limit Low
dw 0x0000 ; Base Low
db 0x00 ; Base Mid + Accessed
db 0x9A ; Flagg stuff
db 0xCF ; More flag + Limit High
db 0x00 ; Base High
; 4gb flat data descriptor (0x10)
data4gb_desc dw 0x0000 ; Limit Low
dw 0x0000 ; Base Low
db 0x00 ; Base Mid + Accessed
db 0x93 ; Flagg stuff
db 0xCF ; More flag + Limit High
db 0x00 ; Base High
; 4kb vga (0xb8000) descriptor (0x18)
vga_desc dw 0x1000 ; Limit Low
dw 0x8000 ; Base Low
db 0x0B ; Base Mid + Accessed
db 0x93 ; Flagg stuff
db 0x8F ; More flag + Limit High
db 0x00 ; Base High
GDT_SIZE EQU $-GDT_START
; ---------------------------------------------------------
; FROM HERE ON: EVERYTHING IS IN PROTECTED MODE
; ---------------------------------------------------------
[bits 32]
ProtectedMode:
mov ax, 0x10 ; Load 4GB data selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
call headsize+KERNEL_ENTRY_POINT
; -------------------------------------------------
KERNEL_OFF EQU 0x500
KERNEL_ENTRY_POINT EQU 0x000000
headsize dw $ |
Wat doet ie?
Als eerste weten we dat we op plaats 0x500 staan, da's namelijk waar de bootsector kernel.sys inlaad. We zetten dus eerst onze segmenten goed zodat we niet in de knoei komen met data. (de stack blijft wel nog op 0x9000:0xFFFF staan btw).
Hierna gaan we checken of we een 386 of hoger hebben. Dat is nodig omdat we anders helemaal niet eens naar protected mode kunnen schakelen (286 uitgezonderd, maar da's hell-on-earth). Nadat we een 386 hebben gevonden zetten we de A20 lijn op, zodat we onze complete geheugen fatsoenlijk kunnen aanspreken (lang leve de backwards compatibilty).
Btw, als je een os gaat bouwen die ECHT compatible wil zijn, kan ik je melden dan een OS zoals microsoft al 17 verschilende methodes heeft om de A20 lijn op te zetten, omdat dit soort dingen per computer NET een tikkie anders zijn. Wees dus niet te snel met roepen dat je OS compatible is omdat ie AL op 2 systemen vlekkeloos draait
Goed, na de A20 lijn mag je eindelijk echte 386 code gaan gebruiken, en kunnen we ook de eax'jes, de movzx'jes en de lgdt'jes aanroepen. (probeer de bootsector zo 8086-compatible mogelijk te houden: een gebruiker ziet liever een melding op het scherm dat het OS niet kan draaien, dan dat het complete systeem hangt, omdat je toevallig een ongeldige instructie aanroept).
Wat we gaan doen, is de eerste GDT initaliseren. Deze GDT bestaat uit 4 descriptors:
* de null-descriptor (deze kan je niet aanspreken, maar moet wel aanwezig zijn).
* de 4gb code descriptor (deze descriptor laat je code runnen in het complete geheugenbereik).
* de 4gb data descriptor (deze descriptor laat je data lezen/schrijven in het complete geheugenbereik).
* de vga-descriptor (deze descriptor laat je data lezen/schrijven puur en alleen op het VGA-scherm).
Voor mensen met een ega-schermpje moeten ipv 0x8000 bij de vga-descriptor gewoon 0x0000 invullen. Zodoende wordt dit geheugen gemapped van 0xB8000 naar 0xB0000: het ega-video bereik.
Nadat de GDT geinitialiseerd is, kunnen we springen naar protected mode toe: eerst de PG-bit setten, en daarna een jump doen zodat de hele fetch-queue leeg word gezogen van de real-mode instructies (je hebt toch wel je intel-docs gelezen?
Hierna moeten we naar onze 32bits code springen, en dat doen we door te jumpen naar onze 4gb-code selector (da's 0x8) en als offset onze protected mode code.
Eindelijk in 386 code dus, waarna we de rest van onze segmenten (die nu selectoren heten) goed gaan zetten naar de 4gb data-descriptor (0x10). Dit is ook inclusief de stack, niet echt een ideale situatie, maar goed genoeg voor nu.
Nu zijn we klaar met alle initialisatie die plaats moest vinden voordat we naar de echte kernel kunnen gaan. Tijd om daar naartoe te springen.
Zoals je al weet, hebben we de C-kernel achter de head geplakt. Dus het begin van de kernel begint aan het einde van de head. Deze waarde zoeken we niet zelf uit, maar laten we de assembler zelf uitrekeken (zie de laatste regel in head.s). De C-kernel zelf kunnen we starten door gewoon vanaf de eerste byte te beginnen (waarom dit goed gaat hoor je hierna).
Als er nog geinteresseerden zijn: ik maak hierna nog eventjes een soort van mini-kernel die wat print op het beeldscherm in C, en daarna misschien wat globale info over wat een OS verder allemaal inhoud? (zoals memory managment, io, scheduling etc?)
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Verwijderd
Ik snap momenteel slechts de helft (d.w.z., ik snap het globale idee wel - maar ik ken nog steeds te weinig assembler om de code exact te snappen), maar als jij een kernel zover kunt krijgen om C code te kunnen executen, dan zou dat ongelofelijk gaaf zijn!Op donderdag 16 mei 2002 23:10 schreef JayTaph het volgende:
Als er nog geinteresseerden zijn: ik maak hierna nog eventjes een soort van mini-kernel die wat print op het beeldscherm in C, en daarna misschien wat globale info over wat een OS verder allemaal inhoud? (zoals memory managment, io, scheduling etc?)
--------------
Moeilijkheidsgraad: makkelijk
Voorkennis: at&t style assembler + C
Referenties: Intel x86 Docs, gas docs, at&t assembly tutorials
Tools: gcc / djgpp
Nu is het OS aangekomen bij het uitvoeren van de C-kernel. Zoals je al gelezen had, laten we de kernel beginnen vanaf het begin van de file.
Waarom is dit nu zo moeilijk?
Een "normaal" C-programma wordt meestal gecompileerd geassembleerd en gelinkt naar een bepaald formaal (EXE, ELF etc). Deze formaten gaan er van uit dat ze op een bepaalde offset geladen (COM -filetjes starten op offset 0x100) etc. Zodra het programma is geladen, wordt er een stub uitgevoerd die normaal gesproken door de linker automatisch wordt meegelinkt aan je programma. Deze file heet meestal crt0. In deze file worden allemaal platform/OS technische dingen geregeld en uiteindelijk word de functie _main aangeroepen (dezelfde main() die je in je eigen C-programma schrijft).
Onze kernel wordt gewoon plain binary-formaat zodat er geen stubs aangehangen worden. Tijdens het linken van je kernel, zorg je er voor dat als eerste een aparte object word gelinkt: entry.o. In dit object staat maar 1 functie genaamd _start, die weer op zijn beurt kernel_entry() aanroept.
Als je dit niet op deze manier doet, dan weet je nevernooitniet op welke plek de linker de kernel_entry() functie neerzet, en kun je steeds je head.S blijven aanpassen. Nu weten we zeker dat offset 0 een functie bevat die dat allemaal voor ons kan regelen (de ideale situatie zou zijn om head.S te linken met de rest van de kernel. Op die manier kun je wel heel makkelijk uitvinden waar kernel_entry() zich bevind.
1
2
3
4
5
| void kernel_entry (void); // External reference to the real kernel entrypoint
void _start (void) { // Very heftige stub Copyright (C) 2002 JayTaph
kernel_entry ();
} |
Nu de werkelijke kernel. Omdat we nog eigen stdlib hebben, kunnen we nog geen gebruik maken van dingen zoals memcpy, strcpy, printf en consorten. Deze functies moeten we straks allemaal zelf gaan bouwen. Nu doen we gewoon simpel stringetjes afdrukken dmv vga_putchar().a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| char data[] = "blaaaat"; // Zomaar wat data..
#define DESC_4GB_CODE 0x08
#define DESC_4GB_DATA 0x10
#define DESC_VGA 0x18
/*
* Causes the system to "hang". Works for the time beeing..
*/
void deadlock (void) {
for (;;) ;
}
/*
* Plots a character onto the screen.
*/
void vga_put (int x, int y, char attr, char c) {
short int value = attr * 256 + c;
int offset = (y*160)+(x*2);
__asm__ ("
pushw %%es
movw %%bx, %%es
movw %%ax, %%es:(%%edi)
popw %%es"
:
: "D" (offset), "b" (DESC_VGA), "a" (value)
);
}
/*
* Kernel entrypoint, our "void main(void)".
*/
void kernel_entry () {
int i;
for (i=0; i!=26; i++) vga_put (i, 10, 16+i, 'A'+i);
for (i=0; testtekst[i]; i++) vga_put (i, 11, 31, testtekst[i]);
for (i=26; i!=0; i--) vga_put (i, 12, 16+i, 'A'+i);
deadlock ();
}
char testtekst[] = "Deze tekst zetten we zodadelijk op het scherm neer.. :)"; |
deze functie werkt op de volgende manier:
We krijgen mee: x en y coordiaat van de plek waarop we willen plotten, de attribuut (achtergrond*16+voorgrond), en het karakter. De functie rekent uit de offset uit en zorgt ervoor dat de attribuut+karakter worden samengevoegd.
Hierna krijgen we een stukje assembler dat het gaat plotten naar het vga-descriptor (in AT&T style). De rest van de functies zijn te basic om uit te leggen
Nou, de eerste echte kernel is klaar
Binnenkort zal ik wel een simpel printf() routine schrijven, zodat je een beetje kunt klootvioolen (of misschien dat iemand anders die wil schrijven???)
Yo dawg, I heard you like posts so I posted below your post so you can post again.
Ik hoop niet dat ik dit topic al te veel omhoog schop, maar ik was opzoek naar info over C kernels, en ik liep tegen jouw topic aan. Ik had al een bootloader geschreven met FAT12, maar nu wil ik een C kernel gaan gebruiken (ASM werkt perfect, maar ik wil een C kernelOp maandag 20 mei 2002 21:50 schreef JayTaph het volgende:
De Kernel in C
--------------
Moeilijkheidsgraad: makkelijk
Voorkennis: at&t style assembler + C
Referenties: Intel x86 Docs, gas docs, at&t assembly tutorials
Tools: gcc / djgpp
Nu is het OS aangekomen bij het uitvoeren van de C-kernel. Zoals je al gelezen had, laten we de kernel beginnen vanaf het begin van de file.
Waarom is dit nu zo moeilijk?
Een "normaal" C-programma wordt meestal gecompileerd geassembleerd en gelinkt naar een bepaald formaal (EXE, ELF etc). Deze formaten gaan er van uit dat ze op een bepaalde offset geladen (COM -filetjes starten op offset 0x100) etc. Zodra het programma is geladen, wordt er een stub uitgevoerd die normaal gesproken door de linker automatisch wordt meegelinkt aan je programma. Deze file heet meestal crt0. In deze file worden allemaal platform/OS technische dingen geregeld en uiteindelijk word de functie _main aangeroepen (dezelfde main() die je in je eigen C-programma schrijft).
Onze kernel wordt gewoon plain binary-formaat zodat er geen stubs aangehangen worden. Tijdens het linken van je kernel, zorg je er voor dat als eerste een aparte object word gelinkt: entry.o. In dit object staat maar 1 functie genaamd _start, die weer op zijn beurt kernel_entry() aanroept.
Als je dit niet op deze manier doet, dan weet je nevernooitniet op welke plek de linker de kernel_entry() functie neerzet, en kun je steeds je head.S blijven aanpassen. Nu weten we zeker dat offset 0 een functie bevat die dat allemaal voor ons kan regelen (de ideale situatie zou zijn om head.S te linken met de rest van de kernel. Op die manier kun je wel heel makkelijk uitvinden waar kernel_entry() zich bevind.
code:
1 2 3 4 5void kernel_entry (void); // External reference to the real kernel entrypoint void _start (void) { // Very heftige stub Copyright (C) 2002 JayTaph kernel_entry (); }
Nu de werkelijke kernel. Omdat we nog eigen stdlib hebben, kunnen we nog geen gebruik maken van dingen zoals memcpy, strcpy, printf en consorten. Deze functies moeten we straks allemaal zelf gaan bouwen. Nu doen we gewoon simpel stringetjes afdrukken dmv vga_putchar().a
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43char data[] = "blaaaat"; // Zomaar wat data.. #define DESC_4GB_CODE 0x08 #define DESC_4GB_DATA 0x10 #define DESC_VGA 0x18 /* * Causes the system to "hang". Works for the time beeing.. */ void deadlock (void) { for (;;) ; } /* * Plots a character onto the screen. */ void vga_put (int x, int y, char attr, char c) { short int value = attr * 256 + c; int offset = (y*160)+(x*2); __asm__ (" pushw %%es movw %%bx, %%es movw %%ax, %%es:(%%edi) popw %%es" : : "D" (offset), "b" (DESC_VGA), "a" (value) ); } /* * Kernel entrypoint, our "void main(void)". */ void kernel_entry () { int i; for (i=0; i!=26; i++) vga_put (i, 10, 16+i, 'A'+i); for (i=0; testtekst[i]; i++) vga_put (i, 11, 31, testtekst[i]); for (i=26; i!=0; i--) vga_put (i, 12, 16+i, 'A'+i); deadlock (); } char testtekst[] = "Deze tekst zetten we zodadelijk op het scherm neer.. :)";
deze functie werkt op de volgende manier:
We krijgen mee: x en y coordiaat van de plek waarop we willen plotten, de attribuut (achtergrond*16+voorgrond), en het karakter. De functie rekent uit de offset uit en zorgt ervoor dat de attribuut+karakter worden samengevoegd.
Hierna krijgen we een stukje assembler dat het gaat plotten naar het vga-descriptor (in AT&T style). De rest van de functies zijn te basic om uit te leggen
Nou, de eerste echte kernel is klaar. Eigenlijk moet je nog een fatsoenlijke stack definieeren, nieuwe kernel descriptors maken die zorgt dat de kernel per definitie niet buiten zichzelf kan lezen/schrijven/uitvoeren.
Binnenkort zal ik wel een simpel printf() routine schrijven, zodat je een beetje kunt klootvioolen (of misschien dat iemand anders die wil schrijven???)
Om te testen pak ik jouw code en compileer het vervolgens zo:
1
2
3
| gcc -ffreestanding -o kernel1.o kernel1.c gcc -ffreestanding -o kernel2.o kernel2.c ld -Ttext 0x100000 --oformat binary -o kernel.bin kernel1.o kernel2.o |
Vervolgens mik ik de kernel.bin op mijn floppy, druk hem in mijn 386 en zie: Kernel aan het starten tiktiktik. Klaar, en hij hangt. Er gebeurt dus helemaal niks.
Als ik een C kernel maak met daarin:
1
2
3
| void main(void) {
} |
dan gaat ie lekker de bootloader weer opnieuw starten zoals het hoort. Ik gok dat het in mijn compile/linken zit, maar dit probleem heb ik dus met alle tutorials die ik gebruik.
Ik gebruik overigens Linux om te compilen.
Blog | aaZoo - (Wireless) Networking, Security, DDoS Mitigatie, Virtualisatie en Storage