YeXo - een kernel programmeren

31 maart 2006

Een kernel debuggen met bochs

Een kernel debuggen is erg lastig. Op een 'echte' computer is het zo goed als onmogelijk omdat als er iest fout gaat in je kernel (een kernel panic), er niets meer is dat betrouwbaar werkt. De enige manier om dit op te lossen is bochs gebruiken met de ingebouwde debugger. Zie hiervoor ook de debugging handleiding van bochs (engels). Hierna zal ik kort samenvatten hoe je de interne debugger van bochs kunt gebruiken om fouten in je kernel te traceren.

Om te beginnen start je niet bochs.exe maar bochsdbg.exe. Je virtuele computer begint nu niet met opstarten maar geeft in plaats daarvan een commandline prompt. Je hebt hier een aantal opdrachten tot je beschikking. De belangrijkste zijn de volgende, voor een uitgebreide lijst zie de debugging handleiding van bochs.

c(ontinue)
Ga verder met uitvoeren
s(tep) i
Voer i stappen uit, standaardwaarde voor i is 1.
Ctrl-C
Stop met uitvoeren en geef opnieuw een commandline prompt. Ctrl-C is handig als je je kernel tijdens een bepaalde actie wilt stoppen om daarna stap voor stap verder te gaan.
q(uit)
Stop met uitvoeren en sluit debugger af
vbreak segment:offset
Stel een breakpoint in op het virtuele adres segment:offset.
info break
Geef informatie over alle breakpoints.
info regs
Print een lijst van alle CPU registers en hun inhoud.

28 maart 2006

Hoeveel geheugen heeft de computer?

Het is noodzakelijk voor de kernel om te weten hoeveel RAM de computer eigenlijk heeft. Er zijn verschillende manieren om dit te bepalen: je kunt de hoeveelheid geheugen uitlezen uit het cmos. Het nadeel hiervan is echter dat de hoogste waarde die je kunt uitlezen 99mb is. Dus op een computer met 100mb RAM of meer heb je een probleem. Een tweede manier is om via bios aanroepen een overzicht van het geheugen te verkrijgen. Dit is de meestgebruikte en hieronder besproken manier. Omdat dit via interrupt moet kan dit dus alleen maar in de boatloader. Gelukkig doet grub dit al een geeft hij het resultaat door aan de geladen kernel. Een laatste manier om de hoeveelheid geheugen te bepalen is het gewoon uitproberen van het geheugen. Dit is echter lastig en wordt afgeraden omdat het vaak fout gaat.

Een overzicht van het geheugen via grub.

Zoals je waarschijnlijk weet, levert grub een structure met daarin allerlei informatie aan de kernel. Het adres van deze gegevens staat in ebx op het moment dat de kernel geladen is. Zie voor meer informatie hierover ook de multiboot standaard.

Tenslotte volgt hier nog een functie waarmee je de memory map die grub doorgeeft kunt afdrukken op het scherm. De enige fucnties die je hiervoor verder nodig hebt zijn void kprintf(char *str) en void kprinthex(unsigned long). Als je een fatsoenlijke printf functie gemaakt hebt is de code makkelijk om te zetten om die te gebruiken. unsigned long numUsablePages;

void installPaging(memory_map_t *memMap,unsigned long memMapLength){
kprintf("Kernel end address: ");
kprinthex((unsigned long)(&end));
kprintf("\nSize of memory map = ");
kprinthex(memMapLength);
kprintf("\n");

numUsablePages = 0;

memory_map_t* curMap = memMap;
while( ((unsigned long)curMap) < (((unsigned long)memMap)+memMapLength) ){
kprintf("Size=");
kprinthex(curMap->size);
kprintf(" start address=");
kprinthex(curMap->base_addr_low);
kprintf(" length=");
kprinthex(curMap->length_low);
kprintf(" type=");
kprinthex(curMap->type);
kprintf("\n");

if( curMap->type == 1 ){
numUsablePages += ((curMap->base_addr_low+curMap->length_low)>>12) - ((curMap->base_addr_low+4095)>>12);
}
curMap = (memory_map_t*) ( ((unsigned long)curMap) + curMap->size + 4 );
}
kprintf("Number of usable pages = ");
kprinthex(numUsablePages);
kprintf("\n");
}

