### Kernel Initialization Sequence Source: https://context7.com/armwillking/linux-0.01/llms.txt Initializes core kernel subsystems and sets up the scheduler during system boot. ```c /* init/main.c - Kernel entry point */ void main(void) { /* Interrupts are still disabled at this point */ time_init(); /* Initialize system time from CMOS */ tty_init(); /* Initialize terminal subsystem */ trap_init(); /* Setup interrupt handlers */ sched_init(); /* Initialize scheduler and timer */ buffer_init(); /* Initialize buffer cache */ hd_init(); /* Initialize hard disk driver */ sti(); /* Enable interrupts */ move_to_user_mode(); if (!fork()) { init(); /* First user process */ } /* Task 0 idle loop */ for(;;) pause(); } ``` ```c /* kernel/sched.c - Scheduler initialization */ void sched_init(void) { int i; struct desc_struct * p; /* Setup TSS and LDT descriptors for task 0 */ set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); /* Clear remaining task slots */ p = gdt+2+FIRST_TSS_ENTRY; for(i=1;ia=p->b=0; p++; p->a=p->b=0; p++; } ltr(0); /* Load task register */ lldt(0); /* Load LDT register */ /* Setup 8253 timer chip for 100Hz */ outb_p(0x36,0x43); outb_p(LATCH & 0xff , 0x40); outb(LATCH >> 8 , 0x40); /* Setup timer interrupt handler */ set_intr_gate(0x20,&timer_interrupt); outb(inb_p(0x21)&~0x01,0x21); /* Setup system call interrupt */ set_system_gate(0x80,&system_call); } ``` -------------------------------- ### Implement File Open System Call in C Source: https://context7.com/armwillking/linux-0.01/llms.txt Handles the `open` system call, managing file descriptors, file table entries, and inode retrieval. It supports various file types and TTY special cases. ```c /* fs/open.c - File open system call */ int sys_open(const char * filename, int flag, int mode) { struct m_inode * inode; struct file * f; int i,fd; mode &= 0777 & ~current->umask; /* Find free file descriptor */ for(fd=0 ; fdfilp[fd]) break; if (fd>=NR_OPEN) return -EINVAL; current->close_on_exec &= ~(1<f_count) break; if (i>=NR_FILE) return -EINVAL; (current->filp[fd]=f)->f_count++; /* Open the file and get inode */ if ((i=open_namei(filename,flag,mode,&inode))<0) { current->filp[fd]=NULL; f->f_count=0; return i; } /* Handle TTY special cases */ if (S_ISCHR(inode->i_mode)) if (MAJOR(inode->i_zone[0])==4) { if (current->leader && current->tty<0) { current->tty = MINOR(inode->i_zone[0]); tty_table[current->tty].pgrp = current->pgrp; } } f->f_mode = inode->i_mode; f->f_flags = flag; f->f_count = 1; f->f_inode = inode; f->f_pos = 0; return (fd); } ``` -------------------------------- ### Implement Write System Call in C Source: https://context7.com/armwillking/linux-0.01/llms.txt Handles the `write` system call, dispatching write operations based on the file type (pipe, character device, block device, regular file). ```c /* fs/read_write.c - Write system call */ int sys_write(unsigned int fd, char * buf, int count) { struct file * file; struct m_inode * inode; if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd])) return -EINVAL; if (!count) return 0; inode=file->f_inode; if (inode->i_pipe) return (file->f_mode&2)?write_pipe(inode,buf,count):-1; if (S_ISCHR(inode->i_mode)) return rw_char(WRITE,inode->i_zone[0],buf,count); if (S_ISBLK(inode->i_mode)) return block_write(inode->i_zone[0],&file->f_pos,buf,count); if (S_ISREG(inode->i_mode)) return file_write(inode,file,buf,count); return -EINVAL; } ``` -------------------------------- ### Implement Process Scheduling and Task Management in C Source: https://context7.com/armwillking/linux-0.01/llms.txt Contains the core scheduler logic, timer interrupt handling, and process sleep/wake mechanisms. ```c /* kernel/sched.c - Process scheduler */ #define NR_TASKS 64 #define HZ 100 /* Task states */ #define TASK_RUNNING 0 #define TASK_INTERRUPTIBLE 1 #define TASK_UNINTERRUPTIBLE 2 #define TASK_ZOMBIE 3 #define TASK_STOPPED 4 struct task_struct *current = &(init_task.task); struct task_struct * task[NR_TASKS] = {&(init_task.task), }; long volatile jiffies=0; void schedule(void) { int i,next,c; struct task_struct ** p; /* Check alarms and wake up interruptible tasks with signals */ for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) if (*p) { if ((*p)->alarm && (*p)->alarm < jiffies) { (*p)->signal |= (1<<(SIGALRM-1)); (*p)->alarm = 0; } if ((*p)->signal && (*p)->state==TASK_INTERRUPTIBLE) (*p)->state=TASK_RUNNING; } /* Find the runnable task with highest counter */ while (1) { c = -1; next = 0; i = NR_TASKS; p = &task[NR_TASKS]; while (--i) { if (!*--p) continue; if ((*p)->state == TASK_RUNNING && (*p)->counter > c) c = (*p)->counter, next = i; } if (c) break; /* All counters are zero, recalculate based on priority */ for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) if (*p) (*p)->counter = ((*p)->counter >> 1) + (*p)->priority; } switch_to(next); } /* Timer interrupt handler - called HZ times per second */ void do_timer(long cpl) { if (cpl) current->utime++; /* User time */ else current->stime++; /* System time */ if ((--current->counter)>0) return; current->counter=0; if (!cpl) return; /* Don't reschedule from kernel mode */ schedule(); } /* Put current process to sleep until event */ void sleep_on(struct task_struct **p) { struct task_struct *tmp; if (!p) return; if (current == &(init_task.task)) panic("task[0] trying to sleep"); tmp = *p; *p = current; current->state = TASK_UNINTERRUPTIBLE; schedule(); if (tmp) tmp->state=0; /* Wake up previous waiter */ } /* Wake up processes waiting on event */ void wake_up(struct task_struct **p) { if (p && *p) { (**p).state=0; /* TASK_RUNNING */ *p=NULL; } } ``` -------------------------------- ### Signal Handling and Registration Source: https://context7.com/armwillking/linux-0.01/llms.txt Implementation of POSIX signal delivery and registration, including the kill system call and signal handler assignment. ```c /* kernel/exit.c - Signal handling */ /* Send a signal to a process */ static inline void send_sig(long sig, struct task_struct * p, int priv) { if (!p || sig<1 || sig>32) return; /* Check permissions */ if (priv || current->uid==p->uid || current->euid==p->uid || current->uid==p->euid || current->euid==p->euid) p->signal |= (1<<(sig-1)); } /* Kill system call - send signal to process(es) */ void do_kill(long pid, long sig, int priv) { struct task_struct **p = NR_TASKS + task; if (!pid) { /* Send to all processes in current process group */ while (--p > &FIRST_TASK) { if (*p && (*p)->pgrp == current->pid) send_sig(sig,*p,priv); } } else if (pid>0) { /* Send to specific process */ while (--p > &FIRST_TASK) { if (*p && (*p)->pid == pid) send_sig(sig,*p,priv); } } else if (pid == -1) { /* Send to all processes */ while (--p > &FIRST_TASK) send_sig(sig,*p,priv); } else { /* Send to process group -pid */ while (--p > &FIRST_TASK) if (*p && (*p)->pgrp == -pid) send_sig(sig,*p,priv); } } int sys_kill(int pid, int sig) { do_kill(pid,sig,!(current->uid || current->euid)); return 0; } /* kernel/sched.c - Signal registration */ int sys_signal(long signal, long addr, long restorer) { long i; switch (signal) { case SIGHUP: case SIGINT: case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGUSR1: case SIGSEGV: case SIGUSR2: case SIGPIPE: case SIGALRM: case SIGCHLD: i=(long) current->sig_fn[signal-1]; current->sig_fn[signal-1] = (fn_ptr) addr; current->sig_restorer = (fn_ptr) restorer; return i; default: return -1; } } ``` -------------------------------- ### Implement Read System Call in C Source: https://context7.com/armwillking/linux-0.01/llms.txt Handles the `read` system call, dispatching read operations based on the file type (pipe, character device, block device, directory, regular file). ```c /* fs/read_write.c - Read system call */ int sys_read(unsigned int fd, char * buf, int count) { struct file * file; struct m_inode * inode; if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd])) return -EINVAL; if (!count) return 0; verify_area(buf,count); inode = file->f_inode; /* Dispatch based on file type */ if (inode->i_pipe) return (file->f_mode&1)?read_pipe(inode,buf,count):-1; if (S_ISCHR(inode->i_mode)) return rw_char(READ,inode->i_zone[0],buf,count); if (S_ISBLK(inode->i_mode)) return block_read(inode->i_zone[0],&file->f_pos,buf,count); if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) { if (count+file->f_pos > inode->i_size) count = inode->i_size - file->f_pos; if (count<=0) return 0; return file_read(inode,file,buf,count); } return -EINVAL; } ``` -------------------------------- ### Copy Page Tables for fork() with COW Source: https://context7.com/armwillking/linux-0.01/llms.txt Implements copy-on-write for page tables when fork() is called. It allocates new page table entries and marks shared physical pages as read-only. Requires kernel memory management functions. ```c #define copy_page(from,to) __asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si") /* Copy page tables for fork(), implementing copy-on-write */ int copy_page_tables(unsigned long from, unsigned long to, long size) { unsigned long * from_page_table; unsigned long * to_page_table; unsigned long this_page; unsigned long * from_dir, * to_dir; unsigned long nr; if ((from&0x3fffff) || (to&0x3fffff)) panic("copy_page_tables called with wrong alignment"); from_dir = (unsigned long *) ((from>>20) & 0xffc); to_dir = (unsigned long *) ((to>>20) & 0xffc); size = ((unsigned) (size+0x3fffff)) >> 22; for( ; size-->0 ; from_dir++,to_dir++) { if (1 & *to_dir) panic("copy_page_tables: already exist"); if (!(1 & *from_dir)) continue; from_page_table = (unsigned long *) (0xfffff000 & *from_dir); if (!(to_page_table = (unsigned long *) get_free_page())) return -1; *to_dir = ((unsigned long) to_page_table) | 7; nr = (from==0)?0xA0:1024; /* 160 pages for first fork */ for ( ; nr-- > 0 ; from_page_table++,to_page_table++) { this_page = *from_page_table; if (!(1 & this_page)) continue; this_page &= ~2; /* Mark read-only for COW */ *to_page_table = this_page; if (this_page > LOW_MEM) { *from_page_table = this_page; this_page -= LOW_MEM; this_page >>= 12; mem_map[this_page]++; /* Increment reference count */ } } } invalidate(); /* Flush TLB */ return 0; } ``` -------------------------------- ### Implement fork() System Call in C Source: https://context7.com/armwillking/linux-0.01/llms.txt This function creates a new process by duplicating the calling process. It handles memory allocation, process state initialization, and resource management. The child process returns 0, and the parent returns the child's PID. ```c /* kernel/fork.c - Process creation */ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none, long ebx,long ecx,long edx, long fs,long es,long ds, long eip,long cs,long eflags,long esp,long ss) { struct task_struct *p; int i; struct file *f; /* Allocate a page for the new task structure and kernel stack */ p = (struct task_struct *) get_free_page(); if (!p) return -EAGAIN; /* Copy parent's task structure */ *p = *current; /* Initialize child's process state */ p->state = TASK_RUNNING; p->pid = last_pid; p->father = current->pid; p->counter = p->priority; p->signal = 0; p->alarm = 0; p->leader = 0; /* Leadership doesn't inherit */ p->utime = p->stime = 0; p->cutime = p->cstime = 0; p->start_time = jiffies; /* Setup Task State Segment (TSS) for context switching */ p->tss.esp0 = PAGE_SIZE + (long) p; p->tss.ss0 = 0x10; p->tss.eip = eip; p->tss.eflags = eflags; p->tss.eax = 0; /* Child returns 0 from fork */ p->tss.ecx = ecx; p->tss.edx = edx; p->tss.ebx = ebx; p->tss.esp = esp; p->tss.ebp = ebp; /* Copy page tables (copy-on-write) */ if (copy_mem(nr,p)) { free_page((long) p); return -EAGAIN; } /* Increment reference counts for open files */ for (i=0; ifilp[i]) f->f_count++; /* Increment inode reference counts */ if (current->pwd) current->pwd->i_count++; if (current->root) current->root->i_count++; /* Setup GDT entries for new task */ set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); task[nr] = p; return last_pid; /* Parent returns child's PID */ } ``` -------------------------------- ### Process Exit and Wait Implementation Source: https://context7.com/armwillking/linux-0.01/llms.txt Handles process termination via do_exit and sys_exit, and child process monitoring via sys_waitpid. ```c /* kernel/exit.c - Process termination */ int do_exit(long code) { int i; /* Free memory */ free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); /* Orphan children to init */ for (i=0 ; ifather == current->pid) task[i]->father = 0; /* Close all open files */ for (i=0 ; ifilp[i]) sys_close(i); /* Release current directory and root */ iput(current->pwd); current->pwd=NULL; iput(current->root); current->root=NULL; /* Release controlling terminal */ if (current->leader && current->tty >= 0) tty_table[current->tty].pgrp = 0; if (current->father) { current->state = TASK_ZOMBIE; do_kill(current->father,SIGCHLD,1); current->exit_code = code; } else release(current); schedule(); return (-1); } int sys_exit(int error_code) { return do_exit((error_code&0xff)<<8); } /* Wait for child process termination */ int sys_waitpid(pid_t pid, int * stat_addr, int options) { int flag=0; struct task_struct ** p; verify_area(stat_addr,4); repeat: for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) if (*p && *p != current && (pid==-1 || (*p)->pid==pid || (pid==0 && (*p)->pgrp==current->pgrp) || (pid<0 && (*p)->pgrp==-pid))) if ((*p)->father == current->pid) { flag=1; if ((*p)->state==TASK_ZOMBIE) { /* Child has exited - return status */ put_fs_long((*p)->exit_code, (unsigned long *) stat_addr); current->cutime += (*p)->utime; current->cstime += (*p)->stime; flag = (*p)->pid; release(*p); return flag; } } if (flag) { if (options & WNOHANG) return 0; sys_pause(); /* Wait for signal */ if (!(current->signal &= ~(1<<(SIGCHLD-1)))) goto repeat; else return -EINTR; } return -ECHILD; } ``` -------------------------------- ### Map Page at Virtual Address - C Source: https://context7.com/armwillking/linux-0.01/llms.txt Maps a physical page at a given virtual address. It handles the allocation of new page tables if necessary and sets the page table entry to present, read-write, and user-accessible. Ensure the physical page address is within the valid range. ```c /* Map a page at a virtual address */ unsigned long put_page(unsigned long page, unsigned long address) { unsigned long tmp, *page_table; if (page < LOW_MEM || page > HIGH_MEMORY) printk("Trying to put page %p at %p\n",page,address); /* Get page directory entry */ page_table = (unsigned long *) ((address>>20) & 0xffc); if ((*page_table)&1) page_table = (unsigned long *) (0xfffff000 & *page_table); else { /* Allocate new page table */ if (!(tmp=get_free_page())) return 0; *page_table = tmp|7; /* Present, RW, User */ page_table = (unsigned long *) tmp; } page_table[(address>>12) & 0x3ff] = page | 7; return page; } ``` -------------------------------- ### Buffer Cache Management Source: https://context7.com/armwillking/linux-0.01/llms.txt Functions for managing block device buffers, including allocation, reading, releasing, and synchronizing dirty buffers to disk. ```c /* fs/buffer.c - Block buffer cache */ #define BLOCK_SIZE 1024 #define NR_HASH 307 struct buffer_head * hash_table[NR_HASH]; static struct buffer_head * free_list; #define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH) #define hash(dev,block) hash_table[_hashfn(dev,block)] /* Get a buffer for a block, allocating if necessary */ struct buffer_head * getblk(int dev, int block) { struct buffer_head * tmp; repeat: /* Check if already in cache */ if (tmp=get_hash_table(dev,block)) return tmp; /* Find a free buffer */ tmp = free_list; do { if (!tmp->b_count) { wait_on_buffer(tmp); if (!tmp->b_count) break; } tmp = tmp->b_next_free; } while (tmp != free_list || (tmp=NULL)); if (!tmp) { printk("Sleeping on free buffer .."); sleep_on(&buffer_wait); goto repeat; } tmp->b_count++; remove_from_queues(tmp); /* Write out if dirty */ if (tmp->b_dirt) sync_dev(tmp->b_dev); /* Update buffer identity */ tmp->b_dev=dev; tmp->b_blocknr=block; tmp->b_dirt=0; tmp->b_uptodate=0; insert_into_queues(tmp); return tmp; } /* Read a block from device */ struct buffer_head * bread(int dev, int block) { struct buffer_head * bh; if (!(bh=getblk(dev,block))) panic("bread: getblk returned NULL\n"); if (bh->b_uptodate) return bh; /* Already in cache */ ll_rw_block(READ,bh); /* Read from device */ if (bh->b_uptodate) return bh; brelse(bh); return (NULL); } /* Release a buffer */ void brelse(struct buffer_head * buf) { if (!buf) return; wait_on_buffer(buf); if (!(buf->b_count--)) panic("Trying to free free buffer"); wake_up(&buffer_wait); } /* Sync all dirty buffers to disk */ int sys_sync(void) { int i; struct buffer_head * bh; sync_inodes(); /* Write inodes first */ bh = start_buffer; for (i=0 ; ib_dirt) ll_rw_block(WRITE,bh); } return 0; } ``` -------------------------------- ### Allocate Free Physical Page - C Source: https://context7.com/armwillking/linux-0.01/llms.txt Allocates a free physical page from memory above 1MB. Returns the physical address of the allocated page or 0 if none is available. It marks the page as used and clears its contents. ```c /* mm/memory.c - Physical page management */ #define PAGE_SIZE 4096 #define LOW_MEM 0x100000 /* 1MB - end of kernel space */ #define PAGING_MEMORY (HIGH_MEMORY - LOW_MEM) #define PAGING_PAGES (PAGING_MEMORY/4096) #define MAP_NR(addr) (((addr)-LOW_MEM)>>12) static unsigned short mem_map[PAGING_PAGES] = {0,}; /* Allocate a free physical page, returns physical address or 0 */ unsigned long get_free_page(void) { register unsigned long __res asm("ax"); __asm__("std ; repne ; scasw\n\t" "jne 1f\n\t" "movw $1,2(%%edi)\n\t" /* Mark page as used */ "sall $12,%%ecx\n\t" /* Convert to address */ "movl %%ecx,%%edx\n\t" "addl %2,%%edx\n\t" "movl $1024,%%ecx\n\t" "leal 4092(%%edx),%%edi\n\t" "rep ; stosl\n\t" /* Clear page */ "movl %%edx,%%eax\n" "1:" "=a" (__res) :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), "D" (mem_map+PAGING_PAGES-1) :"di","cx","dx"); return __res; } ``` -------------------------------- ### Physical Page Allocation and Management Source: https://context7.com/armwillking/linux-0.01/llms.txt Provides functions for allocating and freeing physical memory pages, and for mapping virtual addresses to physical pages. ```APIDOC ## Memory Management - Page Allocation ### Description This section details the core functions for managing physical memory pages within the Linux kernel. It covers page allocation, freeing, and mapping, utilizing a reference counting bitmap and page tables for efficient memory handling and copy-on-write operations. ### Functions #### `get_free_page()` ##### Description Allocates a free physical page of memory. It manages physical memory above 1MB using a reference counting bitmap. ##### Method Internal Kernel Function ##### Return Value - `unsigned long`: The physical address of the allocated page, or 0 if allocation fails. ##### Request Example (Not applicable, this is an internal function call) ##### Response Example (Not applicable, returns a physical address) #### `free_page(unsigned long addr)` ##### Description Frees a previously allocated physical page, decrementing its reference count. It includes checks to prevent freeing kernel memory or non-existent/already free pages. ##### Method Internal Kernel Function ##### Parameters - **addr** (unsigned long) - Required - The physical address of the page to free. ##### Request Example (Not applicable, this is an internal function call) ##### Response Example (Not applicable, this function has a `void` return type) #### `put_page(unsigned long page, unsigned long address)` ##### Description Maps a given physical page (`page`) to a specific virtual address (`address`). It handles the allocation of new page tables if necessary and sets the page table entry with appropriate permissions (Present, RW, User). ##### Method Internal Kernel Function ##### Parameters - **page** (unsigned long) - Required - The physical address of the page to map. - **address** (unsigned long) - Required - The virtual address to map the page to. ##### Request Example (Not applicable, this is an internal function call) ##### Response Example - **unsigned long**: The physical address of the mapped page, or 0 if a new page table could not be allocated. ``` -------------------------------- ### Handle Write to Copy-on-Write Page Source: https://context7.com/armwillking/linux-0.01/llms.txt Handles a page fault that occurs when a process attempts to write to a copy-on-write page. It calls un_wp_page to resolve the write protection. ```c /* Handle write to copy-on-write page */ void do_wp_page(unsigned long error_code, unsigned long address) { un_wp_page((unsigned long *) \ (((address>>10) & 0xffc) + (0xfffff000 & \ *((unsigned long *) ((address>>20) &0xffc)))))); } ``` -------------------------------- ### Unwrite-Protect Page with COW Source: https://context7.com/armwillking/linux-0.01/llms.txt Makes a page writable. If the page is shared (multiple references), it allocates a new page, copies the content, and updates the page table entry to point to the new page. Otherwise, it simply marks the existing page as writable. ```c /* Unwrite-protect a page - allocate new page if shared */ void un_wp_page(unsigned long * table_entry) { unsigned long old_page,new_page; old_page = 0xfffff000 & *table_entry; /* If only one reference, just make it writable */ if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) { *table_entry |= 2; return; } /* Allocate new page and copy contents */ if (!(new_page=get_free_page())) do_exit(SIGSEGV); if (old_page >= LOW_MEM) mem_map[MAP_NR(old_page)]--; *table_entry = new_page | 7; copy_page(old_page,new_page); } ``` -------------------------------- ### Find Empty Process Slot in C Source: https://context7.com/armwillking/linux-0.01/llms.txt This function searches for an available slot in the task table to assign to a new process. It increments the last used PID and iterates through the task array to find the first empty entry. ```c /* Find an empty slot in the task table */ int find_empty_process(void) { int i; repeat: if ((++last_pid)<0) last_pid=1; for(i=0 ; ipid == last_pid) goto repeat; for(i=1 ; i= 0) \ return __res; \ errno = -__res; \ return -1; \ } /* System call with one argument */ #define _syscall1(type,name,atype,a) \ type name(atype a) \ { \ type __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" (a)); \ if (__res >= 0) \ return __res; \ errno = -__res; \ return -1; \ } /* Example: Define fork() and pause() system calls */ static inline _syscall0(int,fork) static inline _syscall0(int,pause) static inline _syscall0(int,sync) /* Usage in init/main.c */ void init(void) { int pid; setup(); /* Initialize devices */ if (!fork()) /* Create child process */ _exit(execve("/bin/update",NULL,NULL)); (void) open("/dev/tty0",O_RDWR,0); /* Open console stdin */ (void) dup(0); /* stdout = stdin */ (void) dup(0); /* stderr = stdin */ if ((pid=fork())<0) printf("Fork failed in init\r\n"); else if (!pid) { close(0);close(1);close(2); setsid(); /* Create new session */ (void) open("/dev/tty0",O_RDWR,0); (void) dup(0); (void) dup(0); _exit(execve("/bin/sh",argv,envp)); /* Execute shell */ } wait(&pid); /* Wait for child */ sync(); /* Sync filesystems */ _exit(0); } ``` -------------------------------- ### System Call for Creating Pipes in Linux Kernel Source: https://context7.com/armwillking/linux-0.01/llms.txt The `sys_pipe` function creates a new pipe and returns two file descriptors, one for reading and one for writing. It manages file table entries and file descriptors. ```c /* Create a pipe - returns two file descriptors */ int sys_pipe(unsigned long * fildes) { struct m_inode * inode; struct file * f[2]; int fd[2]; int i,j; /* Find two free file table entries */ j=0; for(i=0;j<2 && if_count++; if (j<2) { if (j==1) f[0]->f_count=0; return -1; } /* Find two free file descriptors */ j=0; for(i=0;j<2 && ifilp[i]) { current->filp[ fd[j]=i ] = f[j]; j++; } if (j<2) { if (j==1) current->filp[fd[0]]=NULL; f[0]->f_count=f[1]->f_count=0; return -1; } /* Get pipe inode */ if (!(inode=get_pipe_inode())) { current->filp[fd[0]] = current->filp[fd[1]] = NULL; f[0]->f_count = f[1]->f_count = 0; return -1; } f[0]->f_inode = f[1]->f_inode = inode; f[0]->f_pos = f[1]->f_pos = 0; f[0]->f_mode = 1; /* Read end */ f[1]->f_mode = 2; /* Write end */ put_fs_long(fd[0],0+fildes); put_fs_long(fd[1],1+fildes); return 0; } ``` -------------------------------- ### Write Pipe Function in Linux Kernel Source: https://context7.com/armwillking/linux-0.01/llms.txt Implements writing data to a pipe. It waits if the pipe is full and handles cases where no readers are left, signaling SIGPIPE. Data is written to the circular buffer. ```c int write_pipe(struct m_inode * inode, char * buf, int count) { char * b=buf; wake_up(&inode->i_wait); if (inode->i_count != 2) { /* No readers */ current->signal |= (1<<(SIGPIPE-1)); return -1; } while (count-->0) { /* Wait if pipe is full */ while (PIPE_FULL(*inode)) { wake_up(&inode->i_wait); if (inode->i_count != 2) { current->signal |= (1<<(SIGPIPE-1)); return b-buf; } sleep_on(&inode->i_wait); } ((char *)inode->i_size)[PIPE_HEAD(*inode)] = get_fs_byte(b++); INC_PIPE( PIPE_HEAD(*inode) ); wake_up(&inode->i_wait); } wake_up(&inode->i_wait); return b-buf; } ``` -------------------------------- ### Free Physical Page - C Source: https://context7.com/armwillking/linux-0.01/llms.txt Frees a physical page given its address. It handles kernel memory and checks for invalid addresses or attempts to free an already free page. This function decrements the reference count of the page. ```c /* Free a physical page */ void free_page(unsigned long addr) { if (addrHIGH_MEMORY) panic("trying to free nonexistent page"); addr -= LOW_MEM; addr >>= 12; if (mem_map[addr]--) return; /* Decrement reference count */ mem_map[addr]=0; panic("trying to free free page"); } ``` -------------------------------- ### Read Pipe Function in Linux Kernel Source: https://context7.com/armwillking/linux-0.01/llms.txt Implements reading data from a pipe. It waits if the pipe is empty and handles cases where no writers are left. Data is read from the circular buffer. ```c int read_pipe(struct m_inode * inode, char * buf, int count) { char * b=buf; /* Wait for data if pipe is empty */ while (PIPE_EMPTY(*inode)) { wake_up(&inode->i_wait); if (inode->i_count != 2) /* No writers left */ return 0; sleep_on(&inode->i_wait); } /* Read data from circular buffer */ while (count>0 && !(PIPE_EMPTY(*inode))) { count--; put_fs_byte(((char *)inode->i_size)[PIPE_TAIL(*inode)],b++); INC_PIPE( PIPE_TAIL(*inode) ); } wake_up(&inode->i_wait); return b-buf; } ``` -------------------------------- ### Pipe Macros for Linux Kernel Source: https://context7.com/armwillking/linux-0.01/llms.txt These macros define operations for accessing pipe buffer pointers and checking pipe status. They are used within the pipe implementation to manage the circular buffer. ```c #define PIPE_HEAD(inode) (((long *)((inode).i_zone))[0]) #define PIPE_TAIL(inode) (((long *)((inode).i_zone))[1]) #define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1)) #define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode)) #define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1)) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.