29

Table of Contents - TFE Times · Table of Contents How to make an ... common standard file format for executables in most UNIX system). Chapter 3: First boot with ... This boot process

  • Upload
    lyanh

  • View
    213

  • Download
    0

Embed Size (px)

Citation preview

1. Introduction2. Introductionaboutthex86architectureandaboutourOS3. Setupthedevelopmentenvironment4. FirstbootwithGRUB5. BackboneoftheOSandC++runtime6. Baseclassesformanagingx86architecture7. GDT8. IDTandinterrupts9. Theory:physicalandvirtualmemory10. Memorymanagement:physicalandvirtual11. Processmanagementandmultitasking12. Externalprogramexecution:ELFfiles13. Userlandandsyscalls14. Modulardrivers15. Somebasicsmodules:console,keyboard16. IDEHarddisks17. DOSPartitions18. EXT2read-onlyfilesystems19. StandardClibrary(libC)20. UNIXbasictools:sh,cat21. Luainterpreter

TableofContents

HowtomakeanOperatingSystem

2

OnlinebookabouthowtowriteacomputeroperatingsysteminC/C++fromscratch.

Caution:Thisrepositoryisaremakeofmyoldcourse.ItwaswrittenseveralyearsagoasoneofmyfirstprojectswhenIwasinHighSchool,I'mstillrefactoringsomeparts.TheoriginalcoursewasinFrenchandI'mnotanEnglishnative.I'mgoingtocontinueandimprovethiscourseinmyfree-time.

Book:Anonlineversionisavailableathttp://samypesse.gitbooks.io/how-to-create-an-operating-system/(PDF,MobiandePub).ItwasbeengeneratedusingGitBook.

SourceCode:Allthesystemsourcecodewillbestoredinthesrcdirectory.Eachstepwillcontainlinkstothedifferentrelatedfiles.

Contributions:Thiscourseisopentocontributions,feelfreetosignalerrorswithissuesordirectlycorrecttheerrorswithpull-requests.

Questions:Feelfreetoaskanyquestionsbyaddingissues.Pleasedon'temailme.

YoucanfollowmeonTwitter@SamyPesseorsupportmeonFlattrorGittip.

ThegoalistobuildaverysimpleUNIX-basedoperatingsysteminC++,notjusta"proof-of-concept".TheOSshouldbeabletoboot,startauserlandshell,andbeextensible.

HowtoMakeaComputerOperatingSystem

WhatkindofOSarewebuilding?

HowtomakeanOperatingSystem

3Introduction

HowtomakeanOperatingSystem

4Introduction

Thetermx86denotesafamilyofbackwardcompatibleinstructionsetarchitecturesbasedontheIntel8086CPU.