25 maart 2006

De print functie voor de kernel

Nu de voorbereidingen voor de print functie zijn gebeurd (zie "Voorbereiding voor en print functie") kunnen we echt beginnen. De functie void kprintf(char *str) is eigenlijk heel eenvoudig. Het enige wat die hoeft te doen is de string doorlopen en elk teken doorgeven aan de functie putch die het eigenlijke werk doet. Let erop dat deze kprintf nog geen extra argumenten accepteert, dingen zoals kprintf("een getal: %d",getalVar); zijn dus niet mogelijk.


//Eerste een paar globale variabelen, het doel lijkt me duidelijk
char attribute;
unsigned short *videoMem;
unsigned int cursorX,cursorY;
unsigned int lines, columns;

/*Het attribuut bevat de voor- en achtergrondkleur van de tekst.
Dit is opgebouwd met behulp van de definities in scrn.h
Het is een heel simpele functie geimplementeerd als definitie waardoor
het een soort inline functie wordt.*/
#define setAttribute(a); attribute=a;

/* putch(char) print een teken op het scherm op de positie die door cursorX en cursorY aangegeven wordt.
Op dit moment worden nog maar een paar speciale tekens ondersteunt, namelijk: 0x08 (backspace), 0x09 (tab)
en '\n' (nieuwe regel).
*/
void putch(char c){
switch(c){
case 0x08: //backspace
if( cursorX==0 && cursorY > 0){
*(videoMem+cursorY*columns-1) = ' '|(attribute<<8);
cursorX = columns-1;
cursorY--;
}
if( cursorX > 0 ){
*(videoMem+cursorY*columns+cursorX-1) = ' '|(attribute<<8);
cursorX--;
}
break;
case 0x09: // tab: Vermeerder cursorX tot het volgende punt dat deelbaar is door 8
cursorX = (cursorX + 8) & ~(8-1);
if( cursorX == columns ){
cursorX = 0;
cursorY++;
}
break;
case '\n': // We doen alsof hier \n\r staat, net zoals dos en het bios
cursorX = 0;
cursorY++;
break;
}
if( c >= ' ' ){ // We kunnen deze char printen op het scherm.
*(videoMem+cursorY*columns+cursorX) = c|(attribute<<8);
cursorX++;
if( cursorX >= columns ){
cursorX = 0;
cursorY++;
}
}
// Als cursorY naar de regel wijst die net niet meer op het scherm pas, schuif dan het hele scherm
// een regel omhoog.
if( cursorY == lines ){
scroll();
}
// Zorg dat de cursor (het knipperende streepje) op de goede positie komt
setHardwareCursor();
}

// setHardwareCursor zorgt ervoor dat de cursor (het knipperende streepje) op de goede positie komt
void setHardwareCursor(){
unsigned short cursorPosition = (cursorY*columns) + cursorX;
outportb(0x3D4, 14);
outportb(0x3D5, cursorPosition >> 8);
outportb(0x3D4, 15);
outportb(0x3D5, cursorPosition & 0xFF);
}

/*De functie scroll schuift het hele scherm omhoog.*/
void scroll(){
memcpy(videoMem,videoMem+columns,lines*columns*2);
memsetw(videoMem+(lines-1)*columns,' '|(attribute<<8),columns);
cursorY--;
}

/*Print eens string.*/
void kprintf(char *text){
char *tp = text;
while( *tp != '\0' ){
//TODO: check for %
putch(*tp);
*tp++;
}
}

/*Leeg het hele scherm door het scherm vol te printen met spaties.*/
void clearScreen(){
memsetw(videoMem,' '|(attribute<<8),lines*columns);
cursorX = 0;
cursorY = 0;
}


void videoInit(){
int i = 0;
videoMem = (unsigned short *)0xC00B8000;
setAttribute(KLEUR(ZWART,LICHTGRIJS));
clearScreen();
cursorY = 0;
cursorX = 0;
lines = 25; //standaard schermmodus: 25x80
columns = 80;
}
24 maart 2006

Voorbereiding voor een print fucntie.

