Per Printz Madsen 1 Linux kernen Monolithic kernel Support for dynamiske moduler Få kerne tråde Preemptive kerne
Per Printz Madsen 2 Linux kerne struktur.
OPS struktur. HW CPU DISK USB Ethernet Memory kernel Memory management FilsystemDevice driver Protokolstak OPS APP Supervisor mode User mode System kald Kald af OPS.-funktion. Fx fopen() Trap Applikationsprogram
Systemkald - Linux OPS APP ENTRY(sys_call_table).long sys_restart_syscall.long sys_exit.long sys_fork....long sys_mitkald #define __NR_exit 1 #define __NR_fork 2... #define __NR_mitkald 290 #include asmlinkage int sys_mitkald (int arg1, char* arg2) { // Kode } #include main() { mitkald(1, "hi"); } _syscall2(int, mitkald, int, arg1, char*, arg2); /usr/src/linux/arch/i386/kernel/syscall_table.S
Systemkald - Linux OPS APP #include asmlinkage int sys_mitkald (int arg1, char* arg2) { // Kode } #include _syscall2(int, mitkald, int, arg1, char*, arg2); main() { mitkald(1, "hi"); } mitkald:.... Int $0x ISR: 80 System_call..... Call *SYMBOL_NAME(sys_call_table)(,%eax,4)
Nyt systemkald i Linux 1.Tilføj entry i sys_tcall_table : /usr/src/linuxXXXX/arch/i386/kernel/syscall_table.S 2.Define systemkald nr. i: /usr/src/linuxXXXX/include/asm-i386/unistd.h 3.Skriv kode til kaldet fx i: mitkald.h og mitkald.c. H- filen placeres typisk i: /usr/src/linuxXXXX/include/linux/ eller /usr/src/linuxXXXX/include/asm/ C-filen placeres typisk i: /usr/src/linuxXXXX/ipc/ eller /usr/src/linuxXXXX/fs/ Modificer Makefilen i det dir du placere din kode i. 5.Generer stubben vha macroen: _syscall2(int, myservice, int, arg1, char*, arg2); 6.Make ny kerne. Læs: /usr/src/linuxXXXX/README 7.Du kan nu anvende systemkaldet, den nye kerne er lavet. Fremgangsmåde:
OPS struktur. Monolitisk kerne HW CPU DISK USB Ethernet Memory kernel Memory management FilsystemDevice driver Protokolstak OPS APP System kald Supervisor mode User mode Linux/UNIX
OPS struktur. Micro kerne HWCPU DISKUSB EthernetMemory Ext. kernel Ext. Memory management Filsystem Device driver Protokolstak OPS APP Supervisor mode User mode Minimal kerne, mem.management og IPC Fx Mach, Amoeba
Per Printz Madsen 9 Linux kerne struktur.
Per Printz Madsen Linux proces. En ressource enhed. Egen memory. Egen status for filer. Egen protection ID. Administrative data fx. Start tid, Forbrugt CPU-tid osv. Samt alle alm. ting, som egen stak, program status, CPU’registre, prioritet osv.
Per Printz Madsen #include void slut () {printf(" -- Så er det slut\n"); exit(0);} int main (int argc, char *argv[]) { int status, pid; char kommando[80]; signal (SIGINT, slut); while (1) { printf("ppmshell>"); scanf("%s",kommando); pid = fork(); if (pid != 0) while(wait(&status) != pid); else execlp(kommando, (char *)NULL); }
Per Printz Madsen 12 Threads
Per Printz Madsen 13 Threads systemkald. int pthread_create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void), void *arg) ; Return 0 for OK ellers fejlkode. thread: Tråd ID. attr: Tråd attributter, hvis NULL så default. start_routine: Kode, der skal afvikles. arg: Evt. argumenter til koden. void pthread_exit (void *value_ptr); value_ptr: Værdi til joining tråde. Ofte NULL. int pthread_join (pthread_t thread, void **value_ptr); Return 0 for OK ellers fejlkode. Thread: Joining tråd ID. value_ptr: Værdi fra joining tråde.
Per Printz Madsen 14 Schedulering. Linux 1.Real-time FIFO. 2.Real-time Round Robin. 3.Alm. Threads og processer. Real-Time prioriteter 0 – 99. Kun SuperUser Alm. prioriteter 100 – 139. Default 120 ( nice ) nice(0) ~ 120 (Default). nice(1) – nice(19) : Nedprioritering fx baggrunds job. nice(-1) – nice(-20) : Kun SuperUser.
Per Printz Madsen 15 Schedulering af alm. threads og processer Tidskvant tilskrevet en proces/tråd, når den forrige er opbrugt: Tidskvant = (140 – Statisk prioritet) * 20 for Statisk prioritet < 120 (140 – Statisk prioritet) * 5 for Statisk prioritet >= 120 Dvs: nice(-20) ~ 800 mS, nice(0) ~ 100 mS nice(19) ~ 5 mS Dynamisk prioritet: Hvem skal til først ? Dyn. prioritet = max(100, min(sta. prioritet – bonus + 5, 139))
Per Printz Madsen 16 Threads systemkald. void pthread_yield(); int pthread_setschedparam(thread,schedpolicy,schedparam); void *traad(void *threadid) { // noget kode } pthread_t th; struct sched_param param; if ((rc= pthread_create(&th, NULL, traad, (void *)0))) { cout << "ERROR – code: " << rc <<'\n'; exit(-1); } param.sched_priority= sched_get_priority_min(SCHED_RR)+1; pthread_setschedparam(th, SCHED_RR, ¶m);
Per Printz Madsen 17 Linux kerne struktur.
Per Printz Madsen Memory management Sikre beskyttelse af memory. Løse relocations problemet. Sikre ''ubegrænset memory'' God udnyttelse. Transparent for programmøren.
Memory management. Løsning: Virtuel memory Kræver ekstra Hardware, nemlig: Memory Management Unit (MMU) Alle alm. CPU’ere har en tilhørende MMU. Pentium. M68XXX Sparc
Virtuel memory.
Virtuel memory: Paging. Oversættelse fra Virtuelle adresser til Fysiske adresser findes i en: Page tabel.
Multi level page tabel. Second-level page tables Top-level page table
Linux’s virtuelle adr.område. Kernel space User space 0x xFFFF FFFF 1 GB 2 GB 0xC
Linux’s måde. Virtuel adr. 32 bit. PD offset 10 bit PF offset 10 bit Frame offset 12 bit cr3 PD tabel Fysisk adresse.
MMU tabel. TLBs – Translation Lookaside Buffers
Page fault. Problem: Hvis den fysiske memory er fuld, hvem skal så fjernes. Fjern ikke en side, der skal bruges hurtigt igen. Modificerede sider skal gemmes. Ikke modificerede sider kan blot overskrives. Metode: Page Replacement Algoritmer.....
Page Replacement Algoritmer. Den optimale algoritme: Fjern den side, som for hvilken det gælder, at det varer længst tid, inden den skal bruges. --- Kan ikke realiseres....
Per Printz Madsen 29 Linux kerne struktur.
Per Printz Madsen Håndtering af Hardware Device drivere. Software moduler der håndterer Hardware fx I/O. Ofte dynamisk loadable. Bliver afvikler i Supervisor mode - Kernel space. Kan kun anvende de, af kernel exporterede, funktioner. Skal udvikles til en bestemt kerne version.
Per Printz Madsen 31 Device-Independent. Protections. Major nr: x Minor nr: y /dev/MinDriver Min driver ttys Protections. Major nr: 3 Minor nr: 48 /dev/ttys0 Protections. Major nr: 3 Minor nr: 49 /dev/ttys1 fd= open(”/dev/MinDriver”,..); read(fd,..); write(fd,..); Nr: x Nr: 3 Operativsystem Applikation
Per Printz Madsen 32 Device-Independent. mknod /dev/MinDevice c chmod 666 /dev/MinDevice Oprettelse af device fil: Character devices: 1 mem 2 pty 3 ttyp 4 ttyS 6 lp 7 vcs 10 misc 13 input 14 sound 21 sg 180 usb /proc/devicesMajor numre: 60 to 63, 120 to 127, 240 to 253 er reserveret for eksperimentelt brug.
Per Printz Madsen 33 Loadable kernemoduler. #include module_init(device1_init); module_exit(device1_exit); make -C /usr/src/linux M='pwd' modules mod1.ko insmod mod1.ko APP OPS rmmod mod1
Per Printz Madsen 34 Hjemmelavet device driver 1.Skriv et kernemodul, der implementerer devicen. Major= register_chrdev(0,”MinDriver”,&fops); Plus meget mere. 2.Indsæt modul i kernen. insmod MinDriver.ko 3.Lav en devicefil mknod –m 664 MinDevice c Major 7
Per Printz Madsen 35 Hjemmelavet device driver static int device1_init(void) { int res; device1_cdev = cdev_alloc( ); device1_cdev->ops = &device1_fops; if (device1_major) { res = register_chrdev_region(dev, device1_nr_devs, "device1"); } else { res = alloc_chrdev_region(&dev, device1_minor, 1, "device1"); device1_major = MAJOR(dev); } if (res < 0) { return res;} else printk(KERN_INFO "device1: major number %d\n",device1_major); cdev_init(device1_cdev, &device1_fops); cdev_add (device1_cdev, dev, device1_nr_devs); printk(KERN_INFO "Inserting device1 module\n"); return 0; } static void device1_exit(void) { unregister_chrdev_region(dev, device1_nr_devs); }
Per Printz Madsen 36 Hjemmelavet device driver int device1_open( struct inode *inode, struct file *filp); int device1_release(struct inode *inode, struct file *filp); ssize_t device1_read( struct file *filp, char *buf, size_t count, loff_t *f_pos); ssize_t device1_write(struct file *filp,const char *buf,size_t count,loff_t *f_pos); struct file_operations device1_fops = {.read= device1_read,.write= device1_write,.open= device1_open,.release= device1_release }; ssize_t device1_read( struct file *filp, char *buf, size_t count, loff_t *f_pos) { copy_to_user(buf,memory_buffer,count); return count; } ssize_t device1_write(struct file *filp,const char *buf,size_t count,loff_t *f_pos) { copy_from_user(memory_buffer,buf,count); return 1; }
Per Printz Madsen 37 Hjemmelavet devicedriver #include int check_region(unsigned long start, unsigned long len); struct resource *request_region(unsigned long start, unsigned long len, char *name); void release_region(unsigned long start, unsigned long len); unsigned char inb(unsigned short port); void outb(unsigned char byte, unsigned short port); unsigned short inw(unsigned short port); void outw(unsigned short word, unsigned short port);
Simpel character devicedriver x x x Controler: UART Status Data Control Systenkald Applikation Operativsystem Output kald. ISR RTE If NoOfChInBuf = BufSize Wait(OutSem); putbuf(ch); If NoOfChInBuf > 0 Åben for IRQ Data =getbuf(); If NoOfChInBuf < 2/3*BufSize og sender har kaldt Wait() så signal(OutSem); If NoOfChInBuf = 0 Luk for IRQ. x
FIFO kø: Ringbuffer #define BufSize 128 char ringbuf[BufSize]; int InPtr=0, UdPtr=0, NoOfChInBuf=0; void enable() {asm("STI");} void disable() {asm("CLI");} void PutBuf(char ch) { disable(); ringbuf[InPtr]= ch; if (BufSize <= ++InPtr) InPtr= 0; ++ NoOfChInBuf enable(); } char GetBuf() { char ch disable(); if (NoOfChInBuf > 0) { ch= ringbuf[UdPtr]; NoOfChInBuf--; if (BufSize <= ++UdPtr) UdPtr= 0; } enable(); return ch; }
Eks. på brug af char device driver #include #include #include #include #include main() { int fd, res, stop= 0; struct termios oldtio, newtio; char buf[255]; fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY ); tcgetattr(fd,&oldtio); /* save current port settings */ bzero(&newtio, sizeof(newtio)); newtio.c_cflag = B38400 | CRTSCTS | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; /* set input mode (non-canonical, no echo,...) */ newtio.c_lflag = 0; newtio.c_cc[VTIME] = 0; /* inter-character timer unused */ newtio.c_cc[VMIN] = 5; /* blocking read until 5 chars received */ tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); while (!stop) { res = read(fd,buf,255); /* returns after 5 chars have been input */ } tcsetattr(fd,TCSANOW,&oldtio); close(fd); }