Thex86architectureisthemostcommoninstructionsetarchitecturesinceitsintroductionin1981fortheIBMPC.Alargeamountofsoftware,includingoperatingsystems(OS's)suchasDOS,Windows,Linux,BSD,SolarisandMacOSX,functionwithx86-basedhardware.

Inthiscoursewearenotgoingtodesignanoperatingsystemforthex86-64architecturebutforx86-32,thankstobackwardcompatibility,ourOSwillbecompatiblewithournewerPCs(buttakecautionifyouwanttotestitonyourrealmachine).

ThegoalistobuildaverysimpleUNIX-basedoperatingsysteminC++,butthegoalisnottojustbuilda"proof-of-concept".TheOSshouldbeabletoboot,startauserlandshellandbeextensible.

TheOSwillbebuiltforthex86architecture,runningon32bits,andcompatiblewithIBMPCs.

Specifications:

CodeinC++x86,32bitarchitectureBootwithGrubKindofmodularsystemfordriversKindofUNIXstyleMultitaskingELFexecutableinuserlandModules(accessibleinuserlandusing/dev/...):

IDEdisksDOSpartitionsClockEXT2(readonly)BochVBE

Userland:APIPosixLibC"Can"runashellorsomeexecutables(e.g.,lua)

Chapter1:Introductiontothex86architectureandaboutourOS

Whatisthex86architecture?

OurOperatingSystem

HowtomakeanOperatingSystem

5Introductionaboutthex86architectureandaboutourOS

Thefirststepistosetupagoodandviabledevelopmentenvironment.UsingVagrantandVirtualbox,you'llbeabletocompileandtestyourOSfromalltheOSs(Linux,WindowsorMac).

Vagrantisfreeandopen-sourcesoftwareforcreatingandconfiguringvirtualdevelopmentenvironments.ItcanbeconsideredawrapperaroundVirtualBox.

Vagrantwillhelpuscreateacleanvirtualdevelopmentenvironmentonwhateversystemyouareusing.ThefirststepistodownloadandinstallVagrantforyoursystemathttp://www.vagrantup.com/.

OracleVMVirtualBoxisavirtualizationsoftwarepackageforx86andAMD64/Intel64-basedcomputers.

VagrantneedsVirtualboxtowork,Downloadandinstallforyoursystemathttps://www.virtualbox.org/wiki/Downloads.

OnceVagrantandVirtualboxareinstalled,youneedtodownloadtheubuntulucid32imageforVagrant:

vagrantboxaddlucid32http://files.vagrantup.com/lucid32.box

Oncethelucid32imageisready,weneedtodefineourdevelopmentenvironmentusingaVagrantfile,createafilenamedVagrantfile.Thisfiledefineswhatprerequisitesourenvironmentneeds:nasm,make,build-essential,grubandqemu.

Startyourboxusing:

vagrantup

Youcannowaccessyourboxbyusingsshtoconnecttothevirtualboxusing:

vagrantssh

ThedirectorycontainingtheVagrantfilewillbemountedbydefaultinthe/vagrantdirectoryoftheguestVM(inthiscase,UbuntuLucid32):

cd/vagrant

ThefileMakefiledefinessomebasicsrulesforbuildingthekernel,theuserlibcandsomeuserlandprograms.

Build:

Chapter2:Setupthedevelopmentenvironment

InstallVagrant

InstallVirtualbox

Startandtestyourdevelopmentenvironment

Buildandtestouroperatingsystem

HowtomakeanOperatingSystem

6Setupthedevelopmentenvironment

makeall

Testouroperatingsystemwithqemu:

makerun

ThedocumentationforqemuisavailableatQEMUEmulatorDocumentation.

Youcanexittheemulatorusing:Ctrl-a.

HowtomakeanOperatingSystem

7Setupthedevelopmentenvironment

Whenanx86-basedcomputeristurnedon,itbeginsacomplexpathtogettothestagewherecontrolistransferredtoourkernel's"main"routine(kmain()).Forthiscourse,weareonlygoingtoconsidertheBIOSbootmethodandnotit'ssuccessor(UEFI).

TheBIOSbootsequenceis:RAMdetection->Hardwaredetection/Initialization->Bootsequence.

Themostimportantstepforusisthe"Bootsequence",wheretheBIOSisdonewithitsinitializationandtriestotransfercontroltothenextstageofthebootloaderprocess.

Duringthe"Bootsequence",theBIOSwilltrytodeterminea"bootdevice"(e.g.floppydisk,hard-disk,CD,USBflashmemorydeviceornetwork).OurOperatingSystemwillinitiallybootfromthehard-disk(butitwillbepossibletobootitfromaCDoraUSBflashmemorydeviceinfuture).Adeviceisconsideredbootableifthebootsectorcontainsthevalidsignaturebytes0x55and0xAAatoffsets511and512respectively(calledthemagicbytesofMasterBootRecord(MBR),Thissignatureisrepresented(inbinary)as0b1010101001010101.Thealternatingbitpatternwasthoughttobeaprotectionagainstcertainfailures(driveorcontroller).Ifthispatternisgarbledor0x00,thedeviceisnotconsideredbootable)

BIOSphysicallysearchesforabootdevicebyloadingthefirst512bytesfromthebootsectorofeachdeviceintophysicalmemory,startingattheaddress0x7C00(1KiBbelowthe32KiBmark).Whenthevalidsignaturebytesaredetected,BIOStransferscontroltothe0x7C00memoryaddress(viaajumpinstruction)inordertoexecutethebootsectorcode.

ThroughoutthisprocesstheCPUhasbeenrunningin16-bitRealMode(thedefaultstateforx86CPUsinordertomaintainbackwardscompatibility).Toexecutethe32-bitinstructionswithinourkernel,abootloaderisrequiredtoswitchtheCPUintoProtectedMode.

GNUGRUB(shortforGNUGRandUnifiedBootloader)isabootloaderpackagefromtheGNUProject.GRUBisthereferenceimplementationoftheFreeSoftwareFoundation'sMultibootSpecification,whichprovidesauserthechoicetobootoneofmultipleoperatingsystemsinstalledonacomputerorselectaspecifickernelconfigurationavailableonaparticularoperatingsystem'spartitions.

Tomakeitsimple,GRUBisthefirstthingbootedbythemachine(aboot-loader)andwillsimplifytheloadingofourkernelstoredonthehard-disk.

GRUBisverysimpletouseMakeitverysimpletoload32bitskernelswithoutneedsof16bitscodeMultibootwithLinux,WindowsandothersMakeiteasytoloadexternalmodulesinmemory

GRUBusestheMultibootspecification,theexecutablebinaryshouldbe32bitsandmustcontainaspecialheader(multibootheader)inits8192firstbytes.OurkernelwillbeaELFexecutablefile("ExecutableandLinkableFormat",acommonstandardfileformatforexecutablesinmostUNIXsystem).

Chapter3:FirstbootwithGRUB

Howthebootworks?

WhatisGRUB?

WhyareweusingGRUB?

HowtouseGRUB?

HowtomakeanOperatingSystem

8FirstbootwithGRUB

ThefirstbootsequenceofourkerneliswritteninAssembly:start.asmandweusealinkerfiletodefineourexecutablestructure:linker.ld.

ThisbootprocessalsoinitializessomeofourC++runtime,itwillbedescribedinthenextchapter.

Multibootheaderstructure:

structmultiboot_info{

u32flags;

u32low_mem;

u32high_mem;

u32boot_device;

u32cmdline;

u32mods_count;

u32mods_addr;

struct{

u32num;

u32size;

u32addr;

u32shndx;

}elf_sec;

unsignedlongmmap_length;

unsignedlongmmap_addr;

unsignedlongdrives_length;

unsignedlongdrives_addr;

unsignedlongconfig_table;

unsignedlongboot_loader_name;

unsignedlongapm_table;

unsignedlongvbe_control_info;

unsignedlongvbe_mode_info;

unsignedlongvbe_mode;

unsignedlongvbe_interface_seg;

unsignedlongvbe_interface_off;

unsignedlongvbe_interface_len;

};

Youcanusethecommandmbchkkernel.elftovalidateyourkernel.elffileagainstthemultibootstandard.Youcanalsousethecommandnm-nkernel.elftovalidatetheoffsetofthedifferentobjectsintheELFbinary.

Thescriptdiskimage.shwillgenerateaharddiskimagethatcanbeusedbyQEMU.

Thefirststepistocreateahard-diskimage(c.img)usingqemu-img:

qemu-imgcreatec.img2M

Weneednowtopartitionthediskusingfdisk:

fdisk./c.img

#SwitchtoExpertcommands

>x

#Changenumberofcylinders(1-1048576)

>c

>4

#Changenumberofheads(1-256,default16):

>h

>16

#Changenumberofsectors/track(1-63,default63)

>s

Createadiskimageforourkernelandgrub

HowtomakeanOperatingSystem

9FirstbootwithGRUB

>63

#Returntomainmenu

>r

#Addanewpartition

>n

#Chooseprimarypartition

>p

#Choosepartitionnumber

>1

#Choosefirstsector(1-4,default1)

>1

#Chooselastsector,+cylindersor+size{K,M,G}(1-4,default4)

>4

#Togglebootableflag

>a

#Choosefirstpartitionforbootableflag

>1

#Writetabletodiskandexit

>w

Weneednowtoattachthecreatedpartitiontotheloop-device(whichallowsafiletobeaccesslikeablockdevice)usinglosetup.Theoffsetofthepartitionispassedasanargumentandcalculatedusing:offset=start_sector*bytes_by_sector.

Usingfdisk-l-uc.img,youget:63*512=32256.

losetup-o32256/dev/loop1./c.img

WecreateaEXT2filesystemonthisnewdeviceusing:

mke2fs/dev/loop1

Wecopyourfilesonamounteddisk:

mount/dev/loop1/mnt/

cp-Rbootdisk/*/mnt/

umount/mnt/

InstallGRUBonthedisk:

grub--device-map=/dev/null<<EOF

device(hd0)./c.img

geometry(hd0)41663

root(hd0,0)

setup(hd0)

quit

EOF

Andfinallywedetachtheloopdevice:

HowtomakeanOperatingSystem

10FirstbootwithGRUB

losetup-d/dev/loop1

GNUGRUBonWikipediaMultibootspecification

SeeAlso

HowtomakeanOperatingSystem

11FirstbootwithGRUB

AkernelcanbeprogrammedinC++,itisverysimilartomakingakernelinC,exceptthatthereareafewpitfallsyoumusttakeintoaccount(runtimesupport,constructors,...)

ThecompilerwillassumethatallthenecessaryC++runtimesupportisavailablebydefault,butaswearenotlinkinginlibsupc++intoyourC++kernel,weneedtoaddsomebasicfunctionsthatcanbefoundinthecxx.ccfile.

Caution:Theoperatorsnewanddeletecannotbeusedbeforevirtualmemoryandpaginationhavebeeninitialized.

Thekernelcodecan'tusefunctionsfromthestandardlibrariessoweneedtoaddsomebasicfunctionsformanagingmemoryandstrings:

voiditoa(char*buf,unsignedlongintn,intbase);

void*memset(char*dst,charsrc,intn);

void*memcpy(char*dst,char*src,intn);

intstrlen(char*s);

intstrcmp(constchar*dst,char*src);

intstrcpy(char*dst,constchar*src);

voidstrcat(void*dest,constvoid*src);

char*strncpy(char*destString,constchar*sourceString,intmaxLength);

intstrncmp(constchar*s1,constchar*s2,intc);

Thesefunctionsaredefinedinstring.cc,memory.cc,itoa.cc

Duringthenextstep,wearegoingtousedifferenttypesinourcode,mostofthetypeswearegoingtouseunsignedtypes(allthebitsareusedtostoredtheinteger,insignedtypesonebitisusedtosignalthesign):

typedefunsignedcharu8;

typedefunsignedshortu16;

typedefunsignedintu32;

typedefunsignedlonglongu64;

typedefsignedchars8;

typedefsignedshorts16;

typedefsignedints32;

typedefsignedlonglongs64;

Compilingakernelisnotthesamethingascompilingalinuxexecutable,wecan'tuseastandardlibraryandshouldhavenodependenciestothesystem.

OurMakefilewilldefinetheprocesstocompileandlinkourkernel.

Forx86architecture,thefollowingsargumentswillbeusedforgcc/g++/ld:

Chapter4:BackboneoftheOSandC++runtime

C++kernelrun-time

BasicC/C++functions

Ctypes

Compileourkernel

HowtomakeanOperatingSystem

12BackboneoftheOSandC++runtime

#Linker

LD=ld

LDFLAG=-melf_i386-static-L./-T./arch/$(ARCH)/linker.ld

#C++compiler

SC=g++

FLAG=$(INCDIR)-g-O2-w-trigraphs-fno-builtin-fno-exceptions-fno-stack-protector-O0-m32-fno-rtti-nostdlib-nodefaultlibs

#Assemblycompiler

ASM=nasm

ASMFLAG=-felf-o

HowtomakeanOperatingSystem

13BackboneoftheOSandC++runtime

NowthatweknowhowtocompileourC++kernelandbootthebinaryusingGRUB,wecanstarttodosomecoolthingsinC/C++.

WearegoingtouseVGAdefaultmode(03h)todisplaysometexttotheuser.Thescreencanbedirectlyaccessedusingthevideomemoryat0xB8000.Thescreenresolutionis80x25andeachcharacteronthescreenisdefinedby2bytes:oneforthecharactercode,andoneforthestyleflag.Thismeansthatthetotalsizeofthevideomemoryis4000B(80B25B2B).

IntheIOclass(io.cc),:

x,y:definethecursorpositiononthescreenreal_screen:definethevideomemorypointerputc(charc):printauniquecharacteronthescreenandmanagecursorpositionprintf(char*s,...):printastring

WeaddamethodputctotheIOClasstoputacharacteronthescreenandupdatethe(x,y)position.

/*putabyteonscreen*/

voidIo::putc(charc){

kattr=0x07;

unsignedchar*video;

video=(unsignedchar*)(real_screen+2*x+160*y);

//newline

if(c=='\n'){

x=0;

y++;

//backspace

}elseif(c=='\b'){

if(x){

*(video+1)=0x0;

x--;

}

//horizontaltab

}elseif(c=='\t'){

x=x+8-(x%8);

//carriagereturn

}elseif(c=='\r'){

x=0;

}else{

*video=c;

*(video+1)=kattr;

x++;

if(x>79){

x=0;

y++;

}

}

if(y>24)

scrollup(y-24);

}

Wealsoaddausefulandveryknownmethod:printf

/*putastringinscreen*/

voidIo::print(constchar*s,...){

va_listap;

charbuf[16];

Chapter5:Baseclassesformanagingx86architecture

Printingtothescreenconsole

HowtomakeanOperatingSystem

14Baseclassesformanagingx86architecture

inti,j,size,buflen,neg;

unsignedcharc;

intival;

unsignedintuival;

va_start(ap,s);

while((c=*s++)){

size=0;

neg=0;

if(c==0)

break;

elseif(c=='%'){

c=*s++;

if(c>='0'&&c<='9'){

size=c-'0';

c=*s++;

}

if(c=='d'){

ival=va_arg(ap,int);

if(ival<0){

uival=0-ival;

neg++;

}else

uival=ival;

itoa(buf,uival,10);

buflen=strlen(buf);

if(buflen<size)

for(i=size,j=buflen;i>=0;

i--,j--)

buf[i]=

(j>=

0)?buf[j]:'0';

if(neg)

print("-%s",buf);

else

print(buf);

}

elseif(c=='u'){

uival=va_arg(ap,int);

itoa(buf,uival,10);

buflen=strlen(buf);

if(buflen<size)

for(i=size,j=buflen;i>=0;

i--,j--)

buf[i]=

(j>=

0)?buf[j]:'0';

print(buf);

}elseif(c=='x'||c=='X'){

uival=va_arg(ap,int);

itoa(buf,uival,16);

buflen=strlen(buf);

if(buflen<size)

for(i=size,j=buflen;i>=0;

i--,j--)

buf[i]=

(j>=

0)?buf[j]:'0';

print("0x%s",buf);

}elseif(c=='p'){

uival=va_arg(ap,int);

itoa(buf,uival,16);

size=8;

buflen=strlen(buf);

if(buflen<size)

for(i=size,j=buflen;i>=0;

i--,j--)

HowtomakeanOperatingSystem

15Baseclassesformanagingx86architecture

buf[i]=

(j>=

0)?buf[j]:'0';

print("0x%s",buf);

}elseif(c=='s'){

print((char*)va_arg(ap,int));

}

}else

putc(c);

}

return;

}

AlargenumberofinstructionsareavailableinAssemblybutthereisnotequivalentinC(likecli,sti,inandout),soweneedaninterfacetotheseinstructions.

InC,wecanincludeAssemblyusingthedirective"asm()",gccusegastocompiletheassembly.

Caution:gasusestheAT&Tsyntax.

/*outputbyte*/

voidIo::outb(u32ad,u8v){

asmv("outb%%al,%%dx"::"d"(ad),"a"(v));;

}

/*outputword*/

voidIo::outw(u32ad,u16v){

asmv("outw%%ax,%%dx"::"d"(ad),"a"(v));

}

/*outputword*/

voidIo::outl(u32ad,u32v){

asmv("outl%%eax,%%dx"::"d"(ad),"a"(v));

}

/*inputbyte*/

u8Io::inb(u32ad){

u8_v;\

asmv("inb%%dx,%%al":"=a"(_v):"d"(ad));\

return_v;

}

/*inputword*/

u16Io::inw(u32ad){

u16_v;\

asmv("inw%%dx,%%ax":"=a"(_v):"d"(ad));\

return_v;

}

/*inputword*/

u32Io::inl(u32ad){

u32_v;\

asmv("inl%%dx,%%eax":"=a"(_v):"d"(ad));\

return_v;

}

Assemblyinterface

HowtomakeanOperatingSystem

16Baseclassesformanagingx86architecture

ThankstoGRUB,yourkernelisnolongerinreal-mode,butalreadyinprotectedmode,thismodeallowsustouseallthepossibilitiesofthemicroprocessorsuchasvirtualmemorymanagement,pagingandsafemulti-tasking.

TheGDT("GlobalDescriptorTable")isadatastructureusedtodefinethedifferentmemoryareas:thebaseaddress,thesizeandaccessprivilegeslikeexecuteandwrite.Thesememoryareasarecalled"segments".

WearegoingtousetheGDTtodefinedifferentmemorysegments:

"code":kernelcode,usedtostoredtheexecutablebinarycode"data":kerneldata"stack":kernelstack,usedtostoredthecallstackduringkernelexecution"ucode":usercode,usedtostoredtheexecutablebinarycodeforuserprogram"udata":userprogramdata"ustack":userstack,usedtostoredthecallstackduringexecutioninuserland

GRUBinitializesaGDTbutthisGDTisdoesnotcorrespondtoourkernel.TheGDTisloadedusingtheLGDTassemblyinstruction.ItexpectsthelocationofaGDTdescriptionstructure:

AndtheCstructure:

structgdtr{

u16limite;

u32base;

}__attribute__((packed));

Caution:thedirective__attribute__((packed))signaltogccthatthestructureshoulduseaslittlememoryaspossible.Withoutthisdirective,gccincludesomebytestooptimizethememoryalignmentandtheaccessduringexecution.

NowweneedtodefineourGDTtableandthenloaditusingLGDT.TheGDTtablecanbestoredwhereverwewantinmemory,itsaddressshouldjustbesignaledtotheprocessusingtheGDTRregistry.

TheGDTtableiscomposedofsegmentswiththefollowingstructure:

Chapter6:GDT

WhatistheGDT?

HowtoloadourGDT?

HowtomakeanOperatingSystem

17GDT

AndtheCstructure:

structgdtdesc{

u16lim0_15;

u16base0_15;

u8base16_23;

u8acces;

u8lim16_19:4;

u8other:4;

u8base24_31;

}__attribute__((packed));

WeneednowtodefineourGDTinmemoryandfinallyloaditusingtheGDTRregistry.

WearegoingtostoreourGDTattheaddress:

#defineGDTBASE0x00000800

Thefunctioninit_gdt_descinx86.ccinitializeagdtsegmentdescriptor.

voidinit_gdt_desc(u32base,u32limite,u8acces,u8other,structgdtdesc*desc)

{

desc->lim0_15=(limite&0xffff);

desc->base0_15=(base&0xffff);

desc->base16_23=(base&0xff0000)>>16;

desc->acces=acces;

desc->lim16_19=(limite&0xf0000)>>16;

desc->other=(other&0xf);

desc->base24_31=(base&0xff000000)>>24;

return;

}

Andthefunctioninit_gdtinitializetheGDT,somepartsofthebelowfunctionwillbeexplainedlaterandareusedformultitasking.

voidinit_gdt(void)

{

default_tss.debug_flag=0x00;

default_tss.io_map=0x00;

default_tss.esp0=0x1FFF0;

default_tss.ss0=0x18;

/*initializegdtsegments*/

init_gdt_desc(0x0,0x0,0x0,0x0,&kgdt[0]);

HowtodefineourGDTtable?

HowtomakeanOperatingSystem

18GDT

init_gdt_desc(0x0,0xFFFFF,0x9B,0x0D,&kgdt[1]);/*code*/

init_gdt_desc(0x0,0xFFFFF,0x93,0x0D,&kgdt[2]);/*data*/

init_gdt_desc(0x0,0x0,0x97,0x0D,&kgdt[3]);/*stack*/

init_gdt_desc(0x0,0xFFFFF,0xFF,0x0D,&kgdt[4]);/*ucode*/

init_gdt_desc(0x0,0xFFFFF,0xF3,0x0D,&kgdt[5]);/*udata*/

init_gdt_desc(0x0,0x0,0xF7,0x0D,&kgdt[6]);/*ustack*/

init_gdt_desc((u32)&default_tss,0x67,0xE9,0x00,&kgdt[7]);/*descripteurdetss*/

/*initializethegdtrstructure*/

kgdtr.limite=GDTSIZE*8;

kgdtr.base=GDTBASE;

/*copythegdtrtoitsmemoryarea*/

memcpy((char*)kgdtr.base,(char*)kgdt,kgdtr.limite);

/*loadthegdtrregistry*/

asm("lgdtl(kgdtr)");

/*initiliazthesegments*/

asm("movw$0x10,%ax\n\

movw%ax,%ds\n\

movw%ax,%es\n\

movw%ax,%fs\n\

movw%ax,%gs\n\

ljmp$0x08,$next\n\

next:\n");

}

HowtomakeanOperatingSystem

19GDT

Aninterruptisasignaltotheprocessoremittedbyhardwareorsoftwareindicatinganeventthatneedsimmediateattention.

Thereare3typesofinterrupts:

Hardwareinterrupts:aresenttotheprocessorfromanexternaldevice(keyboard,mouse,harddisk,...).Hardwareinterruptswereintroducedasawaytoreducewastingtheprocessor'svaluabletimeinpollingloops,waitingforexternalevents.Softwareinterrupts:areinitiatedvoluntarilybythesoftware.It'susedtomanagesystemcalls.Exceptions:areusedforerrorsoreventsoccurringduringprogramexecutionthatareexceptionalenoughthattheycannotbehandledwithintheprogramitself(divisionbyzero,pagefault,...)

Whentheuserpressedakeyonthekeyboard,thekeyboardcontrollerwillsignalaninterrupttotheInterruptController.Iftheinterruptisnotmasked,thecontrollerwillsignaltheinterrupttotheprocessor,theprocessorwillexecutearoutinetomanagetheinterrupt(keypressedorkeyreleased),thisroutinecould,forexample,getthepressedkeyfromthekeyboardcontrollerandprintthekeytothescreen.Oncethecharacterprocessingroutineiscompleted,theinterruptedjobcanberesumed.

ThePIC(Programmableinterruptcontroller)isadevicethatisusedtocombineseveralsourcesofinterruptontooneormoreCPUlines,whileallowingprioritylevelstobeassignedtoitsinterruptoutputs.Whenthedevicehasmultipleinterruptoutputstoassert,itassertsthemintheorderoftheirrelativepriority.

ThebestknownPICisthe8259A,each8259Acanhandle8devicesbutmostcomputershavetwocontrollers:onemasterandoneslave,thisallowsthecomputertomanageinterruptsfrom14devices.

Inthischapter,wewillneedtoprogramthiscontrollertoinitializeandmaskinterrupts.

TheInterruptDescriptorTable(IDT)isadatastructureusedbythex86architecturetoimplementaninterruptvectortable.TheIDTisusedbytheprocessortodeterminethecorrectresponsetointerruptsandexceptions.

OurkernelisgoingtousetheIDTtodefinethedifferentfunctionstobeexecutedwhenaninterruptoccurred.

LiketheGDT,theIDTisloadedusingtheLIDTLassemblyinstruction.ItexpectsthelocationofaIDTdescriptionstructure:

structidtr{

u16limite;

u32base;

}__attribute__((packed));

TheIDTtableiscomposedofIDTsegmentswiththefollowingstructure:

structidtdesc{

u16offset0_15;

u16select;

u16type;

Chapter7:IDTandinterrupts

Thekeyboardexample:

WhatisthePIC?

WhatistheIDT?

HowtomakeanOperatingSystem

20IDTandinterrupts

u16offset16_31;

}__attribute__((packed));

Caution:thedirective__attribute__((packed))signaltogccthatthestructureshoulduseaslittlememoryaspossible.Withoutthisdirective,gccincludessomebytestooptimizethememoryalignmentandtheaccessduringexecution.

NowweneedtodefineourIDTtableandthenloaditusingLIDTL.TheIDTtablecanbestoredwhereverwewantinmemory,itsaddressshouldjustbesignaledtotheprocessusingtheIDTRregistry.

Hereisatableofcommoninterrupts(MaskablehardwareinterruptarecalledIRQ):

IRQ Description

0 ProgrammableInterruptTimerInterrupt

1 KeyboardInterrupt

2 Cascade(usedinternallybythetwoPICs.neverraised)

3 COM2(ifenabled)

4 COM1(ifenabled)

5 LPT2(ifenabled)

6 FloppyDisk

7 LPT1

8 CMOSreal-timeclock(ifenabled)

9 Freeforperipherals/legacySCSI/NIC

10 Freeforperipherals/SCSI/NIC

11 Freeforperipherals/SCSI/NIC

12 PS2Mouse

13 FPU/Coprocessor/Inter-processor

14 PrimaryATAHardDisk

15 SecondaryATAHardDisk

ThisisasimplemethodtodefineanIDTsegment

voidinit_idt_desc(u16select,u32offset,u16type,structidtdesc*desc)

{

desc->offset0_15=(offset&0xffff);

desc->select=select;

desc->type=type;

desc->offset16_31=(offset&0xffff0000)>>16;

return;

}

Andwecannowinitializetheinterupts:

#defineIDTBASE0x00000000

#defineIDTSIZE0xFF

idtrkidtr;

Howtoinitializetheinterrupts?

HowtomakeanOperatingSystem

21IDTandinterrupts

voidinit_idt(void)

{

/*Initirq*/

inti;

for(i=0;i<IDTSIZE;i++)

init_idt_desc(0x08,(u32)_asm_schedule,INTGATE,&kidt[i]);//

/*Vectors0->31areforexceptions*/

init_idt_desc(0x08,(u32)_asm_exc_GP,INTGATE,&kidt[13]);/*#GP*/

init_idt_desc(0x08,(u32)_asm_exc_PF,INTGATE,&kidt[14]);/*#PF*/

init_idt_desc(0x08,(u32)_asm_schedule,INTGATE,&kidt[32]);

init_idt_desc(0x08,(u32)_asm_int_1,INTGATE,&kidt[33]);

init_idt_desc(0x08,(u32)_asm_syscalls,TRAPGATE,&kidt[48]);

init_idt_desc(0x08,(u32)_asm_syscalls,TRAPGATE,&kidt[128]);//48

kidtr.limite=IDTSIZE*8;

kidtr.base=IDTBASE;

/*CopytheIDTtothememory*/

memcpy((char*)kidtr.base,(char*)kidt,kidtr.limite);

/*LoadtheIDTRregistry*/

asm("lidtl(kidtr)");

}

AfterintializationofourIDT,weneedtoactivateinterruptsbyconfiguringthePIC.ThefollowingfunctionwillconfigurethetwoPICsbywrittingintheirinternalregistriesusingtheoutputportsoftheprocessorio.outb.WeconfigurethePICsusingtheports:

MasterPIC:0x20and0x21SlavePIC:0xA0and0xA1

ForaPIC,thereare2typesofregistries:

ICW(InitializationCommandWord):reinitthecontrollerOCW(OperationControlWord):configurethecontrolleronceinitialized(usedtomask/unmasktheinterrupts)

voidinit_pic(void)

{

/*InitializationofICW1*/

io.outb(0x20,0x11);

io.outb(0xA0,0x11);

/*InitializationofICW2*/

io.outb(0x21,0x20);/*startvector=32*/

io.outb(0xA1,0x70);/*startvector=96*/

/*InitializationofICW3*/

io.outb(0x21,0x04);

io.outb(0xA1,0x02);

/*InitializationofICW4*/

io.outb(0x21,0x01);

io.outb(0xA1,0x01);

/*maskinterrupts*/

io.outb(0x21,0x0);

io.outb(0xA1,0x0);

}

Theregistrieshavetobeconfiguredinorder.

PICICWconfigurationsdetails

HowtomakeanOperatingSystem

22IDTandinterrupts

ICW1(port0x20/port0xA0)

|0|0|0|1|x|0|x|x|

||+---withICW4(1)orwithout(0)

|+-----onecontroller(1),orcascade(0)

+---------triggeringbylevel(level)(1)orbyedge(edge)(0)

ICW2(port0x21/port0xA1)

|x|x|x|x|x|0|0|0|

|||||

+-----------------baseaddressforinterruptsvectors

ICW2(port0x21/port0xA1)

Forthemaster:

|x|x|x|x|x|x|x|x|

||||||||

+------------------slavecontrollerconnectedtotheportyes(1),orno(0)

Fortheslave:

|0|0|0|0|0|x|x|x|pourl'esclave

|||

+--------SlaveIDwhichisequaltothemasterport

ICW4(port0x21/port0xA1)

Itisusedtodefineinwhichmodethecontrollershouldwork.

|0|0|0|x|x|x|x|1|

|||+------mode"automaticendofinterrupt"AEOI(1)

||+--------modebufferedslave(0)ormaster(1)

|+----------modebuffered(1)

+------------mode"fullynested"(1)

YoushouldhavenoticedthatwhenI'minitializingourIDTsegments,I'musingoffsetstosegmentthecodeinAssembly.Thedifferentfunctionsaredefinedinx86int.asmandareofthefollowingscheme:

%macroSAVE_REGS0

pushad

pushds

pushes

pushfs

pushgs

pushebx

movbx,0x10

movds,bx

popebx

%endmacro

%macroRESTORE_REGS0

popgs

WhydoidtsegmentsoffsetourASMfunctions?

HowtomakeanOperatingSystem

23IDTandinterrupts

popfs

popes

popds

popad

%endmacro

%macroINTERRUPT1

global_asm_int_%1

_asm_int_%1:

SAVE_REGS

push%1

callisr_default_int

popeax;;aenleversinon

moval,0x20

out0x20,al

RESTORE_REGS

iret

%endmacro

Thesemacroswillbeusedtodefinetheinterruptsegmentthatwillpreventcorruptionofthedifferentregistries,itwillbeveryusefulformultitasking.

HowtomakeanOperatingSystem

24IDTandinterrupts

InthechapterrelatedtotheGDT,wesawthatusingsegmentationaphysicalmemoryaddressiscalculatedusingasegmentselectorandanoffset.

Inthischapter,wearegoingtoimplementpaging,pagingwilltranslatealinearaddressfromsegmentationintoaphysicaladdress.

Pagingwillallowourkernelto:

usethehard-driveasamemoryandnotbelimitedbythemachinerammemorylimittohaveauniquememoryspaceforeachprocesstoallowandunallowmemoryspaceinadynamicway

Inapagedsystem,eachprocessmayexecuteinitsown4gbareaofmemory,withoutanychanceofeffectinganyotherprocess'smemory,orthekernel's.Itsimplifiesmultitasking.

Thetranslationofalinearaddresstoaphysicaladdressisdoneinmultiplesteps:

1. TheprocessorusetheregistryCR3toknowthephysicaladdressofthepagesdirectory.2. Thefirst10bitsofthelinearaddressrepresentanoffset(between0and1023),pointingtoanentryinthepages

directory.Thisentrycontainsthephysicaladdressofapagestable.3. thenext10bitsofthelinearaddressrepresentanoffset,pointingtoanentryinthepagestable.Thisentryispointing

toa4kopage.4. Thelast12bitsofthelinearaddressrepresentanoffset(between0and4095),whichindicatesthepositioninthe4ko

page.

Chapter8:Theory:physicalandvirtualmemory

Whydoweneedpaging?

Howdoesitwork?

HowtomakeanOperatingSystem

25Theory:physicalandvirtualmemory

Thetwotypesofentries(tableanddirectory)looklikethesame.OnlythefieldingraywillbeusedinourOS.

P:indicateifthepageortableisinphysicalmemoryR/W:indicateifthepageortableisaccessibleinwritting(equals1)U/S:equals1toallowaccesstonon-preferredtasksA:indicateifthepageortablewasaccessedD:(onlyforpagestable)indicateifthepagewaswrittenPS(onlyforpagesdirectory)indicatethesizeofpages:

0=4kb1=4mb

Note:Physicaladdressesinthepagesdiretcoryorpagestablearewrittenusing20bitsbecausetheseaddressesarealignedon4kb,sothelast12bitsshouldbeequalto0.

Apagesdirectoryorpagestableused1024*4=4096bytes=4kApagestablecanaddress1024*4k=4MbApagesdirectorycanaddress1024(10244k)=4Gb

Formatforpagestableanddirectory

Howtoenablepagination?

HowtomakeanOperatingSystem

26Theory:physicalandvirtualmemory

Toenablepagination,wejustneedtosetbit31oftheCR0registryto1:

asm("mov%%cr0,%%eax;\

or%1,%%eax;\

mov%%eax,%%cr0"\

::"i"(0x80000000));

Butbefore,weneedtoinitializeourpagesdirectorywithatleastonepagestable.

Withtheidentitymappingmodel,thepagewillapplyonlytothekernelasthefirst4MBofvirtualmemorycoincidewiththefirst4MBofphysicalmemory:

Thismodelissimple:thefirstvirtualmemorypagecoincidetothefirstpageinphysicalmemory,thesecondpagecoincidetothesecondpageonphysicalmemoryandsoon...

IdentityMapping

HowtomakeanOperatingSystem

27Theory:physicalandvirtualmemory

ThekernelknowsthesizeofthephysicalmemoryavailablethankstoGRUB.

Inourimplementation,thefirst8megabytesofphysicalmemorywillbereservedforusebythekernelandwillcontain:

ThekernelGDT,IDTetTSSKernelStackSomespacereservedtohardware(videomemory,...)Pagedirectoryandpagestableforthekernel

Therestofthephysicalmemoryisfreelyavailabletothekernelandapplications.

Theaddressspacebetweenthebeginningofmemoryand0x40000000addressisthekernelspace,whilethespacebetweentheaddress0x40000000andtheendofthememorycorrespondstouserspace:

Memorymanagement:physicalandvirtual

VirtualMemoryMapping

HowtomakeanOperatingSystem

28Memorymanagement:physicalandvirtual

Thekernelspaceinvirtualmemory,whichisusing1Gbofvirtualmemory,iscommontoalltasks(kernelanduser).

Thisisimplementedbypointingthefirst256entriesofthetaskpagedirectorytothekernelpagedirectory(Invmm.cc):

/*

*KernelSpace.v_addr<USER_OFFSETareaddressedbythekernelpagestable

*/

for(i=0;i<256;i++)

pdir[i]=pd0[i];

HowtomakeanOperatingSystem

29Memorymanagement:physicalandvirtual