Nu we een kernel hebben draaien op virtueel adres 3gb en we een gdt hebben gemaakt, doen we de voorbereidingen om de eerste zinnen op het scherm printen. Iets op het scherm zetten is eigenlijk heel gemakkelijk: je schrijft het teken plus het attribuut (achtergrond en voorgrondkleur) naar de juiste plaats in het geheugen. Het videogeheugen bevindt zich op adres 0xB8000. Als je je kernel op 3gb geladen hebt, moet je dus naar adres 0xC00B8000 schrijven ipv van naar adres 0xB8000.


Het attribuut bestaat uit vier bits voor de achtergrondkleur en vier bits voor de voorgrondkleur. De volgende 16 kleuren zijn mogelijk voor de voorgrond- en achtergrondkleur.

















KleurWaarde (hex.)
ZWART0
BLAUW1
GROEN2
BLAUWGROEN3
ROOD4
ROZE5
BRUIN6
LICHTGRIJS7
DONKERGRIJS8
LICHTBLAUW9
LICHTGROEN10
LICHTBLAUWGROEN11
LICHTROOD12
LICHTROZE13
LICHTBRUIN14
WIT15


Om het later makkelijker te maken om kleuren te wijzigen maken we voor elke kleur een "#define kleurnaam waarde". Daarna maken we een macro aan waarmee we makkelijk het attribuut kunnen verkrijgen. Deze gaat als volgt: /* Gebruik is als volgt: KLEUR(achtergrond, voorgrondkleur)*/
#define KLEUR(a,b) (char)( ((a&0x0F)<<4) | (b&0x0F) )

20 maart 2006

Een gdt (global descriptor table) maken

Wat is een gdt?


Een gdt is een speciale tabel. In die tabel staan gegevens zoals die minimale en maximale waardes van de segment registers. Naast de gdt bestaat er ook nog een ldt, een local descriptor table, maar die is sinds de 386 bestaat verouderd. Ik vertel hierna eerst wat de opbouw is van de gdt en daarna geef ik voorbeeldcode die een gdt maakt en laad.


De opbouw van een gdt


Een gdt is een array van gdt elementen. Een gdt element ziet er als volgt uit:
struct gdt_entry
{
unsigned short limit_low;
unsigned short base_low;
unsigned char base_middle;
unsigned char access;
unsigned char granularity;
unsigned char base_high;
} __attribute__((packed));
De verschillende avariabelen base_* vormen samen de basis (de minimale waarde) van dit gdt element. De limit_* variabelen vormen de limiet (de maximale waarde). De access en granularity velden zijn als volgt opgebouwd:
Het acces veld:


765430
PDPLDTType
P - Is dit element aanwezig? (1 = ja)
DPL - Voor welke ring is dit gdt element? (0 tot 3) 0 is voor de kernel en 3 voor gebruikers-processen.
DT - Geen idee waar dit voor is.
Type - Welk type is dit element?

Het granularity veld:
765430
GD0ASeg Len. 19:16
G - Granularity (0 = 1byte, 1 = 4kbyte)
D - Grootte van dit element, meestal 32 bit(0 = 16bit, 1 = 32-bit)
0 - Deze bit is altijd 0
A - Deze bit is beschikbaar voor de processor, altijd op 0 instellen.


Voorbeeldcode


In dit voorbeeld gebruik ik drie bestanden, namelijk gdt.h, gdt.c en gdtasm.asm. gdt.h kan worden geinclude in het bestand waarin je main functie staat.
gdt.h

#ifndef __GDT_H_
#define __GDT_H_

/* Van het type gdt_entry maken we in gdt.c een array die de gdt voorstelt. Merk op hoe onlogisch
dit struct in elkaar zit. Helaas kan dit niet anders. */
struct gdt_entry
{
unsigned short limit_low;
unsigned short base_low;
unsigned char base_middle;
unsigned char access;
unsigned char granularity;
unsigned char base_high;
} __attribute__((packed));

/* Dit is een speciale 48 bits pointer naar de gdt. Deze hebben we nodig in gdtasm.asm om de processor
de gdt te laten vinden. */
struct gdt_ptr
{
unsigned short limit;
unsigned int base;
} __attribute__((packed));

/* Het aantal elementen in de gdt. */
#define NUM_GET_ENTRIES 3

/*gdtInstall wordt aangeroepen vanuit kmain. Beide functies staan in gdt.c */
extern void gdtInstall();
extern void gdtSetGate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char granularity);

/* Deze functie staat in gdtasm.asm*/
extern void flushgdt();

#endif //__GDT_H_

gdt.c

#include
#include

/* De gdt en een speciale 48 bits pointer ernaartoe. */
struct gdt_entry gdt[NUM_GET_ENTRIES];
struct gdt_ptr gdtPointer;

/*
gdtSetGate stelt het numde element van de gdt array in. basis staat voor de basis van het segment, meestal 0.
De hoogste waarde die een adres in het segment kan aannemen is basis + (limiet*granularity).
*/
void gdtSetGate(int num, unsigned long basis, unsigned long limiet, unsigned char access, unsigned char gran)
{
/* Stel het basis adres van dit element in. We moeten zo moeiljk doen omdat een gdt_entry onlogisch
opgebouwd is. Zie hiervoor gdt.h*/
gdt[num].base_low = (basis & 0xFFFF);
gdt[num].base_middle = (basis >> 16) & 0xFF;
gdt[num].base_high = (basis >> 24) & 0xFF;

/* Stel de limiet in van dit element. */
gdt[num].limit_low = (limiet & 0xFFFF);
gdt[num].granularity = ((limiet >> 16) & 0x0F);

/* Stel ook de access en granularity velden goed in.*/
gdt[num].granularity |= (gran & 0xF0);
gdt[num].access = access;
}

/* gdtInstall is eigenlijk de belangrijkste functie uit dit bestand. gdtInstall wordt door kmain aangeroepen
om ervoor te zorgen dat de gdt goed wordt geinstalleerd. */
void gdtInstall()
{
/* Eerst stellen we de gdtPointer goed in. gdtPointer.limit moet de lengte krijgen van de gdt - 1
en gdtPointer.base moet het adres krijgen van het eerste element. */
gdtPointer.limit = (sizeof(struct gdt_entry) * NUM_GET_ENTRIES) - 1;
gdtPointer.base = &gdt;

/* Het eerste element van een gdt moet altijd volledig uit nullen bestaan. Vraag niet waarom, intel
heeft verzonnen dat het zo moet. */
gdtSetGate(0, 0, 0, 0, 0);

/* Het tweede element van de gdt wordt het code segment. Het basis adres is 0 en de
limiet is 4gb/4kb=0xFFFFF (zie gdtSetGate) */
gdtSetGate(1, 0, 0xFFFFF, 0x9A, 0xC0);

/* Het derde element is het date segment. Deze is precies hetzelfde als het code segment behalve
het type (onderdeel van het access veld). */
gdtSetGate(2, 0, 0xFFFFF, 0x92, 0xC0);

/* De functie flushgdt staat in gdtasm.asm en roepen we aan om de processor te laten weten
dat we een nieuwe gdt hebben. */
flushgdt();
}


gdtasm.asm

[BITS 32]
[SECTION .text]

; Deze functie stelt de segment registers in op de nieuwe waardes
; De data segment registers kunnen we vanuit ax laden maar voor cs
; is een andere aanpak nodig. Om cs opnieuw in te stellen moeten we
; een ljmp doen naar 0x08:adres
; Deze functie is gedefinieerd in C als 'extern void flushgdt();'
global _flushgdt ; Dit zorgt ervoor dat C code deze functie kan aanroepen
extern _gdtPointer ; _gdtPointer staat in een ander bestand, namelijk gdt.c
_flushgdt:
lgdt [_gdtPointer] ; Laad de gdt met onze speciale gdtPointer.
mov ax, 0x10 ; 0x10 is het data segment in de gdt
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:gdtflush ; 0x08 is het code segment in de gdt. Let op dat we een far jump doen
gdtflush:
ret ; Weer terug naar de aanroepende C code.

15 maart 2006

Een kernel laden op 3gb in het virtueel geheugen

Na lang zoeken met google en eindeloos uitproberen is het me eindelijk gelukt om mijn kernel op virtueel adres 3gb te laden. De voordelen hiervan zijn duidelijk: je kunt een process laden op virtueel adres 0 en toch de kernel in dezelfde adress-space laten staan. Hier de asm-code die door grub geladen wordt en waarmee ik paging aanzet en naar 3gb jump:



[BITS 32]

; Zorg dat het begin van de setup sectie door de linker gezien kan worden
global _setup
; _kmain is de c-functie die we aanroepen. Er moet hier een underscore voor omdat
; djgpp aan alle functies en variabelen een underscore toevoegd.
extern _kmain

; Eerst een paar definities voor de multiboot header, zie multiboot specificatie voor info.

; Zorg dat alle boot-modules geladen worden op een adres
; dat samenvalt met een page (deelbaar is door 4096).
MULTIBOOT_MODULE_ALIGN equ 1<<0

; maak dat grub een memory_info structure in het geheugen laad
; Let op: grub geeft ons het adres hiervan in ebx, maar dat is een
; 'echt' adres, geen virtueel adres.
MULTIBOOT_MEMINFO equ 1<<1

; de multiboot flag
MULTIBOOT_FLAGS equ (MULTIBOOT_MODULE_ALIGN | MULTIBOOT_MEMINFO)

; Een magisch getal om te zorgen dat grub deze gegevens vind en de
; de kernel kan laden
MULTIBOOT_MAGIC equ 0x1BADB00

; Als bij de checksum de flags en het magische getal
; opgetelt worden moet de uitkomst 0 zijn.
MULTIBOOT_CHECKSUM equ -(MULTIBOOT_MAGIC + MULTIBOOT_FLAGS)

; Het virtuele adres waarop het tweede gedeelte van de code van de kernel begint
; Dit is dus het adres waar we heen jumpen na paging ingeschakelt te hebben.
KERNEL_VMA equ 0xC0101000

; Het adres waar onze eerste page directory komt te staan. Zodra we eenmaal boven de 3gb zitten
; wordt er in _kmain een nieuwe page_directory opgezet. Het adres van deze page_directory
; maakt niet zoveel uit zolang het geen andere dingen overschrijft (bios, eigen kernel).
PAGE_DIRECTORY equ 0x9C000
; Het adres van de eerste en enige page table die we hier gebruiken.
PAGE_TABLE equ 0x9D000

; Mogelijke waardes voor de attributen van de page directory's en de page table's
PAGE_PRESENT equ 0x0001
PAGE_READWRITE equ 0x0002
PAGE_USER equ 0x0004
; De bits 0x0008 en 0x0010 zijn gereserveerd voor toekomstig gebruik door intel
PAGE_ACCESSED equ 0x0020
PAGE_DIRTY equ 0x0040
; Het attribuut van de elementen in de page directory en de page table
ptattribuut equ (PAGE_PRESENT | PAGE_READWRITE)


SECTION .setup
_setup:
cli
; Vul de page table zodat deze de eerste 4 mb opvult.
mov eax, PAGE_TABLE
mov edx, 0x00000000 | ptattribuut
call map

; Hier vullen we de page directory met nullen zodat er niet per ongeluk
; vreemde waardes in de page directory terechtkomen.
mov ecx,1024
mov edi,PAGE_DIRECTORY
xor eax,eax ; eax = 0
rep stosd

; Hier slaan we het adres van de page table en het attribuut ervan op in het eerste
; en in het 768de element. Hierdoor is het echte adres 0 bereikbaar via virtueel
; adres 0 en via virtueel adres 3gb (0xC000 0000)
mov dword [PAGE_DIRECTORY], PAGE_TABLE | ptattribuut
mov dword [PAGE_DIRECTORY + 768*4], PAGE_TABLE | ptattribuut
; Eerst kopieeren we het adres van de page directory in cr3
mov eax, PAGE_DIRECTORY
mov cr3, eax
; Hier wordt paging ingeschakeld door de laatste bit van cr0 aan te zetten.
mov eax, cr0
or eax, 0x80000000
mov cr0, eax
;Hier maken we een far jump naar 3gb, we komen nu uit in de sectie kernel bij _start.
jmp 0x08:KERNEL_VMA

; Dit is de plaats waar de echte waardes van de multiboot header in het bestand komen te staan
; align 4 is hier nodig om ervoor te zorgen dat grub het magische getal en dus deze gegevens vindt.
align 4
dd MULTIBOOT_MAGIC
dd MULTIBOOT_FLAGS
dd MULTIBOOT_CHECKSUM

; De functie map neemt twee argumenten aan:
; edx: Het 'echte' adres van het begin van de 4mb die in de page table gemapt moeten worden.
; eax: Het adres van de page table waarin de adressen moeten komen en het attribuut
map:
mov ecx, 1024 ; We doorlopen de volgende lus 1024 keer (een page table heeft 1024 elementen)
lmap:
mov dword [eax], edx ; Kopieer het 'echte' adres naar de goede plaats in de page table
add eax, 4 ; We schuiven een element op in de page table (een element is 32bits, dus 4 bytes)
add edx, 4096 ; We schuiven ook het 'echte' adres 4kb (4096 bytes) op
loop lmap ; En we gaan weer naar het begin van de loop
ret

; Zogau paging aangezet is komen we hier aan. We zitten nu op virtueel adres 0xC0101000
; oftewel 3gb + 1mb + 4kb. Die 4kb komt omdat deze sectie 4kb aligned is dmv het linker-script.
SECTION .kernel
_start:
;Het eerste wat we doen is een stack aanmaken
mov esp,stack
; Sla ebx op op de stack. Let erop dat we hierboven nergens ebx gewijzigd hebben
; dus dat ebx nog steeds een pointer naar het multiboot_info structure bevat.
; Deze pointer is nu het eerste argument voor _kmain.
push ebx
call _kmain

; Dit is de sectie die de stack bevat. De stack is 4kb groot. Dit lijkt me voorlopig meer dan genoeg.
; Als de kernel zo uitgebreid wordt dat een grotere stack nodig is, moet alleen de waarde 4096 hieronder
; aangepast worden.
SECTION .bss
resb 4096
stack:

En dan hier mijn linker-script:



OUTPUT_FORMAT("elf32-i386")
ENTRY(_setup)
phys = 0x00100000;
virt = 0xC0100000;
SECTIONS
{
.setup phys : AT( phys )
{
setup = .;
*(.setup)
. = ALIGN(4096);
}
.kernel virt : AT( ADDR(.setup) + SIZEOF(.setup) )
{
kernel = .;
*(.kernel)
*(.text)
. = ALIGN(4096);
}
.data : AT( ADDR(.setup) + SIZEOF(.setup) + SIZEOF(.kernel) )
{
data = .;
*(.data)
. = ALIGN(4096);
}
.bss : AT( ADDR(.setup) + SIZEOF(.setup) + SIZEOF(.kernel) + SIZEOF(.data) )
{
bss = .;
*(.bss)
. = ALIGN(4096);
}
_end = .;
}
12 maart 2006

Java beginners tutorial

Altijd al willen leren programmeren? Of gewoon nieuwsgierig hoe zo'n computer nou eigenlijk werkt? In dat geval ben je hier op het goede adres.


Voordat we beginnen met het eigenlijke programmeren, hier een kleine uitleg wat je met java kunt en wat de voordelen / nadelen zijn van java ten opzichte van c en c++. Als je geen zin hebt in dit theoretische verhaal kun je het ook overslaan en beginnen met de voorbereiding.
Voordelen:


  • Lijkt veel op c++, maar is veel eenvoudiger omdat er geen pointers in java bestaan. Deze heb je in java dan ook niet nodig.

  • Java is objectgeoriënteerd. Het maakt niet uit als je nu nog niet weet wat dit inhoud, hier kom ik later zeker op terug. Voor hele simpele programma's maakt dit niet uit maar je hebt het nodig zogauw je begint met grafische programma's of wat ingewikkeldere technieken.

  • Java is een geïnterpreteerde taal, dit betekend dat java op veel verschillende computers uitgevoerd kan worden (bijv. onder windows en linux) zonder dat je het programma opnieuw moet compileren.

  • Robuustheid: Dit is een gevolg van het feit dat java geïnterpreteerd wordt. Hierdoor zijn verschillende oorzaken van fouten veel makkelijker op te sporen in een java programma dan in een c++ programma.


Nadelen:

  • De snelheid van java programma's ten opzichte van c++ programma's is beperkt.

  • Omdat java nog steeds erg hard in ontwikkeling is verdwijnen er wel eens dingen uit oude versies.


De voorbereiding


Om een programma te schrijven in java hebben we niet veel nodig: een simpele texteditor (kladblok voldoet al), een commandoprompt (onder windows xp: Start->uitvoeren->cmd) en de java sdk van Sun.


We beginnen met het downloaden van de java sdk. Deze is te vinden op de site van sun: http://java.sun.com/javase/downloads/index.jsp. Klik hier op "Download J2SE SDK". Je komt dan op een pagina waar je aan moet vinken akkoord te zijn met de voorwaarden. Download hierna de java sdk voor het besturingssysteem waar jij meer werkt. De installatie spreekt voor zich.


We zijn nu bijna klaar om te beginnen met het eerste programma. Eerst moeten we nog het path iets uitbreiden. Dit gaat onder windows xp op deze manier: Klik met de rechtermuisknop op deze computer en klik op eigenschappen. Ga naar geavanceerd en klik op omgevingsvariabelen. Nu moet je in het onderste vak de variabele 'path' of 'PATH' selecteren op bewerken klikken. Voor dit stukje ga ik ervanuit dat je de java sdk in de map C:/java heb geinstalleerd, als dit niet zo is moet je hierna C:/java vervangen door je eigen installatiemap. Voeg nu in het tekstvak het volgende toe (zonder aanhalingstekens): ";C:/java/bin/". Nu zijn we klaar om met ons eerste programma te beginnen.


Het eerste programma


Om niet met het met simpelste "Hello world!"-programma te beginnen hier een iets uitgebreider voorbeeld:
Bestand: HelloWorld.java

public class HelloWorld{
    int getal1 = 5;
    int getal2 = 8;
    public static void main(String args[] ) {
        System.out.println("Hello World!");
        System.out.println( "Som = " + (getal1+getal2) );
        System.out.println( ("Som = "+getal1) + getal2 );
    }
}

Sla dit op als een bestand genaamd 'HelloWorld.java'. Open daarna een opdrachtprompt, ga naar de goede map (met cd mapnaam) en type:
javac HelloWorld.java
Als het allemaal goed is gegaan heeft de java compiler nu een bestand HelloWorld.class aangemaakt. Om dit bestand uit te voeren type je:
java HelloWorld
Je krijgt nu de volgende uitvoer:
Hello World!
Som = 13
Som = 58


Uitleg van de code


public class HelloWorld {
Deze regel geeft aan dat hier de class HelloWorld begint.
int getal1 = 5;
int getal2 = 8;

Deze regels maken twee variabelen aan met de namen getal1 en getal2. Aan getal1 wordt de waarde 5 toegekent en aan getal2 de waarde 8.
public static void main(String args[] ) {
Deze regel geeft het begin aan van de functie main. De functie main is het beginpunt van het programma. Vanaf dit punt wordt de code uitgevoerd. Deze regel is in elk programma hetzelfde.
System.out.println("Hello World!");
Deze regel print de woorden Hello World! op het scherm op een eigen regel.
System.out.println( "Som = " + (getal1+getal2) );
Hier worden eerste de variabelen getal1 en getal2 bij elkaar opgeteld (5+8=13) en daarna wordt het volgende geprint: Som = 13.
System.out.println( ("Som = "+getal1) + getal2 );
Deze regel lijkt heel erg op de vorige maar verschilt door de haakjes. Deze regel voegt eerst getal1 toe aan "Som = " en plakt er daarna getal2 aan vast. De uitvoer is dan ook: Som = 58.

YeXo online!

YeXo is online! Deze blog zal vooral gaan over progammeren en webdesign. Ik hoop elke week een paar berichten te kunnen plaatsen dus blijf op de hoogte. Ik ben van plan nog deze week een artikel te schrijven over hoe je kunt beginnen met programmeren in c++ en/of java. Ik plan om later vooral over de ingewikkeldere dingen te schrijven. Ik ben nu o.a. bezig met het ontwikkelen van een eigen kernel.