免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123
最近访问板块 发新帖
楼主: 轩辕砍刀
打印 上一主题 下一主题

linux内核分析(转自某位大哥网上的笔记) [复制链接]

论坛徽章:
0
21 [报告]
发表于 2003-04-23 20:27 |只看该作者

linux内核分析(转自某位大哥网上的笔记)

#if PAGE_SHIFT         mempages >;>;= (13 - PAGE_SHIFT);
#endif
        mempages *= sizeof(struct list_head);
        for (order = 0; ((1UL
        do {
                unsigned long tmp;

                nr_hash = (1UL                         sizeof(struct list_head);
                d_hash_mask = (nr_hash - 1);

                tmp = nr_hash;
                d_hash_shift = 0;
                while ((tmp >;>;= 1UL) != 0UL)
                        d_hash_shift++;

                dentry_hashtable = (struct list_head *)
                        __get_free_pages(GFP_ATOMIC, order);
        } while (dentry_hashtable == NULL  --order >;= 0);
        ; 如果order太大,超过了__get_free_pages最大可分配尺寸,则减小order的值重试.

        printk("Dentry-cache hash table entries: %d (order: %ld, %ld bytes)\n",
                        nr_hash, order, (PAGE_SIZE
        if (!dentry_hashtable)
                panic("Failed to allocate dcache hash table\n";

        d = dentry_hashtable;
        i = nr_hash;
        do {
                INIT_LIST_HEAD(d);
                d++;
                i--;
        } while (i);
}
对opera的注释加点解释,读起来可能会更省力些。

1.为什么要用这个算法

    例如要构造一个文件 /usr/local/cross/my_comp
这时要沿着上面这个文件名开始依次找直到cross的数据结构,也就是要找到
  /usr/
/usr/local/
/usr/local/cross/
对应的数据结构dentry
    假定我们已经找到/usr/对应的dentry, 现在必须能够从local找到它对应的dentry,这时就要从名字---->;dentry的快速映射,在Linux中般用哈希映射。

2. 查找方法
  首先,通过d_hash粗分类,找到"local"所在的链表,然后顺序向下一一匹配。

3.一些操作如opera所述

4.初始化

  首先通过__get_free_pages获得一些页面,这些页面构成了所有链表头数组。



[目录]

--------------------------------------------------------------------------------


permission(inode,mask)

permission(inode,mask)用来测试对文件(inode)是否有(mask)访问权.

; fs/namei.c

int permission(struct inode * inode,int mask)
{
        if (inode->;i_op  inode->;i_op->;permission) {
                ; 如果文件系统定义了自已的授权算法
                int retval;
                lock_kernel();
                retval = inode->;i_op->;permission(inode, mask);
                unlock_kernel();
                return retval;
        }
        return vfs_permission(inode, mask); 缺省的授权算法
}
int vfs_permission(struct inode * inode,int mask)
{
        int mode = inode->;i_mode;

        ; 如果对只读文件系统中的普通文件,目录文件,符号链接请求写访问
        if ((mask  S_IWOTH)  IS_RDONLY(inode)
                (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
                return -EROFS; /* Nobody gets write access to a read-only fs */
        ; 如果对免疫文件请求写访问
        if ((mask  S_IWOTH)  IS_IMMUTABLE(inode))
                return -EACCES; /* Nobody gets write access to an immutable file */
        if (current->;fsuid == inode->;i_uid)
                mode >;>;= 6; 如果自已是文件的拥有者,取文件对拥有者的访问权
        else if (in_group_p(inode->;i_gid))
                mode >;>;= 3; 如果自已是文件所在组的成员,取文件对组成员的访问权
        ; 如果所请求的权限是实际对文件权限的子集或者被赋予了超越特权,则允许访问
        if (((mode  mask  S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
                return 0;

        ; 虽然自已对文件没有访问权限,但如果自已被赋予了读和检索的特权,
        ; 则允许读或检索目录.
        /* read and search access */
        if ((mask == S_IROTH) ||
            (S_ISDIR(inode->;i_mode)   !(mask  ~(S_IROTH | S_IXOTH))))
                if (capable(CAP_DAC_READ_SEARCH))
                        return 0;

        return -EACCES;
}

; kernel/sys.c
/*
* Check whether we're fsgid/egid or in the supplemental group..
*/
int in_group_p(gid_t grp)
{
        int retval = 1;
        if (grp != current->;fsgid)
                retval = supplemental_group_member(grp);
        return retval;
}
static int supplemental_group_member(gid_t grp)
{
        int i = current->;ngroups;

        if (i) {
                gid_t *groups = current->;groups;
                do {
                        if (*groups == grp)
                                return 1;
                        groups++;
                        i--;
                } while (i);
        }
        return 0;
}




[目录]

--------------------------------------------------------------------------------


IDE硬盘驱动器读写

    Linux内核在缺省配置下最多支持10个IDE接口,IDE接口用ide_hwif_t结构来描述,每个IDE接口具有一对主-从驱动器接口,它们用ide_drive_t结构来描述,每个驱动器接口可接不同种类的IDE设备,如IDE硬盘,光驱等,它们用ide_driver_t结构来描述.
    每个驱动器接口包含一个命令请求队列,用request_queue_t结构来描述,具体的请求用request结构来描述.
    多个IDE驱动器可以共享一个中断,共享同一中断的驱动器形成一个组,用ide_hwgroup_t结构来描述.ide_intr()是所有的ide驱动器所共用的硬件中断入口,对之对应的ide_hwgroup_t指针将作为dev_id传递给ide_intr.
    每次在读写某个驱动器之前,需要用ide_set_handler()来设置ide_intr将要调用的中断函数指针.中断产生以后,该函数指针被自动清除.
    do_rw_disk(drive,rq,block) 从逻辑扇区号block开始向IDE硬盘驱动器drive写入rq所描述的内容.
    以下是硬盘PIO传输模式的有关代码.
; drivers/ide/ide-disk.c
static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{
        if (IDE_CONTROL_REG)
                OUT_BYTE(drive->;ctl,IDE_CONTROL_REG);
        OUT_BYTE(rq->;nr_sectors,IDE_NSECTOR_REG);
        if (drive->;select.b.lba) { 如果是逻辑块寻址模式
                OUT_BYTE(block,IDE_SECTOR_REG);
                OUT_BYTE(block>;>;=8,IDE_LCYL_REG);
                OUT_BYTE(block>;>;=8,IDE_HCYL_REG);
                OUT_BYTE(((block>;>;
        } else {
                unsigned int sect,head,cyl,track;
                track = block / drive->;sect;
                sect  = block % drive->;sect + 1;
                OUT_BYTE(sect,IDE_SECTOR_REG);
                head  = track % drive->;head;
                cyl   = track / drive->;head;
                OUT_BYTE(cyl,IDE_LCYL_REG);
                OUT_BYTE(cyl>;>;8,IDE_HCYL_REG);
                OUT_BYTE(head|drive->;select.all,IDE_SELECT_REG);
        }
        if (rq->;cmd == READ) {{
                ide_set_handler(drive,  WAIT_CMD, NULL); WAIT_CMD为10秒超时
                OUT_BYTE(drive->;mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
                return ide_started;
        }
        if (rq->;cmd == WRITE) {
                ide_startstop_t startstop;
                OUT_BYTE(drive->;mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
                if (ide_wait_stat( drive, DATA_READY, drive->;bad_wstat, WAIT_DRQ)) {
                        printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->;name,
                                drive->;mult_count ? "MULTWRITE" : "WRITE";
                        return startstop;
                }
                if (!drive->;unmask)
                        __cli();        /* local CPU only */
                if (drive->;mult_count) { 如果允许多扇区传送
                        ide_hwgroup_t *hwgroup = HWGROUP(drive);
                        /*
                        * Ugh.. this part looks ugly because we MUST set up
                        * the interrupt handler before outputting the first block
                        * of data to be written.  If we hit an error (corrupted buffer list)
                        * in ide_multwrite(), then we need to remove the handler/timer
                        * before returning.  Fortunately, this NEVER happens (right?).
                        *
                        * Except when you get an error it seems...
                        */
                        hwgroup->;wrq = *rq; /* scratchpad */
                        ide_set_handler (drive,  WAIT_CMD, NULL);
                        if (ide_multwrite(drive, drive->;mult_count)) {
                                unsigned long flags;
                                spin_lock_irqsave( flags);
                                hwgroup->;handler = NULL;
                                del_timer(
                                spin_unlock_irqrestore( flags);
                                return ide_stopped;
                        }
                } else {
                        ide_set_handler (drive,  WAIT_CMD, NULL);
                        idedisk_output_data(drive, rq->;buffer, SECTOR_WORDS); 写入一扇区SECTOR_WORDS=512/4
                }
                return ide_started;
        }
        printk(KERN_ERR "%s: bad command: %d\n", drive->;name, rq->;cmd);
        ide_end_request(0, HWGROUP(drive));
        return ide_stopped;
}
void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
                      unsigned int timeout, ide_expiry_t *expiry)
{
        unsigned long flags;
        ide_hwgroup_t *hwgroup = HWGROUP(drive);

        spin_lock_irqsave( flags);
        if (hwgroup->;handler != NULL) {
                printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
                        drive->;name, hwgroup->;handler, handler);
        }
        hwgroup->;handler        = handler;
        hwgroup->;expiry                = expiry;
        hwgroup->;timer.expires        = jiffies + timeout;
        add_timer(
        spin_unlock_irqrestore( flags);
}
static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
        if (drive->;bswap) {
                idedisk_bswap_data(buffer, wcount);
                ide_output_data(drive, buffer, wcount);
                idedisk_bswap_data(buffer, wcount);
        } else
                ide_output_data(drive, buffer, wcount);
}
void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
        byte io_32bit = drive->;io_32bit;

        if (io_32bit) {
#if SUPPORT_VLB_SYNC
                if (io_32bit  2) {
                        unsigned long flags;
                        __save_flags(flags);        /* local CPU only */
                        __cli();                /* local CPU only */
                        do_vlb_sync(IDE_NSECTOR_REG);
                        outsl(IDE_DATA_REG, buffer, wcount);
                        __restore_flags(flags);        /* local CPU only */
                } else
#endif /* SUPPORT_VLB_SYNC */
                        outsl(IDE_DATA_REG, buffer, wcount);
        } else {
#if SUPPORT_SLOW_DATA_PORTS
                if (drive->;slow) {
                        unsigned short *ptr = (unsigned short *) buffer;
                        while (wcount--) {
                                outw_p(*ptr++, IDE_DATA_REG);
                                outw_p(*ptr++, IDE_DATA_REG);
                        }
                } else
#endif /* SUPPORT_SLOW_DATA_PORTS */
                        outsw(IDE_DATA_REG, buffer, wcount        }
}
int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
{
        ide_hwgroup_t        *hwgroup= HWGROUP(drive);

        /*
        *        This may look a bit odd, but remember wrq is a copy of the
        *        request not the original. The pointers are real however so the
        *        bh's are not copies. Remember that or bad stuff will happen
        *
        *        At the point we are called the drive has asked us for the
        *        data, and its our job to feed it, walking across bh boundaries
        *        if need be.
        */

        struct request        *rq =

          do {
                unsigned long flags;
                  unsigned int nsect = rq->;current_nr_sectors;
                if (nsect >; mcount)
                        nsect = mcount;
                mcount -= nsect;
                ; 这时mcount为剩余的必需传送的扇区数
                idedisk_output_data(drive, rq->;buffer, nsect                spin_lock_irqsave( flags);        /* Is this really necessary? */
#ifdef CONFIG_BLK_DEV_PDC4030
                rq->;sector += nsect;
#endif
                if (((long)(rq->;nr_sectors -= nsect))                         spin_unlock_irqrestore( flags);
                        break;
                }
                if ((rq->;current_nr_sectors -= nsect) == 0) {
                        if ((rq->;bh = rq->;bh->;b_reqnext) != NULL) {{
                                rq->;current_nr_sectors = rq->;bh->;b_size>;>;9;
                                rq->;buffer             = rq->;bh->;b_data;
                        } else {
                                spin_unlock_irqrestore( flags);
                                printk("%s: buffer list corrupted (%ld, %ld, %d)\n",
                                        drive->;name, rq->;current_nr_sectors,
                                        rq->;nr_sectors, nsect);
                                ide_end_request(0, hwgroup);
                                return 1;
                        }
                } else {
                        /* Fix the pointer.. we ate data */
                        rq->;buffer += nsect                 }
                spin_unlock_irqrestore( flags);
        } while (mcount);
        return 0;
}

; IDE接口共用中断入口
void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
{
        unsigned long flags;
        ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
        ide_hwif_t *hwif;
        ide_drive_t *drive;
        ide_handler_t *handler;
        ide_startstop_t startstop;

        spin_lock_irqsave( flags);
        hwif = hwgroup->;hwif;

        if (!ide_ack_intr(hwif)) {
                spin_unlock_irqrestore( flags);
                return;
        }

        if ((handler = hwgroup->;handler) == NULL || hwgroup->;poll_timeout != 0) {
                /*
                * Not expecting an interrupt from this drive.
                * That means this could be:
                *        (1) an interrupt from another PCI device
                *        sharing the same PCI INT# as us.
                * or        (2) a drive just entered sleep or standby mode,
                *        and is interrupting to let us know.
                * or        (3) a spurious interrupt of unknown origin.
                *
                * For PCI, we cannot tell the difference,
                * so in that case we just ignore it and hope it goes away.
                */
#ifdef CONFIG_BLK_DEV_IDEPCI
                if (IDE_PCI_DEVID_EQ(hwif->;pci_devid, IDE_PCI_DEVID_NULL))
#endif        /* CONFIG_BLK_DEV_IDEPCI */
                {
                        /*
                        * Probably not a shared PCI interrupt,
                        * so we can safely try to do something about it:
                        */
                        unexpected_intr(irq, hwgroup);
#ifdef CONFIG_BLK_DEV_IDEPCI
                } else {
                        /*
                        * Whack the status register, just in case we have a leftover pending IRQ.
                        */
                        (void) IN_BYTE(hwif->;io_ports[IDE_STATUS_OFFSET]);
#endif /* CONFIG_BLK_DEV_IDEPCI */
                }
                spin_unlock_irqrestore( flags);
                return;
        }
        drive = hwgroup->;drive;
        if (!drive) {
                /*
                * This should NEVER happen, and there isn't much we could do about it here.
                */
                spin_unlock_irqrestore( flags);
                return;
        }
        if (!drive_is_ready(drive)) {
                /*
                * This happens regularly when we share a PCI IRQ with another device.
                * Unfortunately, it can also happen with some buggy drives that trigger
                * the IRQ before their status register is up to date.  Hopefully we have
                * enough advance overhead that the latter isn't a problem.
                */
                spin_unlock_irqrestore( flags);
                return;
        }
        if (!hwgroup->;busy) {
                hwgroup->;busy = 1;        /* paranoia */
                printk("%s: ide_intr: hwgroup->;busy was 0 ??\n", drive->;name);
        }
        hwgroup->;handler = NULL;
        del_timer(
        spin_unlock(

        if (drive->;unmask)
                ide__sti();        /* local CPU only */
        startstop = handler(drive);                /* service this interrupt, may set handler for next interrupt */
        spin_lock_irq(

        /*
        * Note that handler() may have set things up for another
        * interrupt to occur soon, but it cannot happen until
        * we exit from this routine, because it will be the
        * same irq as is currently being serviced here, and Linux
        * won't allow another of the same (on any CPU) until we return.
        */
        set_recovery_timer(HWIF(drive));
        drive->;service_time = jiffies - drive->;service_start;
        if (startstop == ide_stopped) {
                if (hwgroup->;handler == NULL) {        /* paranoia */
                        hwgroup->;busy = 0;
                        ide_do_request(hwgroup, hwif->;irq);
                } else {
                        printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->;name);
                }
        }
        spin_unlock_irqrestore( flags);
}
; 单个扇区写入之后的中断处理
static ide_startstop_t write_intr (ide_drive_t *drive)
{
        byte stat;
        int i;
        ide_hwgroup_t *hwgroup = HWGROUP(drive);
        struct request *rq = hwgroup->;rq;

        if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->;bad_wstat)) {
                printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->;name, rq->;nr_sectors, stat);
        } else {
                if ((rq->;nr_sectors == 1) ^ ((stat  DRQ_STAT) != 0)) {
                        rq->;sector++;
                        rq->;buffer += 512;
                        rq->;errors = 0;
                        i = --rq->;nr_sectors;
                        --rq->;current_nr_sectors;
                        if (((long)rq->;current_nr_sectors)                                 ide_end_request(1, hwgroup);
                        if (i >; 0) {
                                idedisk_output_data (drive, rq->;buffer, SECTOR_WORDS);
                                ide_set_handler (drive,  WAIT_CMD, NULL);
                                return ide_started;
                        }
                        return ide_stopped;
                }
                return ide_stopped;        /* the original code did this here (?) */
        }
        return ide_error(drive, "write_intr", stat);
}
; 多重扇区写入后的中断处理
static ide_startstop_t multwrite_intr (ide_drive_t *drive)
{
        byte stat;
        int i;
        ide_hwgroup_t *hwgroup = HWGROUP(drive);
        struct request *rq =

        if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->;bad_wstat)) {
                if (stat  DRQ_STAT) {
                        /*
                        *        The drive wants data. Remember rq is the copy
                        *        of the request
                        */
                        if (rq->;nr_sectors) {
                                if (ide_multwrite(drive, drive->;mult_count))
                                        return ide_stopped;
                                ide_set_handler (drive,  WAIT_CMD, NULL);
                                return ide_started;
                        }
                } else {
                        /*
                        *        If the copy has all the blocks completed then
                        *        we can end the original request.
                        */
                        if (!rq->;nr_sectors) {        /* all done? */
                                rq = hwgroup->;rq;
                                for (i = rq->;nr_sectors; i >; 0{
                                        i -= rq->;current_nr_sectors;
                                        ide_end_request(1, hwgroup);
                                }
                                return ide_stopped;
                        }
                }
                return ide_stopped;        /* the original code did this here (?) */
        }
        return ide_error(drive, "multwrite_intr", stat);
}
; 读扇区的中断处理
static ide_startstop_t read_intr (ide_drive_t *drive)
{
        byte stat;
        int i;
        unsigned int msect, nsect;
        struct request *rq;

        /* new way for dealing with premature shared PCI interrupts */
        if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
                if (stat  (ERR_STAT|DRQ_STAT)) {
                        return ide_error(drive, "read_intr", stat);
                }
                /* no data yet, so wait for another interrupt */
                ide_set_handler(drive,  WAIT_CMD, NULL);
                return ide_started;
        }
        msect = drive->;mult_count;

read_next:
        rq = HWGROUP(drive)->;rq;
        if (msect) {
                if ((nsect = rq->;current_nr_sectors) >; msect)
                        nsect = msect;
                msect -= nsect;
        } else
                nsect = 1;
        idedisk_input_data(drive, rq->;buffer, nsect * SECTOR_WORDS);
        rq->;sector += nsect;
        rq->;buffer += nsect        rq->;errors = 0;
        i = (rq->;nr_sectors -= nsect);
        if (((long)(rq->;current_nr_sectors -= nsect))                 ide_end_request(1, HWGROUP(drive));
        if (i >; 0) {
                if (msect)
                        goto read_next;
                ide_set_handler (drive,  WAIT_CMD, NULL);
                return ide_started;
        }
        return ide_stopped;
}
static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
        ide_input_data(drive, buffer, wcount);
        if (drive->;bswap)
                idedisk_bswap_data(buffer, wcount);
}
void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
        byte io_32bit = drive->;io_32bit;

        if (io_32bit) {
#if SUPPORT_VLB_SYNC
                if (io_32bit  2) {
                        unsigned long flags;
                        __save_flags(flags);        /* local CPU only */
                        __cli();                /* local CPU only */
                        do_vlb_sync(IDE_NSECTOR_REG);
                        insl(IDE_DATA_REG, buffer, wcount);
                        __restore_flags(flags);        /* local CPU only */
                } else
#endif /* SUPPORT_VLB_SYNC */
                        insl(IDE_DATA_REG, buffer, wcount);
        } else {
#if SUPPORT_SLOW_DATA_PORTS
                if (drive->;slow) {
                        unsigned short *ptr = (unsigned short *) buffer;
                        while (wcount--) {
                                *ptr++ = inw_p(IDE_DATA_REG);
                                *ptr++ = inw_p(IDE_DATA_REG);
                        }
                } else
#endif /* SUPPORT_SLOW_DATA_PORTS */
                        insw(IDE_DATA_REG, buffer, wcount        }
}


atomic_t queued_sectors;

#define blk_finished_io(nsects)                                \
        atomic_sub(nsects,                 \
        if (atomic_read(                 printk("block: queued_sectors                 atomic_set( 0);                \
        }

static inline void blkdev_dequeue_request(struct request * req)
{
        list_del(
}
void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
{
        struct request *rq;
        unsigned long flags;

        spin_lock_irqsave( flags);
        rq = hwgroup->;rq;

        if (!end_that_request_first(rq, uptodate, hwgroup->;drive->;name)) {
                add_blkdev_randomness(MAJOR(rq->;rq_dev));
                blkdev_dequeue_request(rq);
                hwgroup->;rq = NULL;
                end_that_request_last(rq);
        }
        spin_unlock_irqrestore( flags);
}
int end_that_request_first (struct request *req, int uptodate, char *name)
{
        struct buffer_head * bh;
        int nsect;

        req->;errors = 0;
        if (!uptodate)
                printk("end_request: I/O error, dev %s (%s), sector %lu\n",
                        kdevname(req->;rq_dev), name, req->;sector);

        if ((bh = req->;bh) != NULL) {
                nsect = bh->;b_size >;>; 9;
                blk_finished_io(nsect);
                req->;bh = bh->;b_reqnext;
                bh->;b_reqnext = NULL;
                bh->;b_end_io(bh, uptodate);
                if ((bh = req->;bh) != NULL) {
                        req->;hard_sector += nsect;
                        req->;hard_nr_sectors -= nsect;
                        req->;sector = req->;hard_sector;
                        req->;nr_sectors = req->;hard_nr_sectors;

                        req->;current_nr_sectors = bh->;b_size >;>; 9;
                        if (req->;nr_sectors current_nr_sectors) {
                                req->;nr_sectors = req->;current_nr_sectors;
                                printk("end_request: buffer-list destroyed\n";
                        }
                        req->;buffer = bh->;b_data;
                        return 1;
                }
        }
        return 0;
}
void end_that_request_last(struct request *req)
{
        if (req->;sem != NULL)
                up(req->;sem);

        blkdev_release_request(req);
}
void inline blkdev_release_request(struct request *req)
{
        request_queue_t *q = req->;q;
        int rw = req->;cmd;

        req->;rq_status = RQ_INACTIVE;
        req->;q = NULL;

        /*
        * Request may not have originated from ll_rw_blk. if not,
        * asumme it has free buffers and check waiters
        */
        if (q) {
                /*
                * we've released enough buffers to start I/O again
                */
                if (waitqueue_active(
                     atomic_read(                         wake_up(

                /*
                * Add to pending free list and batch wakeups
                */
                list_add(

                if (++q->;pending_free[rw] >;= batch_requests) {
                        int wake_up = q->;pending_free[rw];
                        blk_refill_freelist(q, rw);
                        wake_up_nr( wake_up);
                }
        }
}
void inline blk_refill_freelist(request_queue_t *q, int rw)
{
        if (q->;pending_free[rw]) {
                list_splice(
                INIT_LIST_HEAD(
                q->;pending_free[rw] = 0;
        }
}






[目录]

--------------------------------------------------------------------------------


proc

PROC文件系统是一个伪文件系统,它的文件和目录是由Linux 操作系统核心提供的,以文件系统的方式为访问系统内核数据的操作提供接口,它们不占用磁盘上的任何空间,有了这些文件和目录, 用户可以更容易的了解操作系统核心或各个进程的状态,并能对系统的一些参数进行配置。比如,一个系统内能打开的文件数最大缺省是1024,即系统最多能同时打开1024个文件,这在使用Linux做多用户的服务器时是不够用的,通过对/PROC下文件的修改可以在不修改核心,甚至不启动机器的情况下改变这个缺省值。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取PROC文件时,PROC文件系统是动态从系统内核读出所需信息并提交的。它的目录结构如下:
目录名称        目录内容
apm         Advanced power management info
Cmdline         Kernel command line
Cpuinfo        Info about the CPU
Devices        Available devices (block and character)
Dma        Used DMS channels
Filesystems        Supported filesystems
Interrupts        Interrupt usage
Ioports        I/O port usage
Kcore        Kernel core image
Kmsg        Kernel messages
Ksyms        Kernel symbol table
Loadavg        Load average
Locks        Kernel locks
Meminfo        Memory info
Misc        Miscellaneous
Modules        List of loaded modules
Mounts        Mounted filesystems
Partitions        Table of partitions known to the system
Rtc        Real time clock
Slabinfo        Slab pool info
Stat        Overall statistics
Swaps        Swap space utilization
Version        Kernel version
Uptime        System uptime

并不是所有这些目录在你的系统中都有,这取决于你的内核配置和装载的模块。另外,在/proc下还有三个很重要的目录:net,scsi和sys。Sys目录是可写的,可以通过它来访问或修改内核的参数,而net和scsi则依赖于内核配置。例如,如果系统不支持scsi,则scsi目录不存在。
除了以上介绍的这些,还有的是一些以数字命名的目录,它们是进程目录。系统中当前运行的每一个进程都有对应的一个目录在/PROC下,以进程的PID号为目录名,它们是读取进程信息的接口。而self目录则是读取进程本身的信息接口,是一个link。Proc文件系统的名字就是由之而起。进程目录的结构如下:

目录名称        目录内容
Cmdline        Command line arguments
Environ        Values of environment variables
Fd        Directory, which contains all file descriptors
Mem        Memory held by this process
Stat        Process status
Status        Process status in human readable form
Cwd        Link to the current working directory
Exe        Link to the executable of this process
Maps        Memory maps
Statm        Process memory status information
Root        Link to the root directory of this process

用户如果要查看系统信息,可以用cat命令。例如:
>; cat /proc/interrupts
           CPU0
  0:    8728810          XT-PIC  timer
  1:        895          XT-PIC  keyboard
  2:          0          XT-PIC  cascade
  3:     531695          XT-PIC  aha152x
  4:    2014133          XT-PIC  serial
  5:      44401          XT-PIC  pcnet_cs
  8:          2          XT-PIC  rtc
11:          8          XT-PIC  i82365
12:     182918          XT-PIC  PS/2 Mouse
13:          1          XT-PIC  fpu
14:    1232265          XT-PIC  ide0
15:          7          XT-PIC  ide1
NMI:          0
2.修改内核参数
在/proc文件系统中有一个有趣的目录:/proc/sys。它不仅提供了内核信息,而且可以通过它修改内核参数,来优化你的系统。但是你必须很小心,因为可能会造成系统崩溃。最好是先找一台无关紧要的机子,调试成功后再应用到你的系统上。
要改变内核的参数,只要用vi编辑或echo参数重定向到文件中即可。下面有一个例子:
# cat /proc/sys/fs/file-max
4096
# echo 8192 >; /proc/sys/fs/file-max
# cat /proc/sys/fs/file-max
8192
如果你优化了参数,则可以把它们写成脚本文件,使它在系统启动时自动完成修改。

PROC文件系统的初始化过程概述

PROC文件系统总的初始化流程如下图所示,是从INIT/MAIN.C的START_KERNEL()函数中开始的,首先是PROC_ROOT_INIT(),在这个函数中用PROC_DIR_EMTRY注册了/PROC及其目录下的各个文件及目录的基本信息,包括注册INODE NUMBER,文件名长度,文件名,操作权限,连接数,用户标识号,组标识号,允许的INODE OPERATIONS和兄弟、父母、子文件的指针等,并生成文件目录之间的相互关系,即目录树。接下来在SYSCLT_INIT()里把ROOT_TABLE的各项内容挂到/PROC树的PROC_SYS_ROOT下面,PROC_SYS_ROOT是一个特殊的PROC项,即/PROC/SYS目录,在此目录下的部分文件是可写的,可以通过修改这些文件内容来修改系统配置参数。然后是FILESYSTEM_SETUP(),在这里产生一个新的FILE_SYSTEM_TYPE:PROC_FS_TYPE,把这个文件系统类型挂到FILE_SYSTEMS链表的末尾,其中包含了读取PROC文件系统SUPER BLOCK的函数指针,PROC_READ_SUPER,接下来在装载了ROOT文件系统后,如果还要把PROC文件系统MOUNT上来则需通过此函数把PROC文件系统的SUPER BLOCK读进内存里的SUPER_BLOCKS链表。从上面可以看到,PROC文件系统的初始化流程主要分两步,即登记注册和挂载文件系统,其中的核心内容是在登记注册里,下面就具体分析一下这两部分的具体初始化操作。
三、PROC文件系统的登记注册过程
从程序中来看,PROC文件系统的文件可以分为两大类,一类是ROOT部分,另一类是BASE部分,体现在初始化程序中分别叫做PROC_ROOT_INIT()和PROC_BASE_INIT()。ROOT部分主要是针对/PROC目录下的一些名称位置相对固定的常规性文件,如 CPUINFO,MEMINFO,KMESG,MODULES,DEVICES,INTERRUPTS,FILESYSTEMS,PARTITIONS,DMA,IOPORTS,CMDLINE,MOUNTS等;而BASE部分则是针对系统中每个进程的,每个运行中的进程在/PROC下都有一个以自己的进程号为名字的目录,里面记载了关于此进程运行状态的信息,如STATUS,MEM,CWD,ROOT,FD,EXE,CMDLINE,STAT,STATM等。下面将会分别介绍这两部分的初始化过程,首先介绍一下基本的数据结构。
1.基本数据结构
在PROC        文件系统中最重要的数据结构是一个叫PROC_DIR_ENTRY的结构类型(include/linux/proc_fs.h),所有该文件系中的文件及目录都除了通用文件操作用的INODE,FILE,DENTRY等结构外,都必须首先注册自己的一个PROC_DIR_ENTRY,在其中定义了针对自己的各项属性和操作函数指针。
struct proc_dir_entry {
unsigned short low_ino;          /*注册inode号,实际inode的低16位*/
                unsigned short namelen;                   /*名称字符串的长度*/
        const char *name;                        /*文件名称*/
                mode_t mode;                           /*文件权限*/
        nlink_t nlink;                               /*连接到此文件的目录项个数*/
                uid_t uid;                                   /*用户标识*/
        gid_t gid;                               /*组标识*/
                unsigned long size;                       /*文件大小,均为0*/
        struct inode_operations * ops;              /*inode操作的函数指针*/
                int (*get_info)(char *, char **, off_t, int, int);
        void (*fill_inode)(struct inode *, int);         /*填补inode信息的函数指针*/
        struct proc_dir_entry *next, *parent, *subdir;    /*兄弟,父亲,子文件指针*/
void *data;
        int (*read_proc)(char *page, char **start, off_t off, int count,
int *eof, void *data);
        int (*write_proc)(struct file *file, const char *buffer,
                                  unsigned long count, void *data);
        int (*readlink_proc)(struct proc_dir_entry *de, char *page);
        unsigned int count;                                /*使用数*/
                int deleted;                                            /*删除标志*/
};
其次就是针对INODE,FILE和SUPER BLOCK的各种操作函数指针,这些结构与文件系统中使用的完全相同,此处不再赘述。
2.PROC_ROOT_INIT()
PROC_ROOT_INIT()函数的定义如下:
__initfunc(void proc_root_init(void))
{
        proc_base_init();
        proc_register(&proc_root, &proc_root_loadavg);
        proc_register(&proc_root, &proc_root_uptime);
        proc_register(&proc_root, &proc_root_meminfo);
        proc_register(&proc_root, &proc_root_kmsg);
        proc_register(&proc_root, &proc_root_version);
        proc_register(&proc_root, &proc_root_cpuinfo);
        proc_register(&proc_root, &proc_root_self);
#ifdef CONFIG_SYSCTL
        proc_register(&proc_root, &proc_sys_root);
#endif
#ifdef CONFIG_MCA
        proc_register(&proc_root, &proc_mca);
#endif

#ifdef CONFIG_DEBUG_MALLOC
        proc_register(&proc_root, &proc_root_malloc);
#endif
#ifdef CONFIG_MODULES
        proc_register(&proc_root, &proc_root_modules);
        proc_register(&proc_root, &proc_root_ksyms);
#endif
        proc_register(&proc_root, &proc_root_stat);
        proc_register(&proc_root, &proc_root_devices);
        proc_register(&proc_root, &proc_root_partitions);
        proc_register(&proc_root, &proc_root_interrupts);
        proc_register(&proc_root, &proc_root_filesystems);
        proc_register(&proc_root, &proc_root_fs);
        proc_register(&proc_root, &proc_root_dma);
        proc_register(&proc_root, &proc_root_ioports);
        proc_register(&proc_root, &proc_root_cmdline);
                ……
                }
__initfunc是在inlucde/linux/init.h中定义的一个宏,表示此函数仅在系统初始化时使用,使用完毕即释放申请的内存资源。
PROC_REGISTER()函数在fs/proc/root.c中定义,程序如下:
int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
{
        int        i;
        if (dp->;low_ino == 0) {
                i = make_inode_number();
                if (i < 0)
                        return -EAGAIN;
                dp->;low_ino = i;
        }
/*如果没有low_ino值,则产生一个新的赋给它*/
        dp->;next = dir->;subdir;
        dp->;parent = dir;
        dir->;subdir = dp;
/*赋给兄弟、父母及子女的指针*/
        if (S_ISDIR(dp->;mode)) {
                if (dp->;ops == NULL)
                        dp->;ops = &proc_dir_inode_operations;
                dir->;nlink++;
        } else if (S_ISLNK(dp->;mode)) {
                if (dp->;ops == NULL)
                        dp->;ops = &proc_link_inode_operations;
        } else {
                if (dp->;ops == NULL)
                        dp->;ops = &proc_file_inode_operations;
        }
/*对于dp的不同属性调整操作函数指针*/
        return 0;
}
初始化时首先要为每个文件或目录创建一个PROC_DIR_ENTRY的实例变量,内容包括注册的INODE号,名称,操作权限,连接数和INODE操作函数指针等,具体方法如下所示:
struct proc_dir_entry proc_root = {
        PROC_ROOT_INO, 5, "/proc", S_IFDIR | S_IRUGO | S_IXUGO,
  2, 0, 0, 0, &proc_root_inode_operations, NULL, NULL, NULL,
        &proc_root, NULL };
struct proc_dir_entry proc_mca = {
        PROC_MCA, 3, "mca", S_IFDIR | S_IRUGO | S_IXUGO,
  2, 0, 0, 0, &proc_dir_inode_operations, NULL, NULL, NULL,
  &proc_root, NULL };
static struct proc_dir_entry proc_root_loadavg = {
        PROC_LOADAVG, 7, "loadavg",        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_array_inode_operations };
static struct proc_dir_entry proc_root_uptime = {
        PROC_UPTIME, 6, "uptime",        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_array_inode_operations };
static struct proc_dir_entry proc_root_meminfo = {
        PROC_MEMINFO, 7, "meminfo",        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_array_inode_operations };
static struct proc_dir_entry proc_root_kmsg = {
        PROC_KMSG, 4, "kmsg", S_IFREG | S_IRUSR, 1, 0, 0,
        0, &proc_kmsg_inode_operations };
......
PROC_REGISTER()函数首先检查这个新的PROC_DIR_ENTRY是否已有自己的PROC INODE号,如前所述,PROC文件系统是个“伪”文件系统,它并不存在于任何实际的物理设备上,所以它的文件INODE号与普通文件的INODE号的涵义是不同的,它不需要标识此文件的物理存在位置,只要能在本文件系统中唯一地标识这个文件即可。对于ROOT部分的文件在include/proc_fs.h中用一个枚举变量enum root_directory_inos来对其赋值,其中第一个文件即/PROC目录用PROC_ROOT_INO=1来定义。如果此文件在变量初始化时未赋值,LINUX用一个proc_alloc_map来表示INODE的使用情况,proc_alloc_map是一块有4096个bits的内存空间,每一位表示一个INODE的使用情况,如已经被使用则置位,放弃时恢复。分配时找其中第一位未使用的bit,在其位数上加上4096就是这个新登记文件的PROC INODE号。在此之后,PROC_REGISTER()调整父目录与子目录/文件之间的指针关系,及子目录/文件的INODE操作函数指针,最终结果是生成一棵以PROC_DIR_ENTRY为节点,PROC_ROOT为根的目录树,表明其相互之间的关系,在以后对文件或目录做标准操作(即用INODE,FILE,DENTRY等结构)的时候就可以从中获得需要的信息和函数指针。


在解释过PROC_REGISTER()函数后顺便再说明一下它的反向操作函数PROC_UNREGISTER(),即注销一个PROC_DIR_ENTRY项,其定义如下:

int proc_unregister(struct proc_dir_entry * dir, int ino)
{
        struct proc_dir_entry **p = &dir->;subdir, *dp;
/*从dir的subdir指针开始进行搜索*/
        while ((dp = *p) != NULL) {          /*在dp指针尚不为空时*/
                if (dp->;low_ino == ino) {    /*如果low_ino==ino,说明仅对root部分*/
                        *p = dp->;next;
                        dp->;next = NULL;
         /*兄弟指针置空*/
                        if (S_ISDIR(dp->;mode))
                                dir->;nlink--;
        /*如果dp是目录,其父目录的连接数要减去1*/
                        if (ino >;= PROC_DYNAMIC_FIRST &&
                            ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
                                clear_bit(ino-PROC_DYNAMIC_FIRST,
                                          (void *) proc_alloc_map);
        /*如果是在程序中生成的low_ino,则要清除对应的proc_allc_map中的*/
         /*位标志*/
                        proc_kill_inodes(ino);
                        return 0;
                }
                p = &dp->;next;            /*p指向dp的兄弟指针,继续搜索*/
        }
        return -EINVAL;
}
在PROC_UNREGISTER()中调用了另一个函数PROC_KILL_INODE(),该函数的功能是把一个已经被注销的PROC文件系统的INODE消灭掉,定义如下:
static void proc_kill_inodes(int ino)
{
        struct file *filp;

        /* inuse_filps is protected by the single kernel lock */
        for (filp = inuse_filps; filp; filp = filp->;f_next) {
     /*在正在使用中的文件链表中进行搜索*/
                struct dentry * dentry;
                struct inode * inode;

                dentry = filp->;f_dentry;
                if (!dentry)
                        continue;
                if (dentry->;d_op != &proc_dentry_operations)
                        continue;
     /*如果该项不属于PROC文件系统,则继续*/
                inode = dentry->;d_inode;
                if (!inode)
                        continue;
                if (inode->;i_ino != ino)
                        continue;
                filp->;f_op = NULL;
     /*把该文件的操作函数指针置空,以后就无法使用了*/
        }
}
3.PROC_BASE_INIT()
PROC_BASE_INIT()函数在PROC_ROOT_INIT()中调用,BASE部分的初始化与ROOT部分基本相同,首先为每个目录和文件初始化一个PROC_DIR_ENTRY结构,然后调用PROC_REGISTER()函数进行注册,并生成BASE部分的关系树,程序如下:
struct proc_dir_entry proc_pid = {
        PROC_PID_INO, 5, "<pid>;",        S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
        0, &proc_base_inode_operations,        NULL, proc_pid_fill_inode,
        NULL, &proc_root, NULL
};

static struct proc_dir_entry proc_pid_status = {
        PROC_PID_STATUS, 6, "status",        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_array_inode_operations,        NULL, proc_pid_fill_inode,
};
static struct proc_dir_entry proc_pid_mem = {
        PROC_PID_MEM, 3, "mem",        S_IFREG | S_IRUSR | S_IWUSR, 1, 0, 0,
        0, &proc_mem_inode_operations,        NULL, proc_pid_fill_inode,
};
static struct proc_dir_entry proc_pid_cwd = {
        PROC_PID_CWD, 3, "cwd",        S_IFLNK | S_IRWXU, 1, 0, 0,
        0, &proc_link_inode_operations,        NULL, proc_pid_fill_inode,
};
static struct proc_dir_entry proc_pid_root = {
        PROC_PID_ROOT, 4, "root",        S_IFLNK | S_IRWXU, 1, 0, 0,
        0, &proc_link_inode_operations,        NULL, proc_pid_fill_inode,
};
static struct proc_dir_entry proc_pid_exe = {
        PROC_PID_EXE, 3, "exe",        S_IFLNK | S_IRWXU, 1, 0, 0,
        0, &proc_link_inode_operations,        NULL, proc_pid_fill_inode,
};
static struct proc_dir_entry proc_pid_fd = {
        PROC_PID_FD, 2, "fd",        S_IFDIR | S_IRUSR | S_IXUSR, 2, 0, 0,
        0, &proc_fd_inode_operations,        NULL, proc_pid_fill_inode,
};
static struct proc_dir_entry proc_pid_environ = {
        PROC_PID_ENVIRON, 7, "environ",        S_IFREG | S_IRUSR, 1, 0, 0,
        0, &proc_array_inode_operations,        NULL, proc_pid_fill_inode,
};
static struct proc_dir_entry proc_pid_cmdline = {
        PROC_PID_CMDLINE, 7, "cmdline",        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_array_inode_operations,        NULL, proc_pid_fill_inode,
};
static struct proc_dir_entry proc_pid_stat = {
        PROC_PID_STAT, 4, "stat",        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_array_inode_operations,        NULL, proc_pid_fill_inode,
};
static struct proc_dir_entry proc_pid_statm = {
        PROC_PID_STATM, 5, "statm",        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_array_inode_operations,        NULL, proc_pid_fill_inode,
};
static struct proc_dir_entry proc_pid_maps = {
        PROC_PID_MAPS, 4, "maps",        S_IFIFO | S_IRUGO, 1, 0, 0,
        0, &proc_arraylong_inode_operations,        NULL, proc_pid_fill_inode, };


__initfunc(void proc_base_init(void))
{
#if CONFIG_AP1000
        proc_register(&proc_pid, &proc_pid_ringbuf);
#endif
        proc_register(&proc_pid, &proc_pid_status);
        proc_register(&proc_pid, &proc_pid_mem);
        proc_register(&proc_pid, &proc_pid_cwd);
        proc_register(&proc_pid, &proc_pid_root);
        proc_register(&proc_pid, &proc_pid_exe);
        proc_register(&proc_pid, &proc_pid_fd);
        proc_register(&proc_pid, &proc_pid_environ);
        proc_register(&proc_pid, &proc_pid_cmdline);
        proc_regis
ter(&proc_pid, &proc_pid_stat);
        proc_register(&proc_pid, &proc_pid_statm);
        proc_register(&proc_pid, &proc_pid_maps);
#ifdef __SMP__
        proc_register(&proc_pid, &proc_pid_cpu);
#endif
};
这部分与ROOT部分的不同之处一是BASE部分的文件/目录的PROC INODE 号是用另一个枚举变量enum pid_directory_inos来赋值,其第一项PROC_PID_INO=2,即<pid>;目录。由于ROOT部分的每个文件/目录在/PROC下只有唯一的一个实例,而BASE部分对每个进程均有相同的一份拷贝,所以它的实际INODE号必须对不同的进程予以区分,在LINUX中,这种区分是通过把进程PID做为INODE的高16位,PROC_DIR_ENTRY中的LOW_INO做为INODE的低16位来实现的,这样可以保证每个文件INODE号在文件系统中的唯一性。另一个不同之处是BASE部分的文件在注册其PROC_DIR_ENTRY的时候都增加了FILL_INODE函数指针,指向PROC_PID_FILL_INODE函数,该函数的主要功能是把实际INODE号右移16位,获得对应此目录或文件的进程PID号,再把此进程的用户标识和组标识赋回给INODE结构。还有一点区别就是PROC_BASE_INIT()初始化的这棵PROC_DIR_ENTRY树是相对独立的(如图2),它以<pid>;目录,即PROC_PID项为根,并注册了该目录下各个文件及目录之间的相互关系,但它并不把PROC_PID挂到PROC_ROOT下面去,因为这是要在对PROC_ROOT做READDIR时动态加载的。
4.INODE OPERATIONS
有一点需要强调的是PROC文件系统在初始化时只是为每个目录和文件登记了一个PROC_DIR_ENTRY项,并为这些项生成了关系树,但对于VFS的通用文件操作做使用的数据结构,如INODE,FILE,DENTRY等此时都是不存在的,这些数据结构要等到在对PROC文件系统的文件做OPEN和READ等操作时才会根据PROC_DIR_ENTRY里定义的INODE OPERATION及其中的FILE OPERATIONS函数指针调用对应函数产生,这是PROC文件系统与其他基于设备的文件系统的一大区别之处。所以,在PROC_DIR_ENTRY中定义的INODE OPERATIONS决定了该文件的操作方式以及获取对应系统信息的渠道。举例来说,PROC_ROOT指向的PROC_ROOT_INODE_OPERATIONS中允许的INODE OPERATIONS函数是PROC_ROOT_LOOKUP,FILE OPERATIONS函数是PROC_ROOT_READDIR ;PROC_PID指向的PROC_BASE_INODE_OPERATIONS中允许的INODE OPERATIONS函数是PROC_LOOKUP,FILE OPERATIONS函数是PROC_ READDIR ;PROC_MEM_INFO指向的PROC_ARRAY_INODE_OPERATIONS中允许的INODE OPERATIONS函数均为空,FILE OPERATIONS函数是ARRAY_READ。下面我们来分析一下几个LOOKUP和READDIR函数,ARRAY_READ的功能主要是面向底层如何获取系统信息反馈上来,详见黄军同学的报告,这里就不做详述了。
PROC_LOOKUP、PROC_READDIR与PROC_ROOT_LOOKUP、PROC_ROOT_READDIR的功能基本上是相同的,只不过加上了ROOT后就加上了对<ID>;目录的处理功能。
程序如下所示:
1) proc_lookup()
int proc_lookup(struct inode * dir, struct dentry *dentry)
{
        struct inode *inode;
        struct proc_dir_entry * de;
        int error;

        error = -ENOTDIR;
        if (!dir || !S_ISDIR(dir->;i_mode))
                goto out;
/*如果dir空或dir不是目录,则退出*/
        error = -ENOENT;
        inode = NULL;
        de = (struct proc_dir_entry *) dir->;u.generic_ip;
/*根据dir生成一个proc_dir_entry的指针*/
        if (de) {
                for (de = de->;subdir; de ; de = de->;next) {
         /*在de的子目录和文件中搜索*/
                        if (!de || !de->;low_ino)
                                continue;
                        if (de->;namelen != dentry->;d_name.len)
                                continue;
                        if (!memcmp(dentry->;d_name.name, de->;name, de->;namelen)) {
            /*如果dentry和由dir指向的proc_dir_entry名字相同*/
                                int ino = de->;low_ino | (dir->;i_ino & ~(0xffff));
                                error = -EINVAL;
                                inode = proc_get_inode(dir->;i_sb, ino, de);
                 /*申请一个inode节点,对应的proc_dir_entry节点为de,节点号*/
                 /*为ino。同时把de的数据填入inode */
                                break;
                        }
                }
        }

        if (inode) {
                dentry->;d_op = &proc_dentry_operations;
                d_add(dentry, inode);
    /*把dentry放到dentry_hash_table表中然后把inode的I_dentry和dentry的*/
    /*d_alias相连*/
    error = 0;
        }
out:
        return error;
}

   2) proc_root_lookup()
static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
{
        unsigned int pid, c;
        struct task_struct *p;
        const char *name;
        struct inode *inode;
        int len;

        if (dir->;i_ino == PROC_ROOT_INO) { /* check for safety... */
                dir->;i_nlink = proc_root.nlink;

                read_lock(&tasklist_lock);  /*加读进程列表的锁*/
                for_each_task(p) {
                        if (p->;pid)
                                dir->;i_nlink++; /*对于每个进程都要把proc_root的link数加1*/
                }
                read_unlock(&tasklist_lock);  /*解读进程列表的锁*/
        }

        if (!proc_lookup(dir, dentry)) /*如果调用proc_lookup成功则返回*/
                return 0;
        /*如果调用proc_lookup不成功,说明要找的是pid部分的*/
        pid = 0;
        name = dentry->;d_name.name;
        len = dentry->;d_name.len;
        while (len-- >; 0) {
                c = *name - '0';
                name++;
                if (c >; 9) {
                        pid = 0;
                        break;
                }
                pid *= 10;
                pid += c;
 /*把目录名的字符串转换成整数型的进程号*/
                if (pid & 0xffff0000) {
                        pid = 0;
                        break;
                }
        }
        read_lock(&tasklist_lock);
        p = find_task_by_pid(pid);
        read_unlock(&tasklist_lock);
        inode = NULL;
        if (pid && p) {
                unsigned long ino = (pid << 16) + PROC_PID_INO;
                inode = proc_get_inode(dir->;i_sb, ino, &proc_pid);
                if (!inode)
                        return -EINVAL;
                inode->;i_flags|=S_IMMUTABLE;
        }

        dentry->;d_op = &proc_dentry_operations;
        d_add(dentry, inode);
        return 0;
}

3) proc_readdir()
int proc_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
        struct proc_dir_entry * de;
        unsigned int ino;
        int i;
        struct inode *inode = filp->;f_dentry->;d_inode;

        if (!inode || !S_ISDIR(inode->;i_mode))
                return -ENOTDIR;
        ino = inode->;i_ino;
        de = (struct proc_dir_entry *) inode->;u.generic_ip;
        if (!de)
                return -EINVAL;
        i = filp->;f_pos;
        switch (i) {
                case 0:
                        if (filldir(dirent, ".", 1, i, ino) < 0)
                                return 0;
                        i++;
                        filp->;f_pos++;
                        /* fall through */
                case 1:
                        if (filldir(dirent, "..", 2, i, de->;parent->;low_ino) < 0)
                                return 0;
                        i++;
                        filp->;f_pos++;
                        /* fall through */
                default:
                        ino &= ~0xffff;
                        de = de->;subdir;
                        i -= 2;
                        for (; {
                                if (!de)
                                        return 1;
                                if (!i)
                                        break;
                                de = de->;next;
                                i--;
                        }

                        do {
                                if (filldir(dirent, de->;name, de->;namelen, filp->;f_pos, ino | de->;low_ino) < 0)
                                        return 0;
                                filp->;f_pos++;
                                de = de->;next;
                        } while (de);
        }
        return 1;
}


4) get_pid_list()
static int get_pid_list(int index, unsigned int *pids)
{
        struct task_struct *p;
        int nr_pids = 0;

        index -= FIRST_PROCESS_ENTRY;
        read_lock(&tasklist_lock);
        for_each_task(p) {
                int pid = p->;pid;
                if (!pid)
                        continue;
                if (--index >;= 0)
                        continue;
                pids[nr_pids] = pid;
                nr_pids++;
                if (nr_pids >;= PROC_MAXPIDS)
                        break;
        }
        read_unlock(&tasklist_lock);
        return nr_pids;
}


5) proc_root_readdir()
static int proc_root_readdir(struct file * filp,        void * dirent, filldir_t filldir)
{
        unsigned int pid_array[PROC_MAXPIDS];
        char buf[PROC_NUMBUF];
        unsigned int nr = filp->;f_pos;
        unsigned int nr_pids, i;

        if (nr < FIRST_PROCESS_ENTRY) {
                int error = proc_readdir(filp, dirent, filldir);
                if (error <= 0)
                        return error;
                filp->;f_pos = nr = FIRST_PROCESS_ENTRY;
        }

        nr_pids = get_pid_list(nr, pid_array);

        for (i = 0; i < nr_pids; i++) {
                int pid = pid_array;
                ino_t ino = (pid << 16) + PROC_PID_INO;
                unsigned long j = PROC_NUMBUF;

                do {
                        j--;
                        buf[j] = '0' + (pid % 10);
                        pid /= 10;
                } while (pid);

                if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->;f_pos, ino) < 0)
                        break;
                filp->;f_pos++;
        }
        return 0;
}


在这里通过inode_operation和file_operation注册的这些函数是在对/PROC下的文件及目录进行open及read操作时才被调用,生成对应的inode,file,dentry等数据结构并取得对应的系统信息反馈

PROC文件系统的挂载过程
FILESYSTEM_SETUP()主要就是调用了一系列的INIT_*_FS()函数(*代表各种不同的文件系统),对PROC文件系统就是INIT_PROC_FS(),在此函数中实例化了一个FILE_SYSTEM_TYPE类型的结构变量PROC_FS_TYPE,其中包括此文件系统的名字和PROC_READ_SUPER函数指针,然后通过REGISTER_FILESYSTEM函数把它挂到FILE_SYSTEMS链表的末尾。
/*  fs/filesystems.c  */
void __init filesystem_setup(void)
{
#ifdef CONFIG_EXT2_FS
        init_ext2_fs();     /*  初始化ext2文件系统  */
#endif
......
#ifdef CONFIG_PROC_FS
        init_proc_fs();     /*  初始化proc文件系统  */
#endif
......
} ;

/*  fs/proc/procfs_syms.c  */
static struct file_system_type proc_fs_type = {
        "proc",
        0 /* FS_NO_DCACHE doesn't work correctly */,
        proc_read_super,    /*针对本文件系统读取super_block的函数指针*/
        NULL } ;
int init_proc_fs(void)
{
        return register_filesystem(&proc_fs_type) == 0;
}

/*   fs/super.c   */
int register_filesystem(struct file_system_type * fs)
{
        struct file_system_type ** tmp;

        if (!fs)
                return -EINVAL;
        if (fs->;next)
                return -EBUSY;
        tmp = &file_systems;
        while (*tmp) {
                if (strcmp((*tmp)->;name, fs->;name) == 0)
                        return -EBUSY;
                tmp = &(*tmp)->;next;
        } /*遍历file_systems链表*/
        *tmp = fs;  /*把fs挂到file_systems链表末尾*/
        return 0;
}

在系统启动时如果需要把PROC文件系统挂载上来则要根据PROC_FS_TYPE中注册的PROC_READ_SUPER()函数把SUPER BLOCK读入内存,并加入SUPER_BLOCKS链表。对于一般基于硬设备上的文件系统,READ_SUPER函数的操作就是在内存中创建一个新的空SUPER BLOCK,然后从设备上把SUPER BLOCK读入。但对于PROC文件系统,其READ_SUPER操作的内容有所不同,因为PROC文件系统是不存在于任何设备上的,所以PROC_READ_SUPER函数就是在产生一个新的空SUPER_BLOCK之后在内存中锁住该块后直接对其进行修改了。
/*   fs/proc/inode.c   */
struct super_block *proc_read_super(struct super_block *s,void *data, int silent)
{
        struct inode * root_inode;

        lock_super(s);    /*锁住该super_block*/
        s->;s_blocksize = 1024;
        s->;s_blocksize_bits = 10;
        s->;s_magic = PROC_SUPER_MAGIC;
        s->;s_op = &proc_sops;
        root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
        if (!root_inode)
                goto out_no_root;
        s->;s_root = d_alloc_root(root_inode, NULL);
        if (!s->;s_root)
                goto out_no_root;
        parse_options(data, &root_inode->;i_uid, &root_inode->;i_gid);
        unlock_super(s);
        return s;

out_no_root:
        printk("proc_read_super: get root inode failed\n";
        iput(root_inode);
        s->;s_dev = 0;
        unlock_super(s);
        return NULL;
}

论坛徽章:
0
22 [报告]
发表于 2003-04-23 20:31 |只看该作者

linux内核分析(转自某位大哥网上的笔记)

处理由 ifconfig 送来的命令,在驱动程序中我们通常只处理 media type的改变。这个函数会根据 ifconfig 送来的值改变 MII 控制器的 media tyep ,你可以使用

     # ifconfig eth0 media 10basT

将目前的输出入界面强迫改到 10basT 。对于某些自动媒体检测做的有问题的switch 而言这可能是必要的设定,但一般而言默认的 auto 是最好的设定。硬件会自动决定要使用那一个界面,使用者完全不必担心,当实体层的设定改变 ( 例如将网络线插到不同的地方 ) ,硬件会自动侦测并改变设定。

void set_rx_mode(struct net_device *net_dev);

改变目前封包过滤器的模式。当你使用

      # ifconfig eth0 promisc
      # ifconfig eth0 multicast

等命令时会被呼叫。一般而言,驱动程序的默认值是只接受目的位址和网络卡的 MAC address 相同的封包。你可以透过 ifconfig 命令控制驱动程序接受其它种类的封包。结语好了 ! 我己经解析完整个网络卡的驱动程序了。当你了解这个驱动程序后,再去了解其它的驱动程序变成一件很简单的事情。大部份网络驱动程序的架构其实都很类似。事实上, Linux 早期的网络卡驱动程序几乎是由同一个人完成的。而后来的驱动程序也几乎
都以这些驱动程序为蓝本,所以看起来都很类似。你要不要也试著再去读另一个网络驱动程序的源代码呢 ? 也许 你会开始抱怨怎么写驱动程序这么神秘的东西怎么变得如此简单了 !

多馀的一节
这一节多馀的,你不想看就算了 为了证明网络驱动程序之间有多类似我再简略的trace Intel eepro100 的驱程程序给大家看。不罗唆,马上开始。

初始化
static struct pci_device_id eepro100_pci_tbl[] __devinitdata = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
                PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER,
                PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029,
                PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030,
                PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82820FW_4,
                PCI_ANY_ID, PCI_ANY_ID, },
        { 0,}
};
MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);
tatic struct pci_driver eepro100_driver = {
        name:           "eepro100",
        id_table:       eepro100_pci_tbl,
        probe:          eepro100_init_one,
        remove:         eepro100_remove_one,
#ifdef CONFIG_EEPRO100_PM
        suspend:        eepro100_suspend,
        resume:         eepro100_resume,
#endif
};
return pci_module_init(&eepro100_driver);

嗯 ! 一切都不出意类之外,是吧 !
初始化装置

eepro100_init_one()

这个看起来比 SIS900 的复杂多了。不过几个关鉴的函数还是一样,只是它的程序码看起比较乱。 BSD 的人喜欢说 Linux 的程序码太乱 ! 嗯,好像不承认不行 不过我说它乱的很可爱,行了吧 !

传送封包
speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)

这个函数相似到我不必做任何讲解,也不必有任何文件你就可以知道它在做些什么事了 ! 程序码几乎到了一行对一行的程度 ( 夸张了一点 ! 不过很接近事实。我信相 SIS900 的 driver 是很整个程序 copy 过去再修改的 )

中断处理

void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);

这个函数,我再喜欢 Linux 也不得不抱怨一下了。 Donald Becker 先生,能麻烦程序写的好看一点好吗 ?
基本上,它把 sis900_rx 的内容直接放在中断处理函数之中。不过我想分开还是会清楚一些。

speedo_tx_buffer_gc 基本上就是 sis900_finish_xmit 。下面的程序是不是很眼熟呢 ?

     dirty_tx = sp->;dirty_tx;
     while ((int)(sp->;cur_tx - dirty_tx) >; 0) {
        int entry = dirty_tx % TX_RING_SIZE;
        int status = le32_to_cpu(sp->;tx_ring[entry].status);
        }

连变数名字都很像呢 !

不过 eepro100 的驱动程序没有实作 set_config 的界面,所以你不能用ifconfig 来改变 media type 。不过 eepro100 提供了由模块命令列选项改变的功 能,当然它是不及 set_config 来的方便就是了。
还要再来一个吗 ? 你自己去做吧 !





[目录]

--------------------------------------------------------------------------------


ISA总线DMA的实现

Linux对ISA总线DMA的实现
  (By 詹荣开,NUDT dep3)

  Copyright ? 2002 by 詹荣开
  E-mail:zhanrk@sohu.com
  Linux-2.4.0 Version 1.0.0,2002-10-16

  关键词:Linux、I/O、ISA总线、设备驱动程序

  申明:这份文档是按照自由软件开放源代码的精神发布的,任何人可以免费获得、使用和重新发布,但是你没有限制别人重新发布你发布内容的权利。发布本文的目的是希望它能对读者有用,但没有任何担保,甚至没有适合特定目的的隐含的担保。更详细的情况请参阅GNU通用公共许可证(GPL),以及GNU自由文档协议(GFDL)。

  你应该已经和文档一起收到一份GNU通用公共许可证(GPL)的副本。如果还没有,写信给:The Free Software Foundation, Inc., 675 Mass Ave, Cambridge,MA02139, USA

  欢迎各位指出文档中的错误与疑问。

----------------------------------------------------

  DMA是一种无需CPU的参与就可以让外设与系统RAM之间进行双向(to device 或 from device)数据传输的硬件机制。使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率(throughput)。

  由于DMA是一种硬件机制,因此它通常与硬件体系结构是相关的,尤其是依赖于外设的总线技术。比如:ISA卡的DMA机制就与PCI卡的DMA机制有区别。本站主要讨论ISA总线的DMA技术。

1.DMA概述

  DMA是外设与主存之间的一种数据传输机制。一般来说,外设与主存之间存在两种数据传输方法:(1)Pragrammed I/O(PIO)方法,也即由CPU通过内存读写指令或I/O指令来持续地读写外设的内存单元(8位、16位或32位),直到整个数据传输过程完成。(2)DMA,即由DMA控制器(DMA Controller,简称DMAC)来完成整个数据传输过程。在此期间,CPU可以并发地执行其他任务,当DMA结束后,DMAC通过中断通知CPU数据传输已经结束,然后由CPU执行相应的ISR进行后处理。

  DMA技术产生时正是ISA总线在PC中流行的时侯。因此,ISA卡的DMA数据传输是通过ISA总线控制芯片组中的两个级联8237 DMAC来实现的。这种DMA机制也称为“标准DMA”(standard DMA)。标准DMA有时也称为“第三方DMA”(third-party DMA),这是因为:系统DMAC完成实际的传输过程,所以它相对于传输过程的“前两方”(传输的发送者和接收者)来说是“第三方”。

  标准DMA技术主要有两个缺点:(1)8237 DMAC的数据传输速度太慢,不能与更高速的总线(如PCI)配合使用。(2)两个8237 DMAC一起只提供了8个DMA通道,这也成为了限制系统I/O吞吐率提升的瓶颈。

  鉴于上述两个原因,PCI总线体系结构设计一种成为“第一方DMA”(first-party DMA)的DMA机制,也称为“Bus Mastering”(总线主控)。在这种情况下,进行传输的PCI卡必须取得系统总线的主控权后才能进行数据传输。实际的传输也不借助慢速的ISA DMAC来进行,而是由内嵌在PCI卡中的DMA电路(比传统的ISA DMAC要快)来完成。Bus Mastering方式的DMA可以让PCI外设得到它们想要的传输带宽,因此它比标准DMA功能满足现代高性能外设的要求。

  随着计算机外设技术的不断发展,现代能提供更快传输速率的Ultra DMA(UDMA)也已经被广泛使用了。本为随后的篇幅只讨论ISA总线的标准DMA技术在Linux中的实现。记住:ISA卡几乎不使用Bus Mastering模式的DMA;而PCI卡只使用Bus Mastering模式的DMA,它从不使用标准DMA。

2.Intel 8237 DMAC

  最初的IBM PC/XT中只有一个8237 DMAC,它提供了4个8位的DMA通道(DMA channel 0-3)。从IBM AT开始,又增加了一个8237 DMAC(提供4个16位的DMA通道,DMA channel 4-7)。两个8237 DMAC一起为系统提供8个DMA通道。与中断控制器8259的级联方式相反,第一个DMAC被级联到第二个DMAC上,通道4被用于DMAC级联,因此它对外设来说是不可用的。第一个DMAC也称为“slave DAMC”,第二个DMAC也称为“Master DMAC”。

  下面我们来详细叙述一下Intel 8237这个DMAC的结构。

  每个8237 DMAC都提供4个DMA通道,每个DMA通道都有各自的寄存器,而8237本身也有一组控制寄存器,用以控制它所提供的所有DMA通道。

  2.1 DMA通道的寄存器

  8237 DMAC中的每个DMA通道都有5个寄存器,分别是:当前地址寄存器、当前计数寄存器、地址寄存器(也称为偏移寄存器)、计数寄存器和页寄存器。其中,前两个是8237的内部寄存器,对外部是不可见的。

  (1)当前地址寄存器(Current Address Register):每个DMA通道都有一个16位的当前地址寄存器,表示一个DMA传输事务(Transfer Transaction)期间当前DMA传输操作的DMA物理内存地址。在每个DMA传输开始前,8237都会自动地用该通道的Address Register中的值来初始化这个寄存器;在传输事务期间的每次DMA传输操作之后该寄存器的值都会被自动地增加或减小。

  (2)当前计数寄存器(Current Count Register):每个每个DMA通道都有一个16位的当前计数寄存器,表示当前DMA传输事务还剩下多少未传输的数据。在每个DMA传输事务开始之前,8237都会自动地用该通道的Count Register中的值来初始化这个寄存器。在传输事务期间的每次DMA传输操作之后该寄存器的值都会被自动地增加或减小(步长为1)。

  (3)地址寄存器(Address Register)或偏移寄存器(Offset Register):每个DMA通道都有一个16位的地址寄存器,表示系统RAM中的DMA缓冲区的起始位置在页内的偏移。

  (4)计数寄存器(Count Register):每个DMA通道都有一个16位的计数寄存器,表示DMA缓冲区的大小。

  (5)页寄存器(Page Register):该寄存器定义了DMA缓冲区的起始位置所在物理页的基地址,即页号。页寄存器有点类似于PC中的段基址寄存器。

  2.2 8237 DAMC的控制寄存器

  (1)命令寄存器(Command Register)

  这个8位的寄存器用来控制8237芯片的操作。其各位的定义如下图所示:

  (2)模式寄存器(Mode Register)

  用于控制各DMA通道的传输模式,如下所示:

  (3)请求寄存器(Request Register)

  用于向各DMA通道发出DMA请求。各位的定义如下:

  (4)屏蔽寄存器(Mask Register)

  用来屏蔽某个DMA通道。当一个DMA通道被屏蔽后,它就不能在服务于DMA请求,直到通道的屏蔽码被清除。各位的定义如下:

  上述屏蔽寄存器也称为“单通道屏蔽寄存器”(Single Channel Mask Register),因为它一次只能屏蔽一个通道。此外含有一个屏蔽寄存器,可以实现一次屏蔽所有4个DMA通道,如下:

  (5)状态寄存器(Status Register)

  一个只读的8位寄存器,表示各DMA通道的当前状态。比如:DMA通道是否正服务于一个DMA请求,或者某个DMA通道上的DMA传输事务已经完成。各位的定义如下:

  2.3 8237 DMAC的I/O端口地址

  主、从8237 DMAC的各个寄存器都是编址在I/O端口空间的。而且其中有些I/O端口地址对于I/O读、写操作有不同的表示含义。如下表示所示:


Slave DMAC’s I/O port        Master DMAC’sI/O port        read        write
0x000        0x0c0        Channel 0/4 的Address Register
0x001        0x0c1        Channel 0/4的Count Register
0x002        0x0c2        Channel 1/5 的Address Register
0x003        0x0c3        Channel 1/5的Count Register
0x004        0x0c4        Channel 2/6的Address Register
0x005        0x0c5        Channel 2/6的Count Register
0x006        0x0c6        Channel 3/7的Address Register
0x007        0x0c7        Channel 3/7的Count Register
0x008        0x0d0        Status Register        Command Register
0x009        0x0d2                Request Register
0x00a        0x0d4                Single Channel Mask Register
0x00b        0x0d6                Mode Register
0x00c        0x0d8                Clear Flip-Flop Register
0x00d        0x0da        Temporary Register        Reset DMA controller
0x00e        0x0dc                Reset all channel masks
0x00f        0x0de                all-channels Mask Register


  各DMA通道的Page Register在I/O端口空间中的地址如下:


DMA channel        Page Register’sI/O port address
0        0x087
1        0x083
2        0x081
3        0x082
4        0x08f
5        0x08b
6        0x089
7        0x08a


  注意两点:

  1. 各DMA通道的Address Register是一个16位的寄存器,但其对应的I/O端口是8位宽,因此对这个寄存器的读写就需要两次连续的I/O端口读写操作,低8位首先被发送,然后紧接着发送高8位。

  2. 各DMA通道的Count Register:这也是一个16位宽的寄存器(无论对于8位DMA还是16位DMA),但相对应的I/O端口也是8位宽,因此读写这个寄存器同样需要两次连续的I/O端口读写操作,而且同样是先发送低8位,再发送高8位。往这个寄存器中写入的值应该是实际要传输的数据长度减1后的值。在DMA传输事务期间,这个寄存器中的值在每次DMA传输操作后都会被减1,因此读取这个寄存器所得到的值将是当前DMA事务所剩余的未传输数据长度减1后的值。当DMA传输事务结束时,该寄存器中的值应该被置为0。

  2.4 DMA通道的典型使用

  在一个典型的PC机中,某些DMA通道通常被固定地用于一些PC机中的标准外设,如下所示:


Channel        Size        Usage
0        8-bit        Memory Refresh
1        8-bit        Free
2        8-bit        Floppy Disk Controller
3        8-bit        Free
4        16-bit        Cascading
5        16-bit        Free
6        16-bit        Free
7        16-bit        Free


  2.5 启动一个DMA传输事务的步骤

  要启动一个DMA传输事务必须对8237进行编程,其典型步骤如下:

  1.通过CLI指令关闭中断。
  2.Disable那个将被用于此次DMA传输事务的DMA通道。
  3.向Flip-Flop寄存器中写入0值,以重置它。
  4.设置Mode Register。
  5.设置Page Register。
  6.设置Address Register。
  7.设置Count Register。
  8.Enable那个将被用于此次DMA传输事务的DMA通道。
  9.用STI指令开中断。

3 Linux对读写操作8237 DMAC的实现

  由于DMAC的各寄存器是在I/O端口空间中编址的,因此读写8237 DMAC是平台相关的。对于x86平台来说,Linux在include/asm-i386/Dma.h头文件中实现了对两个8237 DMAC的读写操作。

  3.1 端口地址和寄存器值的宏定义

  Linux用宏MAX_DMA_CHANNELS来表示系统当前的DMA通道个数,如下:


  #define MAX_DMA_CHANNELS        8


  然后,用宏IO_DMA1_BASE和IO_DMA2_BASE来分别表示两个DMAC在I/O端口空间的端口基地址:


  #define IO_DMA1_BASE        0x00
    /* 8 bit slave DMA, channels 0..3 */
  #define IO_DMA2_BASE        0xC0
    /* 16 bit master DMA, ch 4(=slave input)..7 */


  接下来,Linux定义了DMAC各控制寄存器的端口地址。其中,slave SMAC的各控制寄存器的端口地址定义如下:


#define DMA1_CMD_REG                0x08        /* command register (w) */
#define DMA1_STAT_REG                0x08        /* status register (r) */
#define DMA1_REQ_REG            0x09    /* request register (w) */
#define DMA1_MASK_REG                0x0A        /* single-channel mask (w) */
#define DMA1_MODE_REG                0x0B        /* mode register (w) */
#define DMA1_CLEAR_FF_REG        0x0C        /* clear pointer flip-flop (w) */
#define DMA1_TEMP_REG           0x0D    /* Temporary Register (r) */
#define DMA1_RESET_REG                0x0D        /* Master Clear (w) */
#define DMA1_CLR_MASK_REG       0x0E    /* Clear Mask */
#define DMA1_MASK_ALL_REG       0x0F    /* all-channels mask (w) */


  Master DMAC的各控制寄存器的端口地址定义如下:


#define DMA2_CMD_REG                0xD0        /* command register (w) */
#define DMA2_STAT_REG                0xD0        /* status register (r) */
#define DMA2_REQ_REG            0xD2    /* request register (w) */
#define DMA2_MASK_REG                0xD4        /* single-channel mask (w) */
#define DMA2_MODE_REG                0xD6        /* mode register (w) */
#define DMA2_CLEAR_FF_REG        0xD8        /* clear pointer flip-flop (w) */
#define DMA2_TEMP_REG           0xDA    /* Temporary Register (r) */
#define DMA2_RESET_REG                0xDA        /* Master Clear (w) */
#define DMA2_CLR_MASK_REG       0xDC    /* Clear Mask */
#define DMA2_MASK_ALL_REG       0xDE    /* all-channels mask (w) */


  8个DMA通道的Address Register的端口地址定义如下:


#define DMA_ADDR_0              0x00    /* DMA address registers */
#define DMA_ADDR_1              0x02
#define DMA_ADDR_2              0x04
#define DMA_ADDR_3              0x06
#define DMA_ADDR_4              0xC0
#define DMA_ADDR_5              0xC4
#define DMA_ADDR_6              0xC8
#define DMA_ADDR_7              0xCC


  8个DMA通道的Count Register的端口地址定义如下:


#define DMA_CNT_0               0x01    /* DMA count registers */
#define DMA_CNT_1               0x03
#define DMA_CNT_2               0x05
#define DMA_CNT_3               0x07
#define DMA_CNT_4               0xC2
#define DMA_CNT_5               0xC6
#define DMA_CNT_6               0xCA
#define DMA_CNT_7               0xCE


  8个DMA通道的Page Register的端口地址定义如下:


#define DMA_PAGE_0              0x87    /* DMA page registers */
#define DMA_PAGE_1              0x83
#define DMA_PAGE_2              0x81
#define DMA_PAGE_3              0x82
#define DMA_PAGE_5              0x8B
#define DMA_PAGE_6              0x89
#define DMA_PAGE_7              0x8A


  Mode Register的几个常用值的定义如下:


  #define DMA_MODE_READ        0x44
  /* I/O to memory, no autoinit, increment, single mode */
  #define DMA_MODE_WRITE        0x48
  /* memory to I/O, no autoinit, increment, single mode */
  #define DMA_MODE_CASCADE 0xC0
   /* pass thru DREQ->;HRQ, DACK<-HLDA only */
  #define DMA_AUTOINIT        0x10


  3.2 读写DMAC的高层接口函数

  (1)使能/禁止一个特定的DMA通道

  Single Channel Mask Register中的bit[2]为0表示使能一个DMA通道,为1表示禁止一个DMA通道;而该寄存器中的bit[1:0]则用于表示使能或禁止哪一个DMA通道。

  函数enable_dma()实现使能某个特定的DMA通道,传输dmanr指定DMA通道号,其取值范围是0~DMA_MAX_CHANNELS-1。如下:


static __inline__ void enable_dma(unsigned int dmanr)
{
        if (dmanr<=3)
                dma_outb(dmanr,  DMA1_MASK_REG);
        else
                dma_outb(dmanr & 3,  DMA2_MASK_REG);
}


  宏dma_outb和dma_inb实际上就是outb(或outb_p)和inb函数。注意,当dmanr取值大于3时,对应的是Master DMAC上的DMA通道0~3,因此在写DMA2_MASK_REG之前,要将dmanr与值3进行与操作,以得到它在master DMAC上的局部通道编号。

  函数disable_dma()禁止一个特定的DMA通道,其源码如下:


static __inline__ void disable_dma(unsigned int dmanr)
{
        if (dmanr<=3)
                dma_outb(dmanr | 4,  DMA1_MASK_REG);
        else
                dma_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
}


  为禁止某个DMA通道,Single Channel Mask Register中的bit[2]应被置为1。

  (2)清除Flip-Flop寄存器

  函数Clear_dma_ff()实现对slave/Master DMAC的Flip-Flop寄存器进行清零操作。如下:


static __inline__ void clear_dma_ff(unsigned int dmanr)
{
        if (dmanr<=3)
                dma_outb(0,  DMA1_CLEAR_FF_REG);
        else
                dma_outb(0,  DMA2_CLEAR_FF_REG);
}


  (3)设置某个特定DMA通道的工作模式

  函数set_dma_mode()实现设置一个特定DMA通道的工作模式。如下:


static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
{
        if (dmanr<=3)
                dma_outb(mode | dmanr,  DMA1_MODE_REG);
        else
                dma_outb(mode | (dmanr&3),  DMA2_MODE_REG);
}


  DMAC 的Mode Register中的bit[1:0]指定对该DMAC上的哪一个DMA通道进行模式设置。

  (4)为DMA通道设置DMA缓冲区的起始物理地址和大小

  由于8237中的DMA通道是通过一个8位的Page Register和一个16位的Address Register来寻址位于系统RAM中的DMA缓冲区,因此8237 DMAC最大只能寻址系统RAM中物理地址在0x000000~0xffffff范围内的DMA缓冲区,也即只能寻址物理内存的低16MB(24位物理地址)。反过来讲,Slave/Master 8237 DMAC又是如何寻址低16MB中的物理内存单元的呢?

  首先来看Slave 8237 DMAC(即第一个8237 DMAC)。由于Slave 8237 DMAC是一个8位的DMAC,因此DMA通道0~3在一次DMA传输操作(一个DMA传输事务又多次DMA传输操作组成)中只能传输8位数据,即一个字节。Slave 8237 DMAC将低16MB物理内存分成256个64K大小的页(Page),然后用Page Register来表示内存单元物理地址的高8位(bit[23:16]),也即页号;用Address Register来表示内存单元物理地址在一个Page(64KB大小)内的页内偏移量,也即24位物理地址中的低16位(bit[15:0])。由于这种寻址机制,因此DMA通道0~3的DMA缓冲区必须在一个Page之内,也即DMA缓冲区不能跨越64KB页边界。

  再来看看Master 8237 DMAC(即第二个8237 DMAC)。这是一个16位宽的DMAC,因此DMA通道5~7在一次DMA传输操作时可以传输16位数据,也即一个字word。此时DMA通道的Count Register(16位宽)表示以字计的待传输数据块大小,因此数据块最大可达128KB(64K个字),也即系统RAM中的DMA缓冲区最大可达128KB。由于一次可传输一个字,因此Master 8237 DMAC所寻址的内存单元的物理地址肯定是偶数,也即物理地址的bit[0]肯定为0。此时物理内存的低16MB被化分成128个128KB大小的page,Page Register中的bit[7:1]用来表示页号,也即对应内存单元物理地址的bit[23:17],而Page Register的bit[0]总是被设置为0。Address Register用来表示内存单元在128KB大小的Page中的页内偏移,也即对应内存单元物理地址的bit[16:1](由于此时物理地址的bit[0]总是为0,因此不需要表示)。由于Master 8237 DMAC的这种寻址机制,因此DMA通道5~7的DMA缓冲区不能跨越128KB的页边界。

  下面我们来看看Linux是如何实现为各DMA通道设置其Page寄存器的。NOTE!DMA通道5~7的Page Register中的bit[0]总是为0。如下所示:


static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
{
        switch(dmanr) {
                case 0:
                        dma_outb(pagenr, DMA_PAGE_0);
                        break;
                case 1:
                        dma_outb(pagenr, DMA_PAGE_1);
                        break;
                case 2:
                        dma_outb(pagenr, DMA_PAGE_2);
                        break;
                case 3:
                        dma_outb(pagenr, DMA_PAGE_3);
                        break;
                case 5:
                        dma_outb(pagenr & 0xfe, DMA_PAGE_5);
                        break;
                case 6:
                        dma_outb(pagenr & 0xfe, DMA_PAGE_6);
                        break;
                case 7:
                        dma_outb(pagenr & 0xfe, DMA_PAGE_7);
                        break;
        }
}


  在上述函数的基础上,函数set_dma_addr()用来为特定DMA通道设置DMA缓冲区的基地址,传输dmanr指定DMA通道号,传输a指定位于系统RAM中的DMA缓冲区起始位置的物理地址。如下:


/* Set transfer address & page bits for specific DMA channel.
* Assumes dma flipflop is clear.
*/
static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
{
        set_dma_page(dmanr, a>;>;16);
        if (dmanr <= 3)  {
            dma_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
        dma_outb( (a>;>; & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
        }  else  {
            dma_outb( (a>;>;1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
            dma_outb( (a>;>;9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
        }
}


  函数set_dma_count()为特定DMA通道设置其Count Register的值。传输dmanr指定DMA通道,传输count指定待传输的数据块大小(以字节计),实际写到Count Register中的值应该是count-1。如下所示:


static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
{
    count--;
        if (dmanr <= 3)  {
            dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
            dma_outb( (count>;>; & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
    } else {
            dma_outb( (count>;>;1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
            dma_outb( (count>;>;9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
    }
}


  函数get_dma_residue()获取某个DMA通道上当前DMA传输事务的未传输剩余数据块的大小(以字节计)。DMA通道的Count Register的值在当前DMA传输事务进行期间会不断地自动将减小,直到当前DMA传输事务完成,Count Register的值减小为0。如下:


static __inline__ int get_dma_residue(unsigned int dmanr)
{
        unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
        : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;

        /* using short to get 16-bit wrap around */
        unsigned short count;

        count = 1 + dma_inb(io_port);
        count += dma_inb(io_port) << 8;

        return (dmanr<=3)? count : (count<<1);
}


  3.3 对DMAC的保护

  DMAC是一种全局的共享资源,为了保证设备驱动程序对它的独占访问,Linux在kernel/dma.c文件中定义了自旋锁dma_spin_lock来保护它(实际上是保护DMAC的I/O端口资源)。任何想要访问DMAC的设备驱动程序都首先必须先持有自旋锁dma_spin_lock。如下:


static __inline__ unsigned long claim_dma_lock(void)
{
        unsigned long flags;
        spin_lock_irqsave(&dma_spin_lock, flags); /* 关中断,加锁*/
        return flags;
}

static __inline__ void release_dma_lock(unsigned long flags)
{
        spin_unlock_irqrestore(&dma_spin_lock, flags);/* 开中断,开锁*/
}


4 Linux对ISA DMA通道资源的管理

  DMA通道是一种系统全局资源。任何ISA外设想要进行DMA传输,首先都必须取得某个DMA通道资源的使用权,并在传输结束后释放所使用DMA通道资源。从这个角度看,DMA通道资源是一种共享的独占型资源。

  Linux在kernel/Dma.c文件中实现了对DMA通道资源的管理。

  4.1 对DMA通道资源的描述

  Linux在kernel/Dma.c文件中定义了数据结构dma_chan来描述DMA通道资源。该结构类型的定义如下:


struct dma_chan {
        int  lock;
        const char *device_id;
};


  其中,如果成员lock!=0则表示DMA通道正被某个设备所使用;否则该DMA通道就处于free状态。而成员device_id就指向使用该DMA通道的设备名字字符串。

  基于上述结构类型dma_chan,Linux定义了全局数组dma_chan_busy[],以分别描述8个DMA通道资源各自的使用状态。如下:


static struct dma_chan dma_chan_busy[MAX_DMA_CHANNELS] = {
        { 0, 0 },
        { 0, 0 },
        { 0, 0 },
        { 0, 0 },
        { 1, "cascade" },
        { 0, 0 },
        { 0, 0 },
        { 0, 0 }
};


  显然,在初始状态时除了DMA通道4外,其余DMA通道皆处于free状态。

  4.2 DMA通道资源的申请

  任何ISA卡在使用某个DMA通道进行DMA传输之前,其设备驱动程序都必须向内核提出DMA通道资源的申请。只有申请获得成功后才能使用相应的DMA通道。否则就会发生资源冲突。

  函数request_dma()实现DMA通道资源的申请。其源码如下:


int request_dma(unsigned int dmanr, const char * device_id)
{
        if (dmanr >;= MAX_DMA_CHANNELS)
                return -EINVAL;

        if (xchg(&dma_chan_busy[dmanr].lock, 1) != 0)
                return -EBUSY;

        dma_chan_busy[dmanr].device_id = device_id;

        /* old flag was 0, now contains 1 to indicate busy */
        return 0;
}


  上述函数的核心实现就是用原子操作xchg()让成员变量dma_chan_busy[dmanr].lock和值1进行交换操作,xchg()将返回lock成员在交换操作之前的值。因此:如果xchg()返回非0值,这说明dmanr所指定的DMA通道已被其他设备所占用,所以request_dma()函数返回错误值-EBUSY表示指定DMA通道正忙;否则,如果xchg()返回0值,说明dmanr所指定的DMA通道正处于free状态,于是xchg()将其lock成员设置为1,取得资源的使用权。

  4.3 释放DMA通道资源

  DMA传输事务完成后,设备驱动程序一定要记得释放所占用的DMA通道资源。否则别的外设将一直无法使用该DMA通道。

  函数free_dma()释放指定的DMA通道资源。如下:


void free_dma(unsigned int dmanr)
{
        if (dmanr >;= MAX_DMA_CHANNELS) {
                printk("Trying to free DMA%d
", dmanr);
                return;
        }

        if (xchg(&dma_chan_busy[dmanr].lock, 0) == 0) {
                printk("Trying to free free DMA%d
", dmanr);
                return;
        }

} /* free_dma */


  显然,上述函数的核心实现就是用原子操作xchg()将lock成员清零。

  4.4 对/proc/dma文件的实现

  文件/proc/dma将列出当前8个DMA通道的使用状况。Linux在kernel/Dma.c文件中实现了函数个get_dma_list()函数来至此/proc/dma文件的实现。函数get_dma_list()的实现比较简单。主要就是遍历数组dma_chan_busy[],并将那些lock成员为非零值的数组元素输出到列表中即可。如下:


int get_dma_list(char *buf)
{
        int i, len = 0;

        for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) {
                if (dma_chan_busy.lock) {
                    len += sprintf(buf+len, "%2d: %s
",
                                   i,
                                   dma_chan_busy.device_id);
                }
        }
        return len;
} /* get_dma_list */


5 使用DMA的ISA设备驱动程序

  DMA虽然是一种硬件机制,但它离不开软件(尤其是设备驱动程序)的配合。任何使用DMA进行数据传输的ISA设备驱动程序都必须遵循一定的框架。

  5.1 DMA通道资源的申请与释放

  同I/O端口资源类似,设备驱动程序必须在一开始就调用request_dma()函数来向内核申请DMA通道资源的使用权。而且,最好在设备驱动程序的open()方法中完成这个操作,而不是在模块的初始化例程中调用这个函数。因为这在一定程度上可以让多个设备共享DMA通道资源(只要多个设备不同时使用一个DMA通道)。这种共享有点类似于进程对CPU的分时共享:-)

  设备使用完DMA通道后,其驱动程序应该记得调用free_dma()函数来释放所占用的DMA通道资源。通常,最好再驱动程序的release()方法中调用该函数,而不是在模块的卸载例程中进行调用。

  还需要注意的一个问题是:资源的申请顺序。为了避免死锁(deadlock),驱动程序一定要在申请了中断号资源后才申请DMA通道资源。释放时则要先释放DMA通道,然后再释放中断号资源。

  使用DMA的ISA设备驱动程序的open()方法的如下:


int xxx_open(struct inode * inode, struct file * filp)
{
     ┆
   if((err = request_irq(irq,xxx_ISR,SA_INTERRUPT,”YourDeviceName”,NULL))
                return err;
        if((err = request_dma(dmanr, “YourDeviceName”)){
                free_irq(irq, NULL);
                return err;
        }
        ┆
        return 0;
}


  release()方法的范例代码如下:


void xxx_release(struct inode * inode, struct file * filp)
{
        ┆
        free_dma(dmanr);
        free_irq(irq,NULL);
        ┆
}


  5.2 申请DMA缓冲区

  由于8237 DMAC只能寻址系统RAM中低16MB物理内存,因此:ISA设备驱动程序在申请DMA缓冲区时,一定要以GFP_DMA标志来调用kmalloc()函数或get_free_pages()函数,以便在系统内存的DMA区中分配物理内存。

  5.3 编程DMAC

  设备驱动程序可以在他的read()方法、write()方法或ISR中对DMAC进行编程,以便准备启动一个DMA传输事务。一个DMA传输事务有两种典型的过程:(1)用户请求设备进行DMA传输;(2)硬件异步地将外部数据写道系统中。

  用户通过I/O请求触发设备进行DMA传输的步骤如下:

  1.用户进程通过系统调用read()/write()来调用设备驱动程序的read()方法或write()方法,然后由设备驱动程序read/write方法负责申请DMA缓冲区,对DMAC进行编程,以准备启动一个DMA传输事务,最后正确地设置设备(setup device),并将用户进程投入睡眠。

  2.DMAC负责在DMA缓冲区和I/O外设之间进行数据传输,并在结束后触发一个中断。

  3.设备的ISR检查DMA传输事务是否成功地结束,并将数据从DMA缓冲区中拷贝到驱动程序的其他内核缓冲区中(对于I/O device to memory的情况)。然后唤醒睡眠的用户进程。

  硬件异步地将外部数据写到系统中的步骤如下:

  1.外设触发一个中断通知系统有新数据到达。

  2.ISR申请一个DMA缓冲区,并对DMAC进行编程,以准备启动一个DMA传输事务,最后正确地设置好外设。

  3.硬件将外部数据写到DMA缓冲区中,DMA传输事务结束后,触发一个中断。

  4. ISR检查DMA传输事务是否成功地结束,然后将DMA缓冲区中的数据拷贝驱动程序的其他内核缓冲区中,最后唤醒相关的等待进程。

  网卡就是上述过程的一个典型例子。

  为准备一个DMA传输事务而对DMAC进行编程的典型代码段如下:


  unsigned long flags;
  flags = claim_dma_lock();
  disable_dma(dmanr);
  clear_dma_ff(dmanr);
  set_dma_mode(dmanr,mode);
  set_dma_addr(dmanr, virt_to_bus(buf));
  set_dma_count(dmanr, count);
  enable_dma(dmanr);
  release_dma_lock(flags);


  检查一个DMA传输事务是否成功地结束的代码段如下:


        int residue;
        unsigned long flags = claim_dma_lock();
        residue = get_dma_residue(dmanr);
        release_dma_lock(flags);
        ASSERT(residue ==  0);


  注:本节大部分内容来自于ldd2

论坛徽章:
0
23 [报告]
发表于 2003-04-23 20:35 |只看该作者

linux内核分析(转自某位大哥网上的笔记)



linux网络部分重要结构体联系图(?)

用\续行, NR

请问ENTRY( ... ) 语法

在中断例程中如何与其他进程通讯??(用信号量还是全局变量)

内核模块编译需要优化

About task->;active_mm

驱动程序怎样锁定内存

linux 2.4.x initialization for IA-32 howto

Booting Linux for IA64

About task->;active_mm (bnn 续)

About Our China's CPU-Fang Zhou

我在你的帖子中注释了一下,不一定对.

RTL8139 驱动程序解析(转)

Sun YongYao--发送、接受、转发包处理结构框图修正

Linux内核分析文档计划

windowsXP和linux在系统结构上谁更好?

TCP协议的核心守护进程echod

请教一个中断方面的问题

再谈page cache和buffer cache

稀疏文件是怎么的概念呢

请教frees/wan的原理问题

块设备文件和普通文件有什么区别?普通文件不也是放在块设备上的吗?

关于I/O请求优化

请教一个MBR的问题

page cache与buffer cache的关系。

请问系统中有几个针对磁盘读写的request队列?

TCP传输控制块的初始状态

net_rx()网络数据流向

这样的内核程序能阻塞吗

Linux设备驱动程序的中断

页故障的处理过程

网卡的初始化过程

2.4内核网络部分的初始化

2.4网络代码阅读笔记(1)

2.4网络代码阅读笔记(2)

2.4网络代码阅读笔(3)

2.4网络代码阅读笔(4)

2.4网络代码阅读笔记(5)

RAM DISK 和 DiskOnChip 有什么关系?

文件映射区域的分配方式

未经accept的socket是如何处理数据的?

如何对拷不同长度的socket缓冲区?

Linux内核地址空间的布局

netfilter一问

请教GDT

我非得用SMP吗?

关于LDT的疑问

请教一个tcp连接性能的问题?

能解释一下A20地址线是怎么回事吗?为何要打开?

如何显示GDT,IDT,LDT表的内容

物理内存的分配结构

重入的疑惑

高端页面的映射

2.4.1内核中页结构PG_refrenced标志什么时候置位?

怎样在内核中写文件?

一些问题(网络方面)

网卡驱动程序(inw,insw提问)

向所有做内核分析的朋友提个问题

netfilter这里还是不明白

交换页分配方法

在网卡驱动程序中如何实现包转发?

请教一个内核寻址的问题

非分页、连续内存?

FreeBSD内核文件的结构

FreeBSD内核的编绎方法

virtual address to physical address - HOWTO?

关于printk的一个问题:

关于内存管理的一个问题

如何加一个文件系统到内核中

如何实现临界区

关于引导程序问题

不让root process使用1024以下的端口

get_current()的问题

hard_smp_processor_id()与smp_processor_id()有什么区别?

新兵笔记--ULK(C3) Exception Handing

TCP包处理的后备队列(backlog)和预备队列(prequeue)

解释一下__wait_queue_head结构?还有wake_up

TCP包的校验和

内核日志和内核控制台

minix文件系统的物理结构

关于buddy system的几个问题?

void page_cache_init(u_long mempages)

信号能否重入?

static __inline__和extern __inline__有什么区别?

void __remove_shared_vm_struct(vma)

spinlock

TCP PAWS处理

About Major Number

linux内核启动到底做了什么的资料

listen和accept过程的简要描述

真正的信号高手请进

有关页寿命的疑问

完了,没耐心看了,大侠帮忙,给我讲一下tcp_connect就好!

linux中如何设置stack的大小?

关于struct

GET_CURRENT还有疑问

谁有ARM远程调试的stub的源代码

[精华] 辞职申明 和 学习内核的一些感想

分析calibrate_delay过程

请教内存初始化的问题(reserve mem)

详细解释一下Thread(线程)???

linux 支持内核线程吗


asmlinkage
http://www.kernelnewbies.org/faq/index.php3#asmlinkage.xml




linuxdoc.org的对于Linux线程的一个比较完整的回答

行内汇编中,"o"(var)(不是零)"o"是什麽寄存器,谢谢!

如何在模块中增加系统调用

red black tree

iptables内核数据结构关系图

[serial]中断问题?

console注册与tty注册的区别

make_pages_present(),不知它的具体作用是什么

宏mb()是什么意思?

这是我搜集的linuxkernel兄的大作

linuxkernel兄大作之2

TCP层向外发包时为什么总是将skb进行克隆?

内核防火墙iptables的一条规则(图)

struct dentry中各项意义

关于read_super_block 的一点疑问!

端口读硬盘信息疑问

asmlinkage这个关键字是什么意思

fork()与vfork()的区别

pg0 的问题?

Linux的启动盘与DOS中的启动盘不一样

__attribute__是什么东西,怎么用呀


800 种文件格式
http://www.wotsit.org/default.asp


在linux下读取、修改(如果可能)主板bios的内容

制作基于软盘的Linux系统

调试信息过多造成dmesg无法完全显示怎么办?

Ctrl-D被按下后,产生什么信号?或者根本不产生信号?

关于中断响应

linux内核概念问题,欢迎讨论

介绍一下e820 map的内容

新兵笔记--ULK(C4) Initializing the idt

_set_gate分析

Linux A-Z书中实例的源程序

关于end_mem的一点疑惑

新兵笔记--ULK(C2) beta版

防火墙分析总结

网络包复制

head.S 中的问题

现转载对我帮助很大的文件,十分感谢那位作者!!!

关于MBR的一个问题

ELF的 e_ident[EI_NIDENT]是什么意思?

Makefile中Config.in是什麽文件

virtual address space and physical address

time quantum

Lisoleg的昨天、今天和明天

System.map中的几个标志T,t,B,b,..的问题

内存初始化mem_init中的两个问题


ldd2
Chapter 9: Interrupt Handling
http://www.xml.com/ldd/chapter/book/pdf/ch09.pdf
C & C

mmap
http://kernelnewbies.org/code/mmap/



内核代码可以读取文件或共享内存吗?

内核镜像是如果映射到3G去的?

进程的页目录表中的768项之后的项是不是都是有效的?

内核页目录

关于进程内存空间的映射问题*

Special expression from linux-kernel mailing list

discussion about MaxNumber Of Threads From KernelT

核心态对用户态的数据访问

内核是怎么访问PCI配置空间的?

这么做行不?(请大伙抽空看看)内核中共享内存的如何使用

which Compiler to Use for kernel compiling

GLIBC被多个进程共享疑问

fork()一个子进程时,IPC资源是否可以被子进程继承

malloc()在内核中对应的函数是什么

支持热插拔的驱动程序的框架疑问

回答“关于页面映射计数”

关于内核中加入自己得代码得可行性

用户空间和内核空间之间的数据传输

为什么需要copy_from_user?(转载)

内核启动过程问题(rush老哥看过来,我知道你看过启动代码)

软中断图解

早期的任务切换

谁能说一下iptables.c 和 netfilter.c 的关系?

最近看mm的人很多啊,和大家分享我给自己写的教程

一个疑问 --《Understanding Linux Kernel》

请教linux源代码中的数组问题

skb_reserve - adjust headroom

UNIX核心介绍

分配虚存空间有了mmap和munmap为什么还需要sys_brk?

Write Your Own Operating System Tutorial && FAQ !

some valuable HowtoS for KernelStudy

To get intelX86 docs

如何修改IP流程中的数据包???

请问怎样让我的一个可执行程序在开机过程中自动执行

关于ctags的问题?

关于copy sk_buff的问题

Kernel2.4.18的交换机制分析

系统初启时中断向量表放在哪里

swap in (2.4.0)

handle mm fault (2.4.0)

swap out for Kernel2.4.0

实时进程的时间片赋值问题?

关于驱动程序与实际设备的关联问题

本论坛关于时钟的一个悬而未决的问题

A20是什么东西?

bootsect.s和setup.s问题集锦


bios ox15中断ah=e801
http://www.ctyme.com/intr/int.htm


gas 文档
http://www.gnu.org/manual/gas-2.9.1/


用什么办法可以将系统的gdt给显示出来?

这么生动的赋值方法

在0x104000处的硬件参数表的详细说明

转贴一篇关于mm的文章。

这不是自己覆盖自己吗

do_irq()的问题

misc两个head.s, end, __PAGE_OFFSET

关于interrup和exception

一个setup.S与head.S连接的问题?

终于独立看懂了一个内嵌汇编,兼问个问题

draft BIOS use document for the kernel(里面有讲e820)

start_arch中copy e820_map的问题

2.2的一些task数据结构在2.4里是什么?

关于bottom half

mem_map array

__init 在那儿定义的

有个prototype用了pgprot来做变量。刚好pgprot_t的数据结构定义里又用了pgprot

fixed_addresses 的排列

how to smp

空闲页面free_area结构初试话一问?

setup_arch中的reserve resource!

slab里的free buffer

list_entry的疑惑

linux内核中的同步和互斥专题 (1)

linux内核中的同步和互斥专题(2)

setup_arch()中PFN_UP,PFN_DOWN,PFN_PHYS这三个函数是什么意思

cache_cache里的slab的大小是不是一个page

几个变量的意思(page,mm)

remap_page_range()的疑问!!??

start_kernel 里的 init_modules()问题

linux 内核原代码汇编中 .align 伪指令的意思是什么?

关于task_union

多个内核问题提问

请问关于页计数和页的使用情况的关系的一个问题?

CR3问题?

Linux字符设备基础(转贴)

又是start_kernel里的变量定义问题

ioremap是干什么用的?

Makefile :这行为什麽要有( )

关于flash的一些问题!

100个最佳Linux站点(推荐)

判断process是在user mode还是在kernel mode的标准是什么?

关于ext2的几个问题

谁知道unistd.h里的这段解释是什么意思

关于skbuff得资料

bdata.last_offset和last_pos在何处初始化?

内存管理问题?空闲页的bitmap是干什么的?

noncontiguous memory究竟指的是什么?

再聊聊free_area的bitmap

关于gcc内嵌汇编的一个问题

对bh_base[32]和bh_task_vec[32]的一些猜测

明白了free_area的bitmap了!

软中断softirq

路由问题


http://linux-mm.org/



super block是用来干什么的

研读Linux内核主要是为了做些什么?

Linux内核抢占补丁的基本原理

page描述符起名page,确实不好

请教一个术语--”堆“

#if 1肯定是满足条件,else后面的有什么用

内存管理中常常见到“round up”,它具体是什么意思呢?

我也来问几个关于gcc内嵌汇编的问题

"aka inode"? that is "as know as inode"

谁知道”16M以上的低位物理内存“到底有多大?占了多少百分比物理内存

如何做源程序的补丁?

local_table是什么?在哪里初始化的

汇编call命令调用C函数时,参数是如何通过stack传递的

一段boot的测试代码,有问题,来看看……

读do_basic_setup时碰到的问题(pci)

start_kernel里面的prof_shift干什么用的

HA开发,增强内核,学习好方式

关于spin_lock

vfs的索引节点号i_ino是怎么管理的

ip_route_input

想听听大家是怎么读核的

我的分析是应该首先发送第一片

谈一谈我的内核精简计划,以及目前的进展情况

IP分片与重组的分析与整理

“Practical Unix & Internet Security"。号称是”圣经”式著作

Linux源代码中的几个缩写

几个网络有关的变量

为什么不立刻用长跳转指令重载CS段寄存器呢

当物理空间的的线性地址>;1G的时候,虚拟空间如何解决

请教关于睡眠和唤醒进程的两个函数...

如何读取系统物理内存

freeswan是什么东西呢?

ip_rcv_finish函数一问

inflate.c文件的fill_inbuf()函数中insize的赋值的问题

裁减Linux内核的心得体会

linux下的一个文件的最大尺寸是多少?由什么决定?windows下呢?

请教一个Netfilter的应用问题

使用register_blkdev( ), 做完insmod后,为什么/proc/devices没有我的块设备

应用层->;pci->;disk,这种情况disk的驱动该如何写?

请教一个内存管理问题(挺典型的一个问题)

快速找到connect,socket函数实现的代码

致地讲一下IP_FORWARD那个函数

如何在内核中唤醒和睡眠用户进程??

如何打开.patch文件?

关于IP_FRAGMENT的问题

How It Works: DOS Floppy Disk Boot Sector

How It Works -- Master Boot Record

Minix代码分析之一:引导扇区代码

同一程序加载执行空间分布一样吗?

锁和信号量

内核与根文件系统

读kernel时容易漏掉的几个细节

推荐课题及"目的"

devfs_entry是干什么用的

2.2里的vfsmntlist,2.4改什么了

如何直接向网卡读写数据包?

如何在内核中加入PF_KEY套接字?

enable_irq(),disable_irq().和cli(),sti()之间有什么区别

关于slip模块中使用ioperm

gfp是什么的缩写阿?

关于中断例程中的子进程睡眠问题

连续空间分配的大小问题!

skb->;data为物理地址。为何在第一句中又进行转换

可加载模块写文件出现的奇怪现象 (程序设计经验)

SYMBOL_NAME( )

zone_struct

关于物理地址和虚拟地址的问题

请问linux文件系统层次结构的问题

kmalloc(size)返回的是物理地址,还是虚拟地址

VFS初始化过程中的一些问题

how to use create_proc_info_entry

中断上下文,进程上下文和任务上下文之间的区别---需要进一步深入

混杂模式

video adapter's ROM

本论坛和mailing list的区别!

很高兴能为大家服务, 及一些想法,大伙来参谋参谋

mkfs和fdisk的根本区别在哪儿?



amp - bios 资料
http://spr2.net/up_loader.php


内核等待队列机制介绍
http://www.linuxaid.com.cn/engineer/ideal/kernel/wait_queue.htm
linuxaid的网友ideal竹叶收藏




bootsect.s把大内核复制到高端内存的时候,还是实模式.如何实现的

page-》list

OWNOS操作系统设计书

need_resched 是怎么使用的

请教高手一个关于网络全局变量dev_base的问题

关于页面映射计数的讨论

free_area_init_core对其中struct page的virtual赋值为当前struct page所描述的物理页框的内核虚地址

再和4-1的反做与运算得到的又是什么呢?

__init , __exit , module_init, module_exit是什么意

写个小的OS项目,如何?加之一些感想(完全兴趣与学习目的)

mem_map数组

怎么解决这个include头文件时出现的矛盾

内核命令行是何时在何处传递给内核的

A20是什么?

关于brk与mmap的问题--已解决见另外一个帖子

在mm中,vm_area_struct为什么只用了单链表?

为什么要copy_from_user?

关于网络中接收软中断(net_rx_action)的问题

对UDP包在对包不做任何改变的情况下用udp_check()函数重新计算,结果与原校验和不符?

怎么初始化一个PCI设备?
[目录]

--------------------------------------------------------------------------------


list5



关于queue_task的一个问题


打造软盘上的linux
http://www.linuxfromscratch.org/ to define your own OS distribution.
www.linuxdoc.org to get howtos you want


可以参见下面链接处:
http://www.linuxeden.com/edu/doctext.php?docid=1582
Linux内核调试技术介绍 :)希望有帮助

我根据这个
从源代码打造一个最小化的Linux系统实作篇
http://www.linux.org.tw/CLDP/gb/mini/BuildMin.html#toc6
编linux,但不知道如何安装到指定路径


为你的Linux快速编译所需要的模块
by 刘军民 (fancao0515@0451.com)
http://www-900.ibm.com/developerWorks/linux/l-tip-prompt/tip13/index.shtml





copy_e820_map()问题

合并相邻区函数merge_segments()--2.0.33

关于module的问题

关于卖广告和我对linux的一点意见

timer_interrupt()函数看不明白,请指点

如何驱动键盘灯?

schedule(void)函数一定是可以重入的,对吗?

mmap (2.4.0)

Linux: Using Video RAM as System RAM

Linux: -aa VM in 2.5

一个linux驱动程序的问题

大侠指点一下get_pid的算法?

怎样修改PIPE_BUF的大小限制

操作系统理论的探索 (序言部分)

问题出在你新编译的内核不支持模块的版本识别

版本2.4.16下path_init和path_walk,link_path_walk分析报告

怎么理解记录块缓冲区的内容是一致的?

mark_bh(TIMER_BH)和timer_bh( )

当今日新月异,“对象”横飞,潜读LINUX源码除了提高自身素质外还有哪些令人兴奋的应用前景

一个困扰很久的问题--paging_init()

Linux核心调试环境的搭建

磁盘扇区与磁盘块如何定义以及如何区分使用?

也表处理宏的定义释疑

为什么学习LINUX源码、学到什么程度及怎样学习才能在最短的时间里取得最大的收获?

关于时间中断的一个问题

事物总是从陌生开始认识

关于/dev/shm

怎么在本机上配置一个lxf看源代码?在下对apache网络配置一窍不通

哪位知道哪有/proc的手册么

请问叶框0(0 ~ 4K物理地址空间)是否一直未使用?

剖析Linux任务切换的细节。

请问linux下有没有好的看源码的工具?

system call

低1G虚存是做什么的?

bootsect,setup,head的总结

增加系统调用的血汗经验 贡献给大家

How to use ramfs ???

能否将framebuffer的源码说一下

entry.S(续)

谁知道系统刚启动时BIOS建立的参数表

指点一下《Understanding the Linux Kernel》中的难点

Linux: O(1) Update For 2.4

links4RealtimeLinux

A new era: Carrier-grade Linux for Telecommunicati

lwIP - A Lightweight TCP/IP Stack

sys_arch interface for lwIP 0.5

Raw TCP/IP interface for lwIP 0.5

links4EmbededLinux

man slabinfo , 对其中的SMP部分不得其解

请教一个关于Linux处理外设中断的问题

异常处理函数的压栈

使用VIDEO_CHAR检查内核启动时在何处挂起

为什么用files->;fd[fd]而不用files->;fd_array[fd]

Linux 下网卡混杂模式

修改时间片DEFAUT_PRIORITY,为什么当系统

Lan网卡收到包后,应该比较mac地址。

如果手工触发request_irq登记的中断服务

请介绍关于cacheline相关知识,比方cacheline_pingpong

网络包的接收过程

关于pt_regs

How the PCI Hot Plug Driver Filesystem


iptable用户空间和内核关系的问题?

LINUX文件系统分析草稿--面向微内核的OS设计

希望大家讨论讨论?我们学源码要学到什么时候才能收手?

中国有多少人在做关于kernel的开发(真遗憾偶挖了坑没有人跳进来)

Linux内核中对硬盘控制的有关资料

head.s 中“jmp 1f”的1f是什么意思?

how to get size fo ram?

谈谈自已所尝试的内核分析方法

linux中进程与线程的问题

如何在LKM中执行一个用户空间的程序

为什么32位的系统不支持大于2G的文件?

Linux上是否有类似winsock2上的SPI相对应的接口层?

请问如何驱动这个怪物

用双网卡如何同时传输数据(?)

在内核中如何进行大空间内存的分配??

请帮忙修改程序(do you like this?)

关于Login的一个问题(basic)

offsetof怎么理解

为什么每个磁道有63个扇区,而不是64个

ldd2的Backward Compatibility章节

LDD第三章的一个问题

如何根据pid得到进程的名称

如何将内核编译成无版本检查的呢

about init section (vmlinux.lds)

udp报文转发不了,而icmp报文可以,为什么(undstand it?)

张贴一个别人推荐的很好的内核线程的例子

2.4.16软中断分析图 (again)

about interrupt number : 15 or 16

关于引用内核输出符号的问题

cache不命中的情况

请教/proc/pci(有个pci图)

连续内存与离散内存的问题

请问怎样能够得到一个进程的所有的通讯流量

如何让root不能修改其他用户的口令?

slab对象的地址可以不通过页表映射吗?

atomic_fool_gcc的作用是什么?如果不加gcc可能怎么处理?为什么2.4中没有了

关于缺叶中断的内存管理1

slab对象的地址可以不通过页表映射吗(...?)

about "jmp *%eax

insmod的模块放在哪里?

linux smp 求救

8259A可编程控制器在linux上的初始化

在网络层构造UDP包好像不太合理

如何将内核中printk的输出到屏幕上

Linux在i386处理器在PAE模式下寻址

shell系统流程(哈哈)

网上那有关于a20线的详细介绍

调度 schedule 概念

zone balance 是何意

多一些供献,少一些..

大家看看,是不是《情景分析》说错了?(文件读写)

欢迎calfe,garycao加入版面管理



裁减libc的两个工具
一个是Montavista公司的lib优化工具
基本思想是扫描你的应用程序的库函数调用.将你的应用程序没有用到的库函数删除.
一个是IBM组织的一个minilibc project
http://www-124.ibm.com/developer/opensource/linux/projects/minilibc/


这儿摘录了其中的几个非正式观点,共享.

Some write for the fun/eduction of it and want to to it all.
Some have ego problems and must do it all.
Some do not know how to adapt existing code so they do it all.
Some have really wierd systems with nothing close so must do it all.
Some have not searched enough to know of simulair systems so must do it all.
Some have ethical/comercial problems with licenceses and must do it all.
Some rename code and say he did it all.
Some DO use existing code.



uclinux 分析
http://hhcn.org/uclinux.html


gnu/hurd 介绍
http://www.gnu.org/software/hurd/


几个手册
http://www.refcards.org


netlink socket资料
http://qos.ittc.ukans.edu/netlink/html/


截包零拷贝能不能实现

收集内核FAQ了! 大家如在版面上发现适合的话题请转载一份贴在这儿

local_irq_disable()在smp下究竟是关了所有处理器的中断还是当前处理器中断

读setup.s中的几个问题(openarm的几个连接)

spinlock的设计和实现

在linux中一个进程如何修改其它进程的数据(关注)

Linux的页式内存内存管理

head.S 分析

内核信号量的简单演示(几个进程并发调用down的情况 ppt)

i386内存结构示意图(intel and mine)

内存观点(2.4.0)(精华收集和自己的一点理解)

如何关闭linux的单用户模式

flush_tlb_xxx()这类函数都是干什么用的

设备初始化问题(basic)

System.map有什么用处?

Linux 内核笔记 -- 信号

如何读取指定硬盘扇区号的扇区数据?

关于swapper的问题

linus关于debug tools的一篇旧帖子

What is the meaning of "volatile"?

重新编译内核后不支持VFAT的中文文件名?(内核?)

忙里偷闲:Slab简要分析(一张图)

volatile的含义

kgdb文档

引导与启动部分之head.s部分的注释

系统引导与启动(suzhe前辈的一次报告)-----by linux3-III

系统引导与启动之深入lilo-----(zz by linux3-III)

有那位大虾做过内核裁减

jiffies耗尽后会发生什么

ip层及tcp层的处理究竟谁在做

关于tcp/ip不明白的地方

请问在Linux下如何得知每个CPU的使用率等信息

[ jkl ]__attribute__

问几个很弱地问题...

Ext2 文件系统的硬盘布局

如何修改或去掉以framebuffer方式启动的内核的小企鹅的标志

__copy_user的实现原理

boot loader 的一些研究

ip数据包接收发送

Linux的存储管理(一)

内核启动时传入的参数存放在甚么位置

编译linux内核及注意事项(支持ipv6)(看起来步骤详细)

我是怎样精通了linux内核的?(??)

pci_read_config_byte

[精华] LDD2-CH12-块设备

<<Linux设备驱动程序第二版>;>;第八章 硬件访问

<<Linux设备驱动程序第二版>;>;第六章 时钟管理

《Linux设备驱动程序》第二版译稿 第九章中断处理 by kongming etc

<<Linux设备驱动程序第二版>;>;第九章 中断处理

<<Linux设备驱动程序第二版>;>;导读计划

Linux 设备驱动程序》第二版翻译稿样章(前言)

《Linux 设备驱动程序》第二版中文翻译稿样章(第 6 章 时间流)

《Linux 设备驱动程序》第二版中文译稿样章(第 4 章 调试技术)

Linux设备驱动程序(第一版)完整勘误表

编译内核出错(为什么这种话题很多?)

gdtr,idtr,cr3乃至页目录表,他们之中的地址都是物理地址吗?

vm area的地址映射(多看些讨论有好处)

difference between "return" and "exit"?

关于booting部分的一些链接

[精华] Linux 内核笔记2 - 进程调度

Linux的存储管理(二)

linux内核调试(讨论)

推荐一本浅显易懂的书

此图如何看(e820)

论文“Linux内核进程调度与控制 --源代码分析与研究”

怎样用bochs和vmware测试内核

关于使用kgdb调试内核

Linux中的NAT能同时支持多少连接?

为什么会kernel panic(多多讨论)

task_struct结构中的comm成员是代表什么意思啊

《Linux 设备驱动程序》第二版中文译稿样章(第 15 章 外设总线概述)

注册设备文件处理函数的方法有问题(算个经验)

根文件在那里初始

关于in_interrupt的问题

为你的Linux快速编译所需要的模块 (zz)

关于《Linux 设备驱动程序》第二版中文译稿样章的说明

MODR/M and SIB,whar's the means?

What's the maximum preemption latency

LINUX下的设备驱动程序

[转贴]如何编写Linux操作系统下的设备驱动程序

关于vmalloc的疑问!!!

into entry-armv.s

设备驱动程序如何在启动时加载(faq)

bonding.c的原码分析

驱动开发的基础问题(硬件厂商提供驱动吗?)

LINUX的网络设备中,利用master 和slave来实现负载平衡

学习内核和驱动需要多少硬件知识

Linux 内核笔记3 --内核同步-- 第一部分

uClinux - BFLT Binary Flat Format

[精华] LINUX实时调度研讨。

mmap函数问题

Setup Terminal Systems

首席培训官教新手使用最新的内核

PG_active和PG_referenced

内核中的所有struct semaphore型变量都共享一个spinlock_t变量

进程互斥,PV操作

ldd2第十五章PCI总线阅读随记

Write Once protocol for multi processor

一个pci插槽的pci设备的中断是不是固定的

do_IRQ()问题

page->;mapping和page->;buffer分别是做什么用的?

do_softirq()问题

Linux内核进程调度与控制 --源代码分析与研究 by minipuss

可否核态和用户态直接进行通讯

Linux 内核笔记3 --内核同步-- 第三部分

Linux 内核笔记3 --内核同步-- 第二部分

How to open/read a file in interrupt_context?

Why "scheduling in interrupt" ?

when should i define a variable with "volatile" ?

Kernel/Device Driver questions?(mmap,kmalloc,irq)

"gdb-serial.txt" from "gdbstub.tar.gz"

gdtr中为什么放线形地址 ,而不是物理地址?

代表设备文件ext2_inode节点保存了什么信息保证找到设备的?

[精华] Linux 内核笔记3 - 内核同步(完整版)

内核与用户进程通讯的几种方式比较

我把内存管理FAQ重新整理了一下。

“逻辑地址”、“线性地址”、“物理地址”的区别和联系

关于在内核中向应用程序发送信号的问题

实际一个程序同时可能有多个进程,所以一般由pid找程序名较合理

refill_inactive()函数

又关于page->;buffers和page->;mapping

关于video.s的疑问

关于内存的几个问题

怎么添加上ip伪装和ip端口转发

Running Linux on Linux(User-Mode Linux )?

如何生成可被lilo引导的image?

同志们,为什么浪费0~08048000的进程地址空间不用

关于添加系统调用的问题

作linux向另一个硬件平台的移植工作应该如何入手?要做哪些工作(链接)

kernel精华!(文档包)已经上传到我公司的服务器上了! (有钱出钱)

Kongming给出了ldd2中文版的部分章节,大家抽空读读,对其中细节给点建议

请问如何使网关支持内网上任意IP的上网通讯?

那么MAIN这个进程是什么时候fork的呢?

怎样在内核中读写文件?

LINUX ALLOCATED DEVICES

Interview with Robert Love

请xshell结合这段代码对于cacheline做些解释

HZ 表示每两次时钟中断相隔的微秒数

head.S 中的__PAGE_OFFSET 和其他

谁能讲一讲Console和tty之间的关系?

wmb是干吗的函数 (zz)

这是我在学习设备驱动程序的一点问题?希望大家赐教!

2.4.16下网络结构全景图1.0 (包含模块接口变量名称)

谁有真正能用的Linux启动盘的资料?

Encrypted Ethernet Bridging

More Explicative Kernel Tainting

setup.S中"in al #0x92" 0x92端口的含义

BIOS 数据区域(BDA)位置在哪里?

Why pay someone to port Linux for you?

中断上下文中如何实现文件读写?

wait和completion数据结构的解释

user_struct

谁能解释一下tty,tty0,ttyS0,console,终端,控制台这几个词

Linux MTD源代码分析

请问内核中读写配置文件的源码在哪个目录的哪个文件中

写时复制中关于empty_zero_page的问题

Linux 内核使用的 GNU C 扩展

我的一个Object-oriented operating environment 设想.

是不是所有的包都要用到这里的match,target,在哪个hook用,看得糊涂了

为什么在转发之前需要COPY一下SK_BUFF???

转载一篇文章"泛系、自由与“一、百、万”工程"

2.4.16内核icmp报文处理分析

请问各hook函数之间怎么传递信息:在同一个hook点上的和不同hook点上的函数各自如何传递

关于中断问题的请教

大家有否考虑在Linux上实现一个硬件抽象层?(空)

Linux Kernel Module Programming Guide

可动态编译的嵌入式操作系统

CMOS里的东西在启动后是不是COPY到内存中去了

问个基础的问题

vmalloc的问题

超级宝书http://suse.chinasec.com/ulk.pdf

哪有LINUX内核分析(进程部分)的文章?

写时复制的问题

守护进程里如何发声?

关于swapper_pg_dir初始化的问题

linux 与 minix的共存

我编驱动程序的时候的问题(PCI)

如何实现内存映射?

关于在转发前sk_buff结构copy的问题

Are you familiar with Architecture or OS ?

为什么谁都可?
[目录]

--------------------------------------------------------------------------------


AKA推荐书籍

====================================================================
《The Design of The UNIX Operating System》 Author: Maurice J. Bach
中译本:《UNIX 操作系统设计》
---------------------
翻译者:陈葆钰等
北大版: 32开,黄皮,9.40¥
机工版: 16开,褐皮,30¥
---------------------
一本老书,但绝对是bible级的。其内容覆盖了经典UNIX操作系统中的所有基本概念
以及设计思想。阅读者最好能懂一些基本的操作系统理论知识。
====================================================================
====================================================================
《Unix Internals - The New Frontiers》 Author: Uresh Vahalia
中译本:《UNIX 高级教程:系统技术内幕》
---------------------
翻译者:聊鸿斌等
清华大学出版社出版,16开,桔皮,58¥
---------------------
一本新书,也是bible级的。其主要特点是80%的内容都是现代UNIX操作系统的新思想
和新概念。对各UNIX大家的精彩设计点都有很详尽的阐述。阅读者最好先看看贝奇那
本书。
====================================================================

====================================================================
《Linux Core Kernel Commentary》
---------------------
Author: Scott Maxwell
---------------------
有中译本,但具体信息不详 对照源码讲Linux内核,版本还比较高,2.2.X。有些新
东西可看看。可惜没讲网络部分的实现。
====================================================================

====================================================================
《Linux Kernel Internals: 2nd version》
---------------------
Author: M Beck ...
---------------------
目前无中译本 以数据结构为主体来介绍内核,内容很丰富,但版本太低(2.0.x),有
些陈旧的东西容易令人误入歧途。
====================================================================

====================================================================
《The Design and Implementation of the 4.4BSD Operating System》
---------------------
Author: McKusick, Bostic, Karels, Quarterman
---------------------
目前无中译本  讲述BSD操作系统最权威的书。书的作者亦即BSD最早的几名开发者。
====================================================================

====================================================================
《Linux 操作系统及实验教程》
---------------------
作者:李善平,郑扣根(浙大教师)
机工出版
---------------------
有些内容不错,讲得还比较深入。也缺少网络部分的描述。
====================================================================

====================================================================
《UNIX 系统下的80386》
---------------------
作者:周明德, 张淑玲
清华出版
---------------------
讲X86的体系结构。要想看懂/arch/i386下的辕马,最好先看看这本书。
====================================================================

====================================================================
《UNIX Systems for Modern Architectures》
---------------------
Author: Curt Schimmel
---------------------
目前无中译本  如果想了解辕马中SMP的实现。可参考看这本书。
====================================================================

====================================================================
《保护模式下的80386及其编程》
---------------------
出版社:清华大学出版社
---------------------
本书全面地介绍了80386的结构。首先是80386实模式和保护模式下的寄存器集和
指令集,接着从保护模式下的虚存管理、保护级、多任务支持、中断和异常等方
面深入地剖析386的强大功能,再接着提供几个典型的编程实例以及一个完整的从
386加电初始化开始到形成一个有基本的多任务和虚拟存储能力的系统的例子并作
了详细解释,最后还清楚地说明了80386与8086/80286的兼容性和差别。本书的特
点是严谨深入,对CPU各种条件下的动作和反应用形式化的微程序讲解得十分清楚,
尤其适合系统程序员阅读。总之,这实在是一本不可多得的好书.

====================================================================

====================================================================
《Linux 操作系统的内核分析》 作者:陈莉君编著
---------------------
价格:40 元
出版社:人民邮电出版社
---------------------

====================================================================




[目录]

--------------------------------------------------------------------------------


linux论坛推荐资源

~~~~~~~
一般文献
~~~~~~~
利索脚组织的网站:
http://www.lisoleg.net
linux kernel internals 2.4(不是特别全)

http://www.moses.uklinux.net/patches/lki.html
http://tzhang.xiloo.com/unix/kernel/

UNIX高级教程 系统技术内幕
Uresh Vahalia 清华大学出版社

书。这是一本非常好的书,思想性很强,对学习Linux以及操作系统非常有帮助。

Understanding the Linux Kernel
Daniel P. Bovet  Marco Cesati
O'Reilly出版

超级宝书!2001年内会有中译本。
这里是第10章
Process Scheduling

Linux 操作系统及实验教程
李善平 郑扣根 编著
机械工业出版社

Linux 操作系统的内核分析
陈莉君编著
人民邮电出版社

Linux Device Driver

书。有中译本。帮助理解中断,任务队列等内核机制,帮助掌握驱动编程。

Operating Systems
resource center
jkl 推荐

关于操作系统的介绍,有许多专题文章

http://www.nondot.org/sabre//os/

关于Linux的重要链接
Pengcheng Zou 推荐

给出了许多重要的链接

http://www.linuxlinks.com/Kernel/

非常完备的CPU开发手册

Intel Architecture Software Developer’s Manual
Volume 3:
System Programming

" target="_new">;http://developer.intel.com/design/pentiumii/manuals/24319202.pdf

对i386的机制讲得非常详细,可以帮助深入了解i386保护模式机制,对理解Linux的相关实现非常有帮助

~~~~~~~
关于内存
~~~~~~~

Outline of the Linux Memory Management System
黑饭 推荐

http://home.earthlink.net/~jknapka/linux-mm/vmoutline.html

已经是一个比较细致的介绍内存(包括内核的和用户空间的)了。

SGI公司的公开项目

http://oss.sgi.com/projects/

SGI公司的关于伸缩性的技术非常棒!Linux的NUMA就是由他们做的,这是他们的网页

Linux内存开发小组的网站
jkl 推荐

http://www.linux-mm.org

这是Linux负责开发内存管理的核心成员的网站
下面有他们关于zone设计思想的描述:

http://surriel.com/zone-alloc.html

~~~~~~~
关于中断
~~~~~~~

关于中断上锁的专题文档

http://netfilter.kernelnotes.org/unreliable-guides/kernel-locking/lklockingguide.html

我们知道在中断中写程序要小心,不小心会发生race condition.这篇文献对这方面做了介绍

~~~~~~~~~~
关于文件系统
~~~~~~~~~~

Linux Commentary
dream_seeker 推荐

http://www.cse.unsw.edu.au/~neilb/oss/linux-commentary/

主要介绍文件系统, 另外,下面的

linux-vm-readme

主要介绍VM和交换,也很值得一看



关于汇编
[http://www.linuxassembly.org http://www.linuxassembly.org ]
Linuxkernel推荐


关于AT

http://www-106.ibm.com/developerworks/linux/library/l-ia.html
lisoleg推荐

关于汇编:
http://www-aig.jpl.nasa.gov/public/home/decoste/HTMLS/GNU/binutils/as_toc.html
http://www.linuxassembly.org/resources.html#tutorials
lucian推荐

关于驱动,专门研究linux驱动设计的bbs
http://short.xilubbs.com
joyfire推荐


Edited by lucian_yao on 05/20/01 08:05 PM.






[目录]

--------------------------------------------------------------------------------


数据结构

以下是linux操作系统核心常用的数据结构
block_dev_struct
此结构用于向核心登记块设备,它还被buffer
cache实用。所有此类结构都位于blk_dev数组中。
struct blk_dev_struct {
    void (*request_fn)(void);
    struct request * current_request;
    struct request   plug;
    struct tq_struct plug_tq;
};
buffer_head
此结构包含关于buffer cache中一块缓存的信息。
/* bh state bits */
#define BH_Uptodate  0   /* 1 if the buffer contains valid data      */
#define BH_Dirty     1   /* 1 if the buffer is dirty                 */
#define BH_Lock      2   /* 1 if the buffer is locked                */
#define BH_Req       3   /* 0 if the buffer has been invalidated     */
#define BH_Touched   4   /* 1 if the buffer has been touched (aging) */
#define BH_Has_aged  5   /* 1 if the buffer has been aged (aging)    */
#define BH_Protected 6   /* 1 if the buffer is protected             */
#define BH_FreeOnIO  7   /* 1 to discard the buffer_head after IO    */
struct buffer_head {
  /* First cache line: */
  unsigned long      b_blocknr;    /* block number                   */
  kdev_t             b_dev;        /* device (B_FREE = free)         */
  kdev_t             b_rdev;       /* Real device                    */
  unsigned long      b_rsector;    /* Real buffer location on disk   */
  struct buffer_head *b_next;      /* Hash queue list                */
  struct buffer_head *b_this_page; /* circular list of buffers in one
                                      page                           */
  /* Second cache line: */
  unsigned long      b_state;      /* buffer state bitmap (above)    */
  struct buffer_head *b_next_free;
  unsigned int       b_count;      /* users using this block         */
  unsigned long      b_size;       /* block size                     */
  /* Non-performance-critical data follows. */
  char               *b_data;      /* pointer to data block          */
  unsigned int       b_list;       /* List that this buffer appears  */
  unsigned long      b_flushtime;  /* Time when this (dirty) buffer
                                    * should be written              */
  unsigned long      b_lru_time;   /* Time when this buffer was
                                    * last used.                     */
  struct wait_queue  *b_wait;
  struct buffer_head *b_prev;      /* doubly linked hash list        */
  struct buffer_head *b_prev_free; /* doubly linked list of buffers  */
  struct buffer_head *b_reqnext;   /* request queue                  */
};
device
系统中每个网络设备都用一个设备数据结构来表示。
struct device
{
  /*
   * This is the first field of the "visible" part of this structure
   * (i.e. as seen by users in the "Space.c" file).  It is the name
   * the interface.
   */
  char                    *name;
  /* I/O specific fields                                           */
  unsigned long           rmem_end;        /* shmem "recv" end     */
  unsigned long           rmem_start;      /* shmem "recv" start   */
  unsigned long           mem_end;         /* shared mem end       */
  unsigned long           mem_start;       /* shared mem start     */
  unsigned long           base_addr;       /* device I/O address   */
  unsigned char           irq;             /* device IRQ number    */
  /* Low-level status flags. */
  volatile unsigned char  start,           /* start an operation   */
                          interrupt;       /* interrupt arrived    */
  unsigned long           tbusy;           /* transmitter busy     */
  struct device           *next;
  /* The device initialization function. Called only once.         */
  int                     (*init)(struct device *dev);
  /* Some hardware also needs these fields, but they are not part of
     the usual set specified in Space.c. */
  unsigned char           if_port;         /* Selectable AUI,TP,   */
  unsigned char           dma;             /* DMA channel          */
  struct enet_statistics* (*get_stats)(struct device *dev);
  /*
   * This marks the end of the "visible" part of the structure. All
   * fields hereafter are internal to the system, and may change at
   * will (read: may be cleaned up at will).
   */
  /* These may be needed for future network-power-down code.       */
  unsigned long           trans_start;     /* Time (jiffies) of
                                              last transmit        */
  unsigned long           last_rx;         /* Time of last Rx      */
  unsigned short          flags;           /* interface flags (BSD)*/
  unsigned short          family;          /* address family ID    */
  unsigned short          metric;          /* routing metric       */
  unsigned short          mtu;             /* MTU value            */
  unsigned short          type;            /* hardware type        */
  unsigned short          hard_header_len; /* hardware hdr len     */
  void                    *priv;           /* private data         */
  /* Interface address info. */
  unsigned char           broadcast[MAX_ADDR_LEN];
  unsigned char           pad;
  unsigned char           dev_addr[MAX_ADDR_LEN];
  unsigned char           addr_len;        /* hardware addr len    */
  unsigned long           pa_addr;         /* protocol address     */
  unsigned long           pa_brdaddr;      /* protocol broadcast addr*/
  unsigned long           pa_dstaddr;      /* protocol P-P other addr*/
  unsigned long           pa_mask;         /* protocol netmask     */
  unsigned short          pa_alen;         /* protocol address len */
  struct dev_mc_list      *mc_list;        /* M'cast mac addrs     */
  int                     mc_count;        /* No installed mcasts  */
  struct ip_mc_list       *ip_mc_list;     /* IP m'cast filter chain */
  __u32                   tx_queue_len;    /* Max frames per queue   */
  /* For load balancing driver pair support */
  unsigned long           pkt_queue;       /* Packets queued       */
  struct device           *slave;          /* Slave device         */
  struct net_alias_info   *alias_info;     /* main dev alias info  */
  struct net_alias        *my_alias;       /* alias devs           */
  /* Pointer to the interface buffers. */
  struct sk_buff_head     buffs[DEV_NUMBUFFS];
  /* Pointers to interface service routines. */
  int                     (*open)(struct device *dev);
  int                     (*stop)(struct device *dev);
  int                     (*hard_start_xmit) (struct sk_buff *skb,
                                              struct device *dev);
  int                     (*hard_header) (struct sk_buff *skb,
                                          struct device *dev,
                                          unsigned short type,
                                          void *daddr,
                                          void *saddr,
                                          unsigned len);
  int                     (*rebuild_header)(void *eth,
                                          struct device *dev,
                                          unsigned long raddr,
                                          struct sk_buff *skb);
  void                    (*set_multicast_list)(struct device *dev);
  int                     (*set_mac_address)(struct device *dev,
                                          void *addr);
  int                     (*do_ioctl)(struct device *dev,
                                          struct ifreq *ifr,
                                          int cmd);
  int                     (*set_config)(struct device *dev,
                                          struct ifmap *map);
  void                    (*header_cache_bind)(struct hh_cache **hhp,
                                          struct device *dev,
                                          unsigned short htype,
                                          __u32 daddr);
  void                    (*header_cache_update)(struct hh_cache *hh,
                                          struct device *dev,
                                          unsigned char *  haddr);
  int                     (*change_mtu)(struct device *dev,
                                          int new_mtu);
  struct iw_statistics*   (*get_wireless_stats)(struct device *dev);
};
device_struct
此结构被块设备和字符设备用来向核心登记(包含设备名称以及可对此设备进行的
文件操作)。chrdevs和blkdevs中的每个有效分别表示一个字符设备和块设备。
struct device_struct {
    const char * name;
    struct file_operations * fops;
};
file
每个打开的文件、套接口都用此结构表示。
struct file {
  mode_t f_mode;
  loff_t f_pos;
  unsigned short f_flags;
  unsigned short f_count;
  unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
  struct file *f_next, *f_prev;
  int f_owner;         /* pid or -pgrp where SIGIO should be sent */
  struct inode * f_inode;
  struct file_operations * f_op;
  unsigned long f_version;
  void *private_data;  /* needed for tty driver, and maybe others */
};
files_struct
描叙被某进程打开的所有文件。
struct files_struct {
  int count;
  fd_set close_on_exec;
  fd_set open_fds;
  struct file * fd[NR_OPEN];
};
fs_struct
struct fs_struct {
  int count;
  unsigned short umask;
  struct inode * root, * pwd;
};
gendisk
包含关于某个硬盘的信息。用于磁盘初始化与分区检查时。
struct hd_struct {
    long start_sect;
    long nr_sects;
};
struct gendisk {
    int major;               /* major number of driver */
    const char *major_name;  /* name of major driver */
    int minor_shift;         /* number of times minor is shifted to
                                get real minor */
    int max_p;               /* maximum partitions per device */
    int max_nr;              /* maximum number of real devices */
    void (*init)(struct gendisk *);
                             /* Initialization called before we
                                do our thing */
    struct hd_struct *part;  /* partition table */
    int *sizes;              /* device size in blocks, copied to
                                blk_size[] */
    int nr_real;             /* number of real devices */
    void *real_devices;      /* internal use */
    struct gendisk *next;
};
inode
此VFS inode结构描叙磁盘上一个文件或目录的信息。
struct inode {
    kdev_t                       i_dev;
    unsigned long                i_ino;
    umode_t                      i_mode;
    nlink_t                      i_nlink;
    uid_t                        i_uid;
    gid_t                        i_gid;
    kdev_t                       i_rdev;
    off_t                        i_size;
    time_t                       i_atime;
    time_t                       i_mtime;
    time_t                       i_ctime;
    unsigned long                i_blksize;
    unsigned long                i_blocks;
    unsigned long                i_version;
    unsigned long                i_nrpages;
    struct semaphore             i_sem;
    struct inode_operations      *i_op;
    struct super_block           *i_sb;
    struct wait_queue            *i_wait;
    struct file_lock             *i_flock;
    struct vm_area_struct        *i_mmap;
    struct page                  *i_pages;
    struct dquot                 *i_dquot[MAXQUOTAS];
    struct inode                 *i_next, *i_prev;
    struct inode                 *i_hash_next, *i_hash_prev;
    struct inode                 *i_bound_to, *i_bound_by;
    struct inode                 *i_mount;
    unsigned short               i_count;
    unsigned short               i_flags;
    unsigned char                i_lock;
    unsigned char                i_dirt;
    unsigned char                i_pipe;
    unsigned char                i_sock;
    unsigned char                i_seek;
    unsigned char                i_update;
    unsigned short               i_writecount;
    union {
        struct pipe_inode_info   pipe_i;
        struct minix_inode_info  minix_i;
        struct ext_inode_info    ext_i;
        struct ext2_inode_info   ext2_i;
        struct hpfs_inode_info   hpfs_i;
        struct msdos_inode_info  msdos_i;
        struct umsdos_inode_info umsdos_i;
        struct iso_inode_info    isofs_i;
        struct nfs_inode_info    nfs_i;
        struct xiafs_inode_info  xiafs_i;
        struct sysv_inode_info   sysv_i;
        struct affs_inode_info   affs_i;
        struct ufs_inode_info    ufs_i;
        struct socket            socket_i;
        void                     *generic_ip;
    } u;
};
ipc_perm
此结构描叙对一个系统V IPC对象的存取权限。
struct ipc_perm
{
  key_t  key;
  ushort uid;   /* owner euid and egid */
  ushort gid;
  ushort cuid;  /* creator euid and egid */
  ushort cgid;
  ushort mode;  /* access modes see mode flags below */
  ushort seq;   /* sequence number */
};
irqaction
用来描叙系统的中断处理过程。
struct irqaction {
  void (*handler)(int, void *, struct pt_regs *);
  unsigned long flags;
  unsigned long mask;
  const char *name;
  void *dev_id;
  struct irqaction *next;
};
linux_binfmt
用来表示可被Linux理解的二进制文件格式。
struct linux_binfmt {
  struct linux_binfmt * next;
  long *use_count;
  int (*load_binary)(struct linux_binprm *, struct  pt_regs * regs);
  int (*load_shlib)(int fd);
  int (*core_dump)(long signr, struct pt_regs * regs);
};
mem_map_t
用来保存每个物理页面的信息。
typedef struct page {
  /* these must be first (free area handling) */
  struct page        *next;
  struct page        *prev;
  struct inode       *inode;
  unsigned long      offset;
  struct page        *next_hash;
  atomic_t           count;
  unsigned           flags;     /* atomic flags, some possibly
                                   updated asynchronously */
  unsigned           dirty:16,
                     age:8;
  struct wait_queue  *wait;
  struct page        *prev_hash;
  struct buffer_head *buffers;
  unsigned long      swap_unlock_entry;
  unsigned long      map_nr;    /* page->;map_nr == page - mem_map */
} mem_map_t;
mm_struct
用来描叙某任务或进程的虚拟内存。
struct mm_struct {
  int count;
  pgd_t * pgd;
  unsigned long context;
  unsigned long start_code, end_code, start_data, end_data;
  unsigned long start_brk, brk, start_stack, start_mmap;
  unsigned long arg_start, arg_end, env_start, env_end;
  unsigned long rss, total_vm, locked_vm;
  unsigned long def_flags;
  struct vm_area_struct * mmap;
  struct vm_area_struct * mmap_avl;
  struct semaphore mmap_sem;
};
pci_bus
表示系统中的一个PCI总线。
struct pci_bus {
  struct pci_bus  *parent;     /* parent bus this bridge is on */
  struct pci_bus  *children;   /* chain of P2P bridges on this bus */
  struct pci_bus  *next;       /* chain of all PCI buses */
  struct pci_dev  *self;       /* bridge device as seen by parent */
  struct pci_dev  *devices;    /* devices behind this bridge */
  void    *sysdata;            /* hook for sys-specific extension */
  unsigned char  number;       /* bus number */
  unsigned char  primary;      /* number of primary bridge */
  unsigned char  secondary;    /* number of secondary bridge */
  unsigned char  subordinate;  /* max number of subordinate buses */
};
pci_dev
表示系统中的每个PCI设备,包括PCI-PCI和PCI-PCI桥接器。
/*
* There is one pci_dev structure for each slot-number/function-number
* combination:
*/
struct pci_dev {
  struct pci_bus  *bus;      /* bus this device is on */
  struct pci_dev  *sibling;  /* next device on this bus */
  struct pci_dev  *next;     /* chain of all devices */
  void    *sysdata;          /* hook for sys-specific extension */
  unsigned int  devfn;       /* encoded device & function index */
  unsigned short  vendor;
  unsigned short  device;
  unsigned int  class;       /* 3 bytes: (base,sub,prog-if) */
  unsigned int  master : 1;  /* set if device is master capable */
  /*
   * In theory, the irq level can be read from configuration
   * space and all would be fine.  However, old PCI chips don't
   * support these registers and return 0 instead.  For example,
   * the Vision864-P rev 0 chip can uses INTA, but returns 0 in
   * the interrupt line and pin registers.  pci_init()
   * initializes this field with the value at PCI_INTERRUPT_LINE
   * and it is the job of pcibios_fixup() to change it if
   * necessary.  The field must not be 0 unless the device
   * cannot generate interrupts at all.
   */
  unsigned char  irq;        /* irq generated by this device */
};
request
被用来向系统的块设备发送请求。它总是向buffer cache读出或写入数据块。
struct request {
    volatile int rq_status;
#define RQ_INACTIVE            (-1)
#define RQ_ACTIVE              1
#define RQ_SCSI_BUSY           0xffff
#define RQ_SCSI_DONE           0xfffe
#define RQ_SCSI_DISCONNECTING  0xffe0
    kdev_t rq_dev;
    int cmd;        /* READ or WRITE */
    int errors;
    unsigned long sector;
    unsigned long nr_sectors;
    unsigned long current_nr_sectors;
    char * buffer;
    struct semaphore * sem;
    struct buffer_head * bh;
    struct buffer_head * bhtail;
    struct request * next;
};
rtable
用来描叙向某个IP主机发送包的路由信息。此结构在IP路由cache内部实用。
struct rtable
{
    struct rtable     *rt_next;
    __u32             rt_dst;
    __u32             rt_src;
    __u32             rt_gateway;
    atomic_t          rt_refcnt;
    atomic_t          rt_use;
    unsigned long     rt_window;
    atomic_t          rt_lastuse;
    struct hh_cache   *rt_hh;
    struct device     *rt_dev;
    unsigned short    rt_flags;
    unsigned short    rt_mtu;
    unsigned short    rt_irtt;
    unsigned char     rt_tos;
};
semaphore
保护临界区数据结构和代码信号灯。
struct semaphore {
    int count;
    int waking;
    int lock ;                /* to make waking testing atomic */
    struct wait_queue *wait;
};
sk_buff
用来描叙在协议层之间交换的网络数据。
struct sk_buff
{
  struct sk_buff      *next;       /* Next buffer in list
*/
  struct sk_buff      *prev;       /* Previous buffer in list
*/
  struct sk_buff_head *list;       /* List we are on
*/
  int                 magic_debug_cookie;
  struct sk_buff      *link3;      /* Link for IP protocol level buffer chai
ns *
  struct sock         *sk;         /* Socket we are owned by
*/
  unsigned long       when;        /* used to compute rtt's
*/
  struct timeval      stamp;       /* Time we arrived
*/
  struct device       *dev;        /* Device we arrived on/are leaving by
*/
  union
  {
      struct tcphdr   *th;
      struct ethhdr   *eth;
      struct iphdr    *iph;
      struct udphdr   *uh;
      unsigned char   *raw;
      /* for passing file handles in a unix domain socket */
      void            *filp;
  } h;
  union
  {
      /* As yet incomplete physical layer views */
      unsigned char   *raw;
      struct ethhdr   *ethernet;
  } mac;
  struct iphdr        *ip_hdr;     /* For IPPROTO_RAW
*/
  unsigned long       len;         /* Length of actual data
*/
  unsigned long       csum;        /* Checksum
*/
  __u32               saddr;       /* IP source address
*/
  __u32               daddr;       /* IP target address
*/
  __u32               raddr;       /* IP next hop address
*/
  __u32               seq;         /* TCP sequence number
*/
  __u32               end_seq;     /* seq [+ fin] [+ syn] + datalen
*/
  __u32               ack_seq;     /* TCP ack sequence number
*/
  unsigned char       proto_priv[16];
  volatile char       acked,       /* Are we acked ?
*/
                      used,        /* Are we in use ?
*/
                      free,        /* How to free this buffer
*/
                      arp;         /* Has IP/ARP resolution finished
*/
  unsigned char       tries,       /* Times tried
*/
                      lock,        /* Are we locked ?
*/
                      localroute,  /* Local routing asserted for this frame
*/
                      pkt_type,    /* Packet class
*/
                      pkt_bridged, /* Tracker for bridging
*/
                      ip_summed;   /* Driver fed us an IP checksum
*/
#define PACKET_HOST         0        /* To us
  */
#define PACKET_BROADCAST    1        /* To all
  */
#define PACKET_MULTICAST    2        /* To group
  */
#define PACKET_OTHERHOST    3        /* To someone else
  */
  unsigned short      users;       /* User count - see datagram.c,tcp.c
*/
  unsigned short      protocol;    /* Packet protocol from driver.
*/
  unsigned int        truesize;    /* Buffer size
*/
  atomic_t            count;       /* reference count
*/
  struct sk_buff      *data_skb;   /* Link to the actual data skb
*/
  unsigned char       *head;       /* Head of buffer
*/
  unsigned char       *data;       /* Data head pointer
*/
  unsigned char       *tail;       /* Tail pointer
*/
  unsigned char       *end;        /* End pointer
*/
  void                (*destructor)(struct sk_buff *); /* Destruct function
*/
  __u16               redirport;   /* Redirect port
*/
};
sock
包含BSD套接口的协议相关信息。例如对于一个INET(Internet AddressDomain)套接口

此数据结构 包含TCP/IP和UDP/IP信息。
struct sock
{
    /* This must be first. */
    struct sock             *sklist_next;
    struct sock             *sklist_prev;
    struct options          *opt;
    atomic_t                wmem_alloc;
    atomic_t                rmem_alloc;
    unsigned long           allocation;       /* Allocation mode */
    __u32                   write_seq;
    __u32                   sent_seq;
    __u32                   acked_seq;
    __u32                   copied_seq;
    __u32                   rcv_ack_seq;
    unsigned short          rcv_ack_cnt;      /* count of same ack */
    __u32                   window_seq;
    __u32                   fin_seq;
    __u32                   urg_seq;
    __u32                   urg_data;
    __u32                   syn_seq;
    int                     users;            /* user count */
  /*
   *    Not all are volatile, but some are, so we
   *     might as well say they all are.
   */
    volatile char           dead,
                            urginline,
                            intr,
                            blog,
                            done,
                            reuse,
                            keepopen,
                            linger,
                            delay_acks,
                            destroy,
                            ack_timed,
                            no_check,
                            zapped,
                            broadcast,
                            nonagle,
                            bsdism;
    unsigned long           lingertime;
    int                     proc;
    struct sock             *next;
    struct sock             **pprev;
    struct sock             *bind_next;
    struct sock             **bind_pprev;
    struct sock             *pair;
    int                     hashent;
    struct sock             *prev;
    struct sk_buff          *volatile send_head;
    struct sk_buff          *volatile send_next;
    struct sk_buff          *volatile send_tail;
    struct sk_buff_head     back_log;
    struct sk_buff          *partial;
    struct timer_list       partial_timer;
    long                    retransmits;
    struct sk_buff_head     write_queue,
                            receive_queue;
    struct proto            *prot;
    struct wait_queue       **sleep;
    __u32                   daddr;
    __u32                   saddr;            /* Sending source */
    __u32                   rcv_saddr;        /* Bound address */
    unsigned short          max_unacked;
    unsigned short          window;
    __u32                   lastwin_seq;      /* sequence number when we las
t
                                                 updated the window we offer
*/
    __u32                   high_seq;         /* sequence number when we did

                                                 current fast retransmit */
    volatile unsigned long  ato;              /* ack timeout */
    volatile unsigned long  lrcvtime;         /* jiffies at last data rcv */





[目录]

--------------------------------------------------------------------------------


重新编译

1.核心的源程序:
    我现在在用TLC, REDHAT也用过, SLACKWARE也用过. 无论哪一种, 都是把核心源程
序放到 /usr/src/linux 下, 因为有些别的应用程序在编译时好像也会从这个路径来引
用一些头文件之类. 一般来说这个 linux 目录都只是个符号连接, 有一点点像WIN下的
Shortcut, 而实际上它对应的目录可能是 /usr/src/linux-2.0.35 之类. RedHat的缺省
安装好像并不装源程序, 只有些头文件.
    以现在的2.2.5 核心为例, 我装的时候就是这样(其实什么版本都一样
    cd /usr/src
    rm linux
    # 这个linux只是个符号连接, 删掉它没事的. 可以 ls -l 看看, 如果看到这个:
    # linux ->; linux-XXXXX, 就表示它是个连接而已. 原来的源程序在箭头后的目录.
    tar zxvf XXXXXXX/linux-2.2.5.tar.gz
    # 这个包解开后, 新核心的源程序就放在了新建立的linux目录下, 这可是个货真价
    # 实的目录.
    mv linux linux-2.2.5
    ln -s linux-2.2.5 linux
    # 按照惯例, 还是把目录另命个名, 再重新做个linux的符号连接
2.准备编译:
    现在要做一些准备工作. 对于新释放出来的核心源程序也没啥好做的, 就打一个:
    cd /usr/src/linux
    make menuconfig

    然后就会看到一个很友好的界面(在LINUX下...已经是很友好的了), 大致上有点像
WIN 9X安装时的选择安装项目. 这就是在配置核心, 选择哪些内容要, 哪些不要.
然后选EXIT退出来, 问是否保存修改时答YES. 然后会有一些提示. 如果看到了有叫你
"make dep", 就要打"make dep"先. 完了后就打 make bzImage. 如果提示信息中没有
叫你"make dep", 只有叫你 "make zImage", "make zdisk" 或 "make zlilo" 的,
就直接打 make bzImage 就行了.

一点说明: make dep 是作一些准备工作, make bzImage 则是开始编译生成核心. 而
          make bzImage与make zImage的区别在于, 作成bzImage的核心压缩率比zImage
          高, 核心就更小一些. make zdisk 与 make zlilo 是做别的用处的核心的.

    然后就等吧(有得你等的). 一般从5分钟到半个钟头不等, 看你的机器了. 第一次编
译会 比较慢. 以后再改了配置后make就会快很多了.

    等这个完了后一定还要 make modules 和 make modules_install.

make bzImage 完后会显示核心放在什么地方, 一般是/usr/src/linux/arch/i386/boot/
下. 把bzImage拷到根下. 然后修改 /etc/lilo.conf, 照着原来的image = XXXXX来加上
image = /bzImage
  root = /dev/hda1 (这里视你的LINUX安装而定, 照你原有的改)
  label = linux
  read-only
    把原来的 label = linux 改一下, 如 label = oldlinux.
    把image = /bzImage 这一节加在原来的前面, 这样会自动作为缺省的核心. 你也可以在
LILO时打linux或oldlinux来启动不同的核心. 关于这一段, 也可以参考俺前面的"ALS007
发声经过". 最后, 切记切记, 一定要打个lilo来重新生成LILO程序.

好了, 重启...





[目录]

--------------------------------------------------------------------------------


重建内核选项

       prompt for development and/or incomplete code/drivers
             很多参考书上说这是那些开发人员认为还不是很稳定的功能,但
             是根据我的经验,这个是应该选的一个选项,因为现代的LINUX是
             建立在这些基础上的,所以应该可以回答Y,除非你只是想使用
             LINUX中已经完全定型的东西,但性能肯定不会好到哪,而且对系
             统特性的支持也不会好。
       processor family (386,486/cx486,586/k5/5x86/6x86,pentinum/k6/tsc,ppro/6x86)
             这应该没有太多可说的吧,选择你的CPU的种类,BIOS可以自检得
             到,注意系统的启动信息。需要注意的是不能选择比你的CPU类型
             还高级的CPU,否则可能不能正常工作。

       math emulation
             模拟数学协处理器,如果你的机器没有数学协处理器,那就选上
             以提高性能,但486以后数学协处理器就集成到CPU内部了,应该是
             用不上的,所以一般的选择是N。当然选上也不会有什么问题,除
             了内 松陨 变大外。

       mttr(memory type range register) support
             这个选项是用来启动pentinum pro和pentinum II 的特殊功能,如果你用
             的不是这类CPU就选N,否则也仅仅是使内核变大而已。

       symmetric multi-processing support
             同步处理器支持,如果你有多个CPU就选上吧。

       enable loadable module support
             这会启动动态载入额外模块的功能,所以一定选上。

       set version information on all symbols for modules
             这个选项可以为某个版本的内核而编译的模块在另一个版本的内
             核下使用,但一般用不上。

        kernel module loader
             如果你启用这个选项,你可以通过kerneld程序的帮助在需要的时候
             自动载入或卸载那些可载入式的模块。建议选上。

         networking support
             如果你用到任何网络就应该选上

         pci bios support
             这个一般是应该选上的,除非你用没有任何PCI设备的机器。PCI
             BIOS是用来侦测并启用PCI设备的。

         pci bridge optimization(v1.3)
             当这个选项被启动时,操作系统会对从CPU和系统内存在PCI总线
             来往的数据做最佳化,这个功能已经完成实验阶段,使用起来应
             该很安全,而且还可增进系统的效率。

         system v ipc
             起用这个选项可以使内核支持System V 的进程间通信的功能
             (IPC),有些从System V转移过来的程序会需要这个功能,建议启
             用该功能。

         sysctl support
             除非你的内存少的可怜,否则你应该启动这个功能,启用该选项
             后内核会大8K,但能让你直接改变内核的参数而不必重新开机。

         kernel support for elf binaries
             该选项让你的系统得以执行用ELF格式存储的可执行文件,而ELF
             是现代LINUX的可执行文件、目标文件和系统函数库的标准格式。
             当操作系统要和编译器以及连接器合作时会需要这些标准,所以
             应该回答Y。

         compile kernel as elf
             这选项让你的内核本身以ELF的格式编译,如果你的系统上的过程
             gcc默认产生ELF格式的可执行文件,那么你就应该启动这个选项。
             先看看你的编译器的版本再决定。

         parallel port support
             如果你有任何并行口的设备并且想让LINUX使用,那么就可以启用
             这个选项。LINUX不仅可以使用并口的打印机,还可以支持PLIP
             (一种为并行口而设计的网络通讯协定),ZIP磁盘驱动器、扫描
             仪等。在大多情况下,你需要额外的驱动程序才能使用外接的并
             口设备。

         plug and play support
             支持PNP设备并非Microsoft的专利,如果你要让LINUX也支持PNP设
             备,只要启用该选项就可以,但有些情况下会和其他设备产生冲
             突(I/O,DMA,IRQ等)。这个选项对PCI设备没有影响,因为他们
             天生就是PNP设备。

         normal floppy disk support
             除非你不想在LINUX下使用软盘,否则就应该回答Y。但对于一些
             不需要支持软盘驱动器的系统而言,这个选项可以节省一些内
             存。

         enhanced ide/mfm/dll disk support
             除非你不需要MFM/DLL/IDE硬盘的的支持,否则就应该回答Y,但如
             果你只有SCSI的硬盘,关掉这个选项会比较安全。

         enhanced ide/mfm/dll cdrom support
             和上面的类似,只不过是对CDROM的支持而已。

         enhanced ide/mfm/dll tape support
             一般没有多少人在用磁带机吧,所以回答N是比较好的答案。

        enhanced ide/mfm/dll floppy support
             这个设备好象一般也没有人用,所以也可以回答N。

        xt harddisk support
             如果你有这种石器时代的XT硬盘,那么恭喜你你可以用上他了。

        parallel port ide device support
             LINUX是支持这种很新的并口的IDE设备的,如果你有的话就用上
             吧。

        networking options
             如果你在前面选了支持网络的话,在这里会回答很多问题。除非
             你有特别的需求,否则使用默认的选项应该就足够了。

        scsi support
             如果你有任何一种SCSI控制卡,这个选项就应该回答Y。事先搞清
             楚你的硬件的类型,因为这些问题都是针对特定的SCSI控制芯片和
             控制卡的,如果你不确定自己使用的是哪一种,查看你的硬件的
             说明文件或者LINUX的HOWTO文档。同样也会让你回答很多SCSI设
             备的支持(硬盘、CDROM、Tape、floppy等),依据你的情况选择。
             如果你没有SCSI设备的话,建议不要支持,因为这会节约很多内核
             空间。

         network device support
             这里面有很多关于网络控制卡的问题,如果你无法确定如何正确
             选择,查看硬件文档或LINUX HOWTO文档。

         amateur radio support
             这个选项可以用来启动无线网络的基本支持,目前的无线网络可
             以通过公众频率传输数据,如果你有此类设备就可以启用,具体
             请参考AX25和HAM HOWTO 文档。
             isdn subsystem
             如果你有ISDN硬件就应该启用该选项并安装合适的硬件驱动程
             序,你应该还会需要启用Support synchronous PPP选项(参考PPP over
             ISDN)。

         old cd-rom drivers
             这是针对一些特殊光盘驱动器程序的问题,如果你有IDE或SCSI的
             CDROM控制卡,那么就不用启用该选项了。

      

论坛徽章:
0
24 [报告]
发表于 2003-04-23 20:36 |只看该作者

linux内核分析(转自某位大哥网上的笔记)



linux网络部分重要结构体联系图(?)

用\续行, NR

请问ENTRY( ... ) 语法

在中断例程中如何与其他进程通讯??(用信号量还是全局变量)

内核模块编译需要优化

About task->;active_mm

驱动程序怎样锁定内存

linux 2.4.x initialization for IA-32 howto

Booting Linux for IA64

About task->;active_mm (bnn 续)

About Our China's CPU-Fang Zhou

我在你的帖子中注释了一下,不一定对.

RTL8139 驱动程序解析(转)

Sun YongYao--发送、接受、转发包处理结构框图修正

Linux内核分析文档计划

windowsXP和linux在系统结构上谁更好?

TCP协议的核心守护进程echod

请教一个中断方面的问题

再谈page cache和buffer cache

稀疏文件是怎么的概念呢

请教frees/wan的原理问题

块设备文件和普通文件有什么区别?普通文件不也是放在块设备上的吗?

关于I/O请求优化

请教一个MBR的问题

page cache与buffer cache的关系。

请问系统中有几个针对磁盘读写的request队列?

TCP传输控制块的初始状态

net_rx()网络数据流向

这样的内核程序能阻塞吗

Linux设备驱动程序的中断

页故障的处理过程

网卡的初始化过程

2.4内核网络部分的初始化

2.4网络代码阅读笔记(1)

2.4网络代码阅读笔记(2)

2.4网络代码阅读笔(3)

2.4网络代码阅读笔(4)

2.4网络代码阅读笔记(5)

RAM DISK 和 DiskOnChip 有什么关系?

文件映射区域的分配方式

未经accept的socket是如何处理数据的?

如何对拷不同长度的socket缓冲区?

Linux内核地址空间的布局

netfilter一问

请教GDT

我非得用SMP吗?

关于LDT的疑问

请教一个tcp连接性能的问题?

能解释一下A20地址线是怎么回事吗?为何要打开?

如何显示GDT,IDT,LDT表的内容

物理内存的分配结构

重入的疑惑

高端页面的映射

2.4.1内核中页结构PG_refrenced标志什么时候置位?

怎样在内核中写文件?

一些问题(网络方面)

网卡驱动程序(inw,insw提问)

向所有做内核分析的朋友提个问题

netfilter这里还是不明白

交换页分配方法

在网卡驱动程序中如何实现包转发?

请教一个内核寻址的问题

非分页、连续内存?

FreeBSD内核文件的结构

FreeBSD内核的编绎方法

virtual address to physical address - HOWTO?

关于printk的一个问题:

关于内存管理的一个问题

如何加一个文件系统到内核中

如何实现临界区

关于引导程序问题

不让root process使用1024以下的端口

get_current()的问题

hard_smp_processor_id()与smp_processor_id()有什么区别?

新兵笔记--ULK(C3) Exception Handing

TCP包处理的后备队列(backlog)和预备队列(prequeue)

解释一下__wait_queue_head结构?还有wake_up

TCP包的校验和

内核日志和内核控制台

minix文件系统的物理结构

关于buddy system的几个问题?

void page_cache_init(u_long mempages)

信号能否重入?

static __inline__和extern __inline__有什么区别?

void __remove_shared_vm_struct(vma)

spinlock

TCP PAWS处理

About Major Number

linux内核启动到底做了什么的资料

listen和accept过程的简要描述

真正的信号高手请进

有关页寿命的疑问

完了,没耐心看了,大侠帮忙,给我讲一下tcp_connect就好!

linux中如何设置stack的大小?

关于struct

GET_CURRENT还有疑问

谁有ARM远程调试的stub的源代码

[精华] 辞职申明 和 学习内核的一些感想

分析calibrate_delay过程

请教内存初始化的问题(reserve mem)

详细解释一下Thread(线程)???

linux 支持内核线程吗


asmlinkage
http://www.kernelnewbies.org/faq/index.php3#asmlinkage.xml




linuxdoc.org的对于Linux线程的一个比较完整的回答

行内汇编中,"o"(var)(不是零)"o"是什麽寄存器,谢谢!

如何在模块中增加系统调用

red black tree

iptables内核数据结构关系图

[serial]中断问题?

console注册与tty注册的区别

make_pages_present(),不知它的具体作用是什么

宏mb()是什么意思?

这是我搜集的linuxkernel兄的大作

linuxkernel兄大作之2

TCP层向外发包时为什么总是将skb进行克隆?

内核防火墙iptables的一条规则(图)

struct dentry中各项意义

关于read_super_block 的一点疑问!

端口读硬盘信息疑问

asmlinkage这个关键字是什么意思

fork()与vfork()的区别

pg0 的问题?

Linux的启动盘与DOS中的启动盘不一样

__attribute__是什么东西,怎么用呀


800 种文件格式
http://www.wotsit.org/default.asp


在linux下读取、修改(如果可能)主板bios的内容

制作基于软盘的Linux系统

调试信息过多造成dmesg无法完全显示怎么办?

Ctrl-D被按下后,产生什么信号?或者根本不产生信号?

关于中断响应

linux内核概念问题,欢迎讨论

介绍一下e820 map的内容

新兵笔记--ULK(C4) Initializing the idt

_set_gate分析

Linux A-Z书中实例的源程序

关于end_mem的一点疑惑

新兵笔记--ULK(C2) beta版

防火墙分析总结

网络包复制

head.S 中的问题

现转载对我帮助很大的文件,十分感谢那位作者!!!

关于MBR的一个问题

ELF的 e_ident[EI_NIDENT]是什么意思?

Makefile中Config.in是什麽文件

virtual address space and physical address

time quantum

Lisoleg的昨天、今天和明天

System.map中的几个标志T,t,B,b,..的问题

内存初始化mem_init中的两个问题


ldd2
Chapter 9: Interrupt Handling
http://www.xml.com/ldd/chapter/book/pdf/ch09.pdf
C & C

mmap
http://kernelnewbies.org/code/mmap/



内核代码可以读取文件或共享内存吗?

内核镜像是如果映射到3G去的?

进程的页目录表中的768项之后的项是不是都是有效的?

内核页目录

关于进程内存空间的映射问题*

Special expression from linux-kernel mailing list

discussion about MaxNumber Of Threads From KernelT

核心态对用户态的数据访问

内核是怎么访问PCI配置空间的?

这么做行不?(请大伙抽空看看)内核中共享内存的如何使用

which Compiler to Use for kernel compiling

GLIBC被多个进程共享疑问

fork()一个子进程时,IPC资源是否可以被子进程继承

malloc()在内核中对应的函数是什么

支持热插拔的驱动程序的框架疑问

回答“关于页面映射计数”

关于内核中加入自己得代码得可行性

用户空间和内核空间之间的数据传输

为什么需要copy_from_user?(转载)

内核启动过程问题(rush老哥看过来,我知道你看过启动代码)

软中断图解

早期的任务切换

谁能说一下iptables.c 和 netfilter.c 的关系?

最近看mm的人很多啊,和大家分享我给自己写的教程

一个疑问 --《Understanding Linux Kernel》

请教linux源代码中的数组问题

skb_reserve - adjust headroom

UNIX核心介绍

分配虚存空间有了mmap和munmap为什么还需要sys_brk?

Write Your Own Operating System Tutorial && FAQ !

some valuable HowtoS for KernelStudy

To get intelX86 docs

如何修改IP流程中的数据包???

请问怎样让我的一个可执行程序在开机过程中自动执行

关于ctags的问题?

关于copy sk_buff的问题

Kernel2.4.18的交换机制分析

系统初启时中断向量表放在哪里

swap in (2.4.0)

handle mm fault (2.4.0)

swap out for Kernel2.4.0

实时进程的时间片赋值问题?

关于驱动程序与实际设备的关联问题

本论坛关于时钟的一个悬而未决的问题

A20是什么东西?

bootsect.s和setup.s问题集锦


bios ox15中断ah=e801
http://www.ctyme.com/intr/int.htm


gas 文档
http://www.gnu.org/manual/gas-2.9.1/


用什么办法可以将系统的gdt给显示出来?

这么生动的赋值方法

在0x104000处的硬件参数表的详细说明

转贴一篇关于mm的文章。

这不是自己覆盖自己吗

do_irq()的问题

misc两个head.s, end, __PAGE_OFFSET

关于interrup和exception

一个setup.S与head.S连接的问题?

终于独立看懂了一个内嵌汇编,兼问个问题

draft BIOS use document for the kernel(里面有讲e820)

start_arch中copy e820_map的问题

2.2的一些task数据结构在2.4里是什么?

关于bottom half

mem_map array

__init 在那儿定义的

有个prototype用了pgprot来做变量。刚好pgprot_t的数据结构定义里又用了pgprot

fixed_addresses 的排列

how to smp

空闲页面free_area结构初试话一问?

setup_arch中的reserve resource!

slab里的free buffer

list_entry的疑惑

linux内核中的同步和互斥专题 (1)

linux内核中的同步和互斥专题(2)

setup_arch()中PFN_UP,PFN_DOWN,PFN_PHYS这三个函数是什么意思

cache_cache里的slab的大小是不是一个page

几个变量的意思(page,mm)

remap_page_range()的疑问!!??

start_kernel 里的 init_modules()问题

linux 内核原代码汇编中 .align 伪指令的意思是什么?

关于task_union

多个内核问题提问

请问关于页计数和页的使用情况的关系的一个问题?

CR3问题?

Linux字符设备基础(转贴)

又是start_kernel里的变量定义问题

ioremap是干什么用的?

Makefile :这行为什麽要有( )

关于flash的一些问题!

100个最佳Linux站点(推荐)

判断process是在user mode还是在kernel mode的标准是什么?

关于ext2的几个问题

谁知道unistd.h里的这段解释是什么意思

关于skbuff得资料

bdata.last_offset和last_pos在何处初始化?

内存管理问题?空闲页的bitmap是干什么的?

noncontiguous memory究竟指的是什么?

再聊聊free_area的bitmap

关于gcc内嵌汇编的一个问题

对bh_base[32]和bh_task_vec[32]的一些猜测

明白了free_area的bitmap了!

软中断softirq

路由问题


http://linux-mm.org/



super block是用来干什么的

研读Linux内核主要是为了做些什么?

Linux内核抢占补丁的基本原理

page描述符起名page,确实不好

请教一个术语--”堆“

#if 1肯定是满足条件,else后面的有什么用

内存管理中常常见到“round up”,它具体是什么意思呢?

我也来问几个关于gcc内嵌汇编的问题

"aka inode"? that is "as know as inode"

谁知道”16M以上的低位物理内存“到底有多大?占了多少百分比物理内存

如何做源程序的补丁?

local_table是什么?在哪里初始化的

汇编call命令调用C函数时,参数是如何通过stack传递的

一段boot的测试代码,有问题,来看看……

读do_basic_setup时碰到的问题(pci)

start_kernel里面的prof_shift干什么用的

HA开发,增强内核,学习好方式

关于spin_lock

vfs的索引节点号i_ino是怎么管理的

ip_route_input

想听听大家是怎么读核的

我的分析是应该首先发送第一片

谈一谈我的内核精简计划,以及目前的进展情况

IP分片与重组的分析与整理

“Practical Unix & Internet Security"。号称是”圣经”式著作

Linux源代码中的几个缩写

几个网络有关的变量

为什么不立刻用长跳转指令重载CS段寄存器呢

当物理空间的的线性地址>;1G的时候,虚拟空间如何解决

请教关于睡眠和唤醒进程的两个函数...

如何读取系统物理内存

freeswan是什么东西呢?

ip_rcv_finish函数一问

inflate.c文件的fill_inbuf()函数中insize的赋值的问题

裁减Linux内核的心得体会

linux下的一个文件的最大尺寸是多少?由什么决定?windows下呢?

请教一个Netfilter的应用问题

使用register_blkdev( ), 做完insmod后,为什么/proc/devices没有我的块设备

应用层->;pci->;disk,这种情况disk的驱动该如何写?

请教一个内存管理问题(挺典型的一个问题)

快速找到connect,socket函数实现的代码

致地讲一下IP_FORWARD那个函数

如何在内核中唤醒和睡眠用户进程??

如何打开.patch文件?

关于IP_FRAGMENT的问题

How It Works: DOS Floppy Disk Boot Sector

How It Works -- Master Boot Record

Minix代码分析之一:引导扇区代码

同一程序加载执行空间分布一样吗?

锁和信号量

内核与根文件系统

读kernel时容易漏掉的几个细节

推荐课题及"目的"

devfs_entry是干什么用的

2.2里的vfsmntlist,2.4改什么了

如何直接向网卡读写数据包?

如何在内核中加入PF_KEY套接字?

enable_irq(),disable_irq().和cli(),sti()之间有什么区别

关于slip模块中使用ioperm

gfp是什么的缩写阿?

关于中断例程中的子进程睡眠问题

连续空间分配的大小问题!

skb->;data为物理地址。为何在第一句中又进行转换

可加载模块写文件出现的奇怪现象 (程序设计经验)

SYMBOL_NAME( )

zone_struct

关于物理地址和虚拟地址的问题

请问linux文件系统层次结构的问题

kmalloc(size)返回的是物理地址,还是虚拟地址

VFS初始化过程中的一些问题

how to use create_proc_info_entry

中断上下文,进程上下文和任务上下文之间的区别---需要进一步深入

混杂模式

video adapter's ROM

本论坛和mailing list的区别!

很高兴能为大家服务, 及一些想法,大伙来参谋参谋

mkfs和fdisk的根本区别在哪儿?



amp - bios 资料
http://spr2.net/up_loader.php


内核等待队列机制介绍
http://www.linuxaid.com.cn/engineer/ideal/kernel/wait_queue.htm
linuxaid的网友ideal竹叶收藏




bootsect.s把大内核复制到高端内存的时候,还是实模式.如何实现的

page-》list

OWNOS操作系统设计书

need_resched 是怎么使用的

请教高手一个关于网络全局变量dev_base的问题

关于页面映射计数的讨论

free_area_init_core对其中struct page的virtual赋值为当前struct page所描述的物理页框的内核虚地址

再和4-1的反做与运算得到的又是什么呢?

__init , __exit , module_init, module_exit是什么意

写个小的OS项目,如何?加之一些感想(完全兴趣与学习目的)

mem_map数组

怎么解决这个include头文件时出现的矛盾

内核命令行是何时在何处传递给内核的

A20是什么?

关于brk与mmap的问题--已解决见另外一个帖子

在mm中,vm_area_struct为什么只用了单链表?

为什么要copy_from_user?

关于网络中接收软中断(net_rx_action)的问题

对UDP包在对包不做任何改变的情况下用udp_check()函数重新计算,结果与原校验和不符?

怎么初始化一个PCI设备?
[目录]

--------------------------------------------------------------------------------


list5



关于queue_task的一个问题


打造软盘上的linux
http://www.linuxfromscratch.org/ to define your own OS distribution.
www.linuxdoc.org to get howtos you want


可以参见下面链接处:
http://www.linuxeden.com/edu/doctext.php?docid=1582
Linux内核调试技术介绍 :)希望有帮助

我根据这个
从源代码打造一个最小化的Linux系统实作篇
http://www.linux.org.tw/CLDP/gb/mini/BuildMin.html#toc6
编linux,但不知道如何安装到指定路径


为你的Linux快速编译所需要的模块
by 刘军民 (fancao0515@0451.com)
http://www-900.ibm.com/developerWorks/linux/l-tip-prompt/tip13/index.shtml





copy_e820_map()问题

合并相邻区函数merge_segments()--2.0.33

关于module的问题

关于卖广告和我对linux的一点意见

timer_interrupt()函数看不明白,请指点

如何驱动键盘灯?

schedule(void)函数一定是可以重入的,对吗?

mmap (2.4.0)

Linux: Using Video RAM as System RAM

Linux: -aa VM in 2.5

一个linux驱动程序的问题

大侠指点一下get_pid的算法?

怎样修改PIPE_BUF的大小限制

操作系统理论的探索 (序言部分)

问题出在你新编译的内核不支持模块的版本识别

版本2.4.16下path_init和path_walk,link_path_walk分析报告

怎么理解记录块缓冲区的内容是一致的?

mark_bh(TIMER_BH)和timer_bh( )

当今日新月异,“对象”横飞,潜读LINUX源码除了提高自身素质外还有哪些令人兴奋的应用前景

一个困扰很久的问题--paging_init()

Linux核心调试环境的搭建

磁盘扇区与磁盘块如何定义以及如何区分使用?

也表处理宏的定义释疑

为什么学习LINUX源码、学到什么程度及怎样学习才能在最短的时间里取得最大的收获?

关于时间中断的一个问题

事物总是从陌生开始认识

关于/dev/shm

怎么在本机上配置一个lxf看源代码?在下对apache网络配置一窍不通

哪位知道哪有/proc的手册么

请问叶框0(0 ~ 4K物理地址空间)是否一直未使用?

剖析Linux任务切换的细节。

请问linux下有没有好的看源码的工具?

system call

低1G虚存是做什么的?

bootsect,setup,head的总结

增加系统调用的血汗经验 贡献给大家

How to use ramfs ???

能否将framebuffer的源码说一下

entry.S(续)

谁知道系统刚启动时BIOS建立的参数表

指点一下《Understanding the Linux Kernel》中的难点

Linux: O(1) Update For 2.4

links4RealtimeLinux

A new era: Carrier-grade Linux for Telecommunicati

lwIP - A Lightweight TCP/IP Stack

sys_arch interface for lwIP 0.5

Raw TCP/IP interface for lwIP 0.5

links4EmbededLinux

man slabinfo , 对其中的SMP部分不得其解

请教一个关于Linux处理外设中断的问题

异常处理函数的压栈

使用VIDEO_CHAR检查内核启动时在何处挂起

为什么用files->;fd[fd]而不用files->;fd_array[fd]

Linux 下网卡混杂模式

修改时间片DEFAUT_PRIORITY,为什么当系统

Lan网卡收到包后,应该比较mac地址。

如果手工触发request_irq登记的中断服务

请介绍关于cacheline相关知识,比方cacheline_pingpong

网络包的接收过程

关于pt_regs

How the PCI Hot Plug Driver Filesystem


iptable用户空间和内核关系的问题?

LINUX文件系统分析草稿--面向微内核的OS设计

希望大家讨论讨论?我们学源码要学到什么时候才能收手?

中国有多少人在做关于kernel的开发(真遗憾偶挖了坑没有人跳进来)

Linux内核中对硬盘控制的有关资料

head.s 中“jmp 1f”的1f是什么意思?

how to get size fo ram?

谈谈自已所尝试的内核分析方法

linux中进程与线程的问题

如何在LKM中执行一个用户空间的程序

为什么32位的系统不支持大于2G的文件?

Linux上是否有类似winsock2上的SPI相对应的接口层?

请问如何驱动这个怪物

用双网卡如何同时传输数据(?)

在内核中如何进行大空间内存的分配??

请帮忙修改程序(do you like this?)

关于Login的一个问题(basic)

offsetof怎么理解

为什么每个磁道有63个扇区,而不是64个

ldd2的Backward Compatibility章节

LDD第三章的一个问题

如何根据pid得到进程的名称

如何将内核编译成无版本检查的呢

about init section (vmlinux.lds)

udp报文转发不了,而icmp报文可以,为什么(undstand it?)

张贴一个别人推荐的很好的内核线程的例子

2.4.16软中断分析图 (again)

about interrupt number : 15 or 16

关于引用内核输出符号的问题

cache不命中的情况

请教/proc/pci(有个pci图)

连续内存与离散内存的问题

请问怎样能够得到一个进程的所有的通讯流量

如何让root不能修改其他用户的口令?

slab对象的地址可以不通过页表映射吗?

atomic_fool_gcc的作用是什么?如果不加gcc可能怎么处理?为什么2.4中没有了

关于缺叶中断的内存管理1

slab对象的地址可以不通过页表映射吗(...?)

about "jmp *%eax

insmod的模块放在哪里?

linux smp 求救

8259A可编程控制器在linux上的初始化

在网络层构造UDP包好像不太合理

如何将内核中printk的输出到屏幕上

Linux在i386处理器在PAE模式下寻址

shell系统流程(哈哈)

网上那有关于a20线的详细介绍

调度 schedule 概念

zone balance 是何意

多一些供献,少一些..

大家看看,是不是《情景分析》说错了?(文件读写)

欢迎calfe,garycao加入版面管理



裁减libc的两个工具
一个是Montavista公司的lib优化工具
基本思想是扫描你的应用程序的库函数调用.将你的应用程序没有用到的库函数删除.
一个是IBM组织的一个minilibc project
http://www-124.ibm.com/developer/opensource/linux/projects/minilibc/


这儿摘录了其中的几个非正式观点,共享.

Some write for the fun/eduction of it and want to to it all.
Some have ego problems and must do it all.
Some do not know how to adapt existing code so they do it all.
Some have really wierd systems with nothing close so must do it all.
Some have not searched enough to know of simulair systems so must do it all.
Some have ethical/comercial problems with licenceses and must do it all.
Some rename code and say he did it all.
Some DO use existing code.



uclinux 分析
http://hhcn.org/uclinux.html


gnu/hurd 介绍
http://www.gnu.org/software/hurd/


几个手册
http://www.refcards.org


netlink socket资料
http://qos.ittc.ukans.edu/netlink/html/


截包零拷贝能不能实现

收集内核FAQ了! 大家如在版面上发现适合的话题请转载一份贴在这儿

local_irq_disable()在smp下究竟是关了所有处理器的中断还是当前处理器中断

读setup.s中的几个问题(openarm的几个连接)

spinlock的设计和实现

在linux中一个进程如何修改其它进程的数据(关注)

Linux的页式内存内存管理

head.S 分析

内核信号量的简单演示(几个进程并发调用down的情况 ppt)

i386内存结构示意图(intel and mine)

内存观点(2.4.0)(精华收集和自己的一点理解)

如何关闭linux的单用户模式

flush_tlb_xxx()这类函数都是干什么用的

设备初始化问题(basic)

System.map有什么用处?

Linux 内核笔记 -- 信号

如何读取指定硬盘扇区号的扇区数据?

关于swapper的问题

linus关于debug tools的一篇旧帖子

What is the meaning of "volatile"?

重新编译内核后不支持VFAT的中文文件名?(内核?)

忙里偷闲:Slab简要分析(一张图)

volatile的含义

kgdb文档

引导与启动部分之head.s部分的注释

系统引导与启动(suzhe前辈的一次报告)-----by linux3-III

系统引导与启动之深入lilo-----(zz by linux3-III)

有那位大虾做过内核裁减

jiffies耗尽后会发生什么

ip层及tcp层的处理究竟谁在做

关于tcp/ip不明白的地方

请问在Linux下如何得知每个CPU的使用率等信息

[ jkl ]__attribute__

问几个很弱地问题...

Ext2 文件系统的硬盘布局

如何修改或去掉以framebuffer方式启动的内核的小企鹅的标志

__copy_user的实现原理

boot loader 的一些研究

ip数据包接收发送

Linux的存储管理(一)

内核启动时传入的参数存放在甚么位置

编译linux内核及注意事项(支持ipv6)(看起来步骤详细)

我是怎样精通了linux内核的?(??)

pci_read_config_byte

[精华] LDD2-CH12-块设备

<<Linux设备驱动程序第二版>;>;第八章 硬件访问

<<Linux设备驱动程序第二版>;>;第六章 时钟管理

《Linux设备驱动程序》第二版译稿 第九章中断处理 by kongming etc

<<Linux设备驱动程序第二版>;>;第九章 中断处理

<<Linux设备驱动程序第二版>;>;导读计划

Linux 设备驱动程序》第二版翻译稿样章(前言)

《Linux 设备驱动程序》第二版中文翻译稿样章(第 6 章 时间流)

《Linux 设备驱动程序》第二版中文译稿样章(第 4 章 调试技术)

Linux设备驱动程序(第一版)完整勘误表

编译内核出错(为什么这种话题很多?)

gdtr,idtr,cr3乃至页目录表,他们之中的地址都是物理地址吗?

vm area的地址映射(多看些讨论有好处)

difference between "return" and "exit"?

关于booting部分的一些链接

[精华] Linux 内核笔记2 - 进程调度

Linux的存储管理(二)

linux内核调试(讨论)

推荐一本浅显易懂的书

此图如何看(e820)

论文“Linux内核进程调度与控制 --源代码分析与研究”

怎样用bochs和vmware测试内核

关于使用kgdb调试内核

Linux中的NAT能同时支持多少连接?

为什么会kernel panic(多多讨论)

task_struct结构中的comm成员是代表什么意思啊

《Linux 设备驱动程序》第二版中文译稿样章(第 15 章 外设总线概述)

注册设备文件处理函数的方法有问题(算个经验)

根文件在那里初始

关于in_interrupt的问题

为你的Linux快速编译所需要的模块 (zz)

关于《Linux 设备驱动程序》第二版中文译稿样章的说明

MODR/M and SIB,whar's the means?

What's the maximum preemption latency

LINUX下的设备驱动程序

[转贴]如何编写Linux操作系统下的设备驱动程序

关于vmalloc的疑问!!!

into entry-armv.s

设备驱动程序如何在启动时加载(faq)

bonding.c的原码分析

驱动开发的基础问题(硬件厂商提供驱动吗?)

LINUX的网络设备中,利用master 和slave来实现负载平衡

学习内核和驱动需要多少硬件知识

Linux 内核笔记3 --内核同步-- 第一部分

uClinux - BFLT Binary Flat Format

[精华] LINUX实时调度研讨。

mmap函数问题

Setup Terminal Systems

首席培训官教新手使用最新的内核

PG_active和PG_referenced

内核中的所有struct semaphore型变量都共享一个spinlock_t变量

进程互斥,PV操作

ldd2第十五章PCI总线阅读随记

Write Once protocol for multi processor

一个pci插槽的pci设备的中断是不是固定的

do_IRQ()问题

page->;mapping和page->;buffer分别是做什么用的?

do_softirq()问题

Linux内核进程调度与控制 --源代码分析与研究 by minipuss

可否核态和用户态直接进行通讯

Linux 内核笔记3 --内核同步-- 第三部分

Linux 内核笔记3 --内核同步-- 第二部分

How to open/read a file in interrupt_context?

Why "scheduling in interrupt" ?

when should i define a variable with "volatile" ?

Kernel/Device Driver questions?(mmap,kmalloc,irq)

"gdb-serial.txt" from "gdbstub.tar.gz"

gdtr中为什么放线形地址 ,而不是物理地址?

代表设备文件ext2_inode节点保存了什么信息保证找到设备的?

[精华] Linux 内核笔记3 - 内核同步(完整版)

内核与用户进程通讯的几种方式比较

我把内存管理FAQ重新整理了一下。

“逻辑地址”、“线性地址”、“物理地址”的区别和联系

关于在内核中向应用程序发送信号的问题

实际一个程序同时可能有多个进程,所以一般由pid找程序名较合理

refill_inactive()函数

又关于page->;buffers和page->;mapping

关于video.s的疑问

关于内存的几个问题

怎么添加上ip伪装和ip端口转发

Running Linux on Linux(User-Mode Linux )?

如何生成可被lilo引导的image?

同志们,为什么浪费0~08048000的进程地址空间不用

关于添加系统调用的问题

作linux向另一个硬件平台的移植工作应该如何入手?要做哪些工作(链接)

kernel精华!(文档包)已经上传到我公司的服务器上了! (有钱出钱)

Kongming给出了ldd2中文版的部分章节,大家抽空读读,对其中细节给点建议

请问如何使网关支持内网上任意IP的上网通讯?

那么MAIN这个进程是什么时候fork的呢?

怎样在内核中读写文件?

LINUX ALLOCATED DEVICES

Interview with Robert Love

请xshell结合这段代码对于cacheline做些解释

HZ 表示每两次时钟中断相隔的微秒数

head.S 中的__PAGE_OFFSET 和其他

谁能讲一讲Console和tty之间的关系?

wmb是干吗的函数 (zz)

这是我在学习设备驱动程序的一点问题?希望大家赐教!

2.4.16下网络结构全景图1.0 (包含模块接口变量名称)

谁有真正能用的Linux启动盘的资料?

Encrypted Ethernet Bridging

More Explicative Kernel Tainting

setup.S中"in al #0x92" 0x92端口的含义

BIOS 数据区域(BDA)位置在哪里?

Why pay someone to port Linux for you?

中断上下文中如何实现文件读写?

wait和completion数据结构的解释

user_struct

谁能解释一下tty,tty0,ttyS0,console,终端,控制台这几个词

Linux MTD源代码分析

请问内核中读写配置文件的源码在哪个目录的哪个文件中

写时复制中关于empty_zero_page的问题

Linux 内核使用的 GNU C 扩展

我的一个Object-oriented operating environment 设想.

是不是所有的包都要用到这里的match,target,在哪个hook用,看得糊涂了

为什么在转发之前需要COPY一下SK_BUFF???

转载一篇文章"泛系、自由与“一、百、万”工程"

2.4.16内核icmp报文处理分析

请问各hook函数之间怎么传递信息:在同一个hook点上的和不同hook点上的函数各自如何传递

关于中断问题的请教

大家有否考虑在Linux上实现一个硬件抽象层?(空)

Linux Kernel Module Programming Guide

可动态编译的嵌入式操作系统

CMOS里的东西在启动后是不是COPY到内存中去了

问个基础的问题

vmalloc的问题

超级宝书http://suse.chinasec.com/ulk.pdf

哪有LINUX内核分析(进程部分)的文章?

写时复制的问题

守护进程里如何发声?

关于swapper_pg_dir初始化的问题

linux 与 minix的共存

我编驱动程序的时候的问题(PCI)

如何实现内存映射?

关于在转发前sk_buff结构copy的问题

Are you familiar with Architecture or OS ?

为什么谁都可?
[目录]

--------------------------------------------------------------------------------


AKA推荐书籍

====================================================================
《The Design of The UNIX Operating System》 Author: Maurice J. Bach
中译本:《UNIX 操作系统设计》
---------------------
翻译者:陈葆钰等
北大版: 32开,黄皮,9.40¥
机工版: 16开,褐皮,30¥
---------------------
一本老书,但绝对是bible级的。其内容覆盖了经典UNIX操作系统中的所有基本概念
以及设计思想。阅读者最好能懂一些基本的操作系统理论知识。
====================================================================
====================================================================
《Unix Internals - The New Frontiers》 Author: Uresh Vahalia
中译本:《UNIX 高级教程:系统技术内幕》
---------------------
翻译者:聊鸿斌等
清华大学出版社出版,16开,桔皮,58¥
---------------------
一本新书,也是bible级的。其主要特点是80%的内容都是现代UNIX操作系统的新思想
和新概念。对各UNIX大家的精彩设计点都有很详尽的阐述。阅读者最好先看看贝奇那
本书。
====================================================================

====================================================================
《Linux Core Kernel Commentary》
---------------------
Author: Scott Maxwell
---------------------
有中译本,但具体信息不详 对照源码讲Linux内核,版本还比较高,2.2.X。有些新
东西可看看。可惜没讲网络部分的实现。
====================================================================

====================================================================
《Linux Kernel Internals: 2nd version》
---------------------
Author: M Beck ...
---------------------
目前无中译本 以数据结构为主体来介绍内核,内容很丰富,但版本太低(2.0.x),有
些陈旧的东西容易令人误入歧途。
====================================================================

====================================================================
《The Design and Implementation of the 4.4BSD Operating System》
---------------------
Author: McKusick, Bostic, Karels, Quarterman
---------------------
目前无中译本  讲述BSD操作系统最权威的书。书的作者亦即BSD最早的几名开发者。
====================================================================

====================================================================
《Linux 操作系统及实验教程》
---------------------
作者:李善平,郑扣根(浙大教师)
机工出版
---------------------
有些内容不错,讲得还比较深入。也缺少网络部分的描述。
====================================================================

====================================================================
《UNIX 系统下的80386》
---------------------
作者:周明德, 张淑玲
清华出版
---------------------
讲X86的体系结构。要想看懂/arch/i386下的辕马,最好先看看这本书。
====================================================================

====================================================================
《UNIX Systems for Modern Architectures》
---------------------
Author: Curt Schimmel
---------------------
目前无中译本  如果想了解辕马中SMP的实现。可参考看这本书。
====================================================================

====================================================================
《保护模式下的80386及其编程》
---------------------
出版社:清华大学出版社
---------------------
本书全面地介绍了80386的结构。首先是80386实模式和保护模式下的寄存器集和
指令集,接着从保护模式下的虚存管理、保护级、多任务支持、中断和异常等方
面深入地剖析386的强大功能,再接着提供几个典型的编程实例以及一个完整的从
386加电初始化开始到形成一个有基本的多任务和虚拟存储能力的系统的例子并作
了详细解释,最后还清楚地说明了80386与8086/80286的兼容性和差别。本书的特
点是严谨深入,对CPU各种条件下的动作和反应用形式化的微程序讲解得十分清楚,
尤其适合系统程序员阅读。总之,这实在是一本不可多得的好书.

====================================================================

====================================================================
《Linux 操作系统的内核分析》 作者:陈莉君编著
---------------------
价格:40 元
出版社:人民邮电出版社
---------------------

====================================================================




[目录]

--------------------------------------------------------------------------------


linux论坛推荐资源

~~~~~~~
一般文献
~~~~~~~
利索脚组织的网站:
http://www.lisoleg.net
linux kernel internals 2.4(不是特别全)

http://www.moses.uklinux.net/patches/lki.html
http://tzhang.xiloo.com/unix/kernel/

UNIX高级教程 系统技术内幕
Uresh Vahalia 清华大学出版社

书。这是一本非常好的书,思想性很强,对学习Linux以及操作系统非常有帮助。

Understanding the Linux Kernel
Daniel P. Bovet  Marco Cesati
O'Reilly出版

超级宝书!2001年内会有中译本。
这里是第10章
Process Scheduling

Linux 操作系统及实验教程
李善平 郑扣根 编著
机械工业出版社

Linux 操作系统的内核分析
陈莉君编著
人民邮电出版社

Linux Device Driver

书。有中译本。帮助理解中断,任务队列等内核机制,帮助掌握驱动编程。

Operating Systems
resource center
jkl 推荐

关于操作系统的介绍,有许多专题文章

http://www.nondot.org/sabre//os/

关于Linux的重要链接
Pengcheng Zou 推荐

给出了许多重要的链接

http://www.linuxlinks.com/Kernel/

非常完备的CPU开发手册

Intel Architecture Software Developer’s Manual
Volume 3:
System Programming

" target="_new">;http://developer.intel.com/design/pentiumii/manuals/24319202.pdf

对i386的机制讲得非常详细,可以帮助深入了解i386保护模式机制,对理解Linux的相关实现非常有帮助

~~~~~~~
关于内存
~~~~~~~

Outline of the Linux Memory Management System
黑饭 推荐

http://home.earthlink.net/~jknapka/linux-mm/vmoutline.html

已经是一个比较细致的介绍内存(包括内核的和用户空间的)了。

SGI公司的公开项目

http://oss.sgi.com/projects/

SGI公司的关于伸缩性的技术非常棒!Linux的NUMA就是由他们做的,这是他们的网页

Linux内存开发小组的网站
jkl 推荐

http://www.linux-mm.org

这是Linux负责开发内存管理的核心成员的网站
下面有他们关于zone设计思想的描述:

http://surriel.com/zone-alloc.html

~~~~~~~
关于中断
~~~~~~~

关于中断上锁的专题文档

http://netfilter.kernelnotes.org/unreliable-guides/kernel-locking/lklockingguide.html

我们知道在中断中写程序要小心,不小心会发生race condition.这篇文献对这方面做了介绍

~~~~~~~~~~
关于文件系统
~~~~~~~~~~

Linux Commentary
dream_seeker 推荐

http://www.cse.unsw.edu.au/~neilb/oss/linux-commentary/

主要介绍文件系统, 另外,下面的

linux-vm-readme

主要介绍VM和交换,也很值得一看



关于汇编
[http://www.linuxassembly.org http://www.linuxassembly.org ]
Linuxkernel推荐


关于AT

http://www-106.ibm.com/developerworks/linux/library/l-ia.html
lisoleg推荐

关于汇编:
http://www-aig.jpl.nasa.gov/public/home/decoste/HTMLS/GNU/binutils/as_toc.html
http://www.linuxassembly.org/resources.html#tutorials
lucian推荐

关于驱动,专门研究linux驱动设计的bbs
http://short.xilubbs.com
joyfire推荐


Edited by lucian_yao on 05/20/01 08:05 PM.






[目录]

--------------------------------------------------------------------------------


数据结构

以下是linux操作系统核心常用的数据结构
block_dev_struct
此结构用于向核心登记块设备,它还被buffer
cache实用。所有此类结构都位于blk_dev数组中。
struct blk_dev_struct {
    void (*request_fn)(void);
    struct request * current_request;
    struct request   plug;
    struct tq_struct plug_tq;
};
buffer_head
此结构包含关于buffer cache中一块缓存的信息。
/* bh state bits */
#define BH_Uptodate  0   /* 1 if the buffer contains valid data      */
#define BH_Dirty     1   /* 1 if the buffer is dirty                 */
#define BH_Lock      2   /* 1 if the buffer is locked                */
#define BH_Req       3   /* 0 if the buffer has been invalidated     */
#define BH_Touched   4   /* 1 if the buffer has been touched (aging) */
#define BH_Has_aged  5   /* 1 if the buffer has been aged (aging)    */
#define BH_Protected 6   /* 1 if the buffer is protected             */
#define BH_FreeOnIO  7   /* 1 to discard the buffer_head after IO    */
struct buffer_head {
  /* First cache line: */
  unsigned long      b_blocknr;    /* block number                   */
  kdev_t             b_dev;        /* device (B_FREE = free)         */
  kdev_t             b_rdev;       /* Real device                    */
  unsigned long      b_rsector;    /* Real buffer location on disk   */
  struct buffer_head *b_next;      /* Hash queue list                */
  struct buffer_head *b_this_page; /* circular list of buffers in one
                                      page                           */
  /* Second cache line: */
  unsigned long      b_state;      /* buffer state bitmap (above)    */
  struct buffer_head *b_next_free;
  unsigned int       b_count;      /* users using this block         */
  unsigned long      b_size;       /* block size                     */
  /* Non-performance-critical data follows. */
  char               *b_data;      /* pointer to data block          */
  unsigned int       b_list;       /* List that this buffer appears  */
  unsigned long      b_flushtime;  /* Time when this (dirty) buffer
                                    * should be written              */
  unsigned long      b_lru_time;   /* Time when this buffer was
                                    * last used.                     */
  struct wait_queue  *b_wait;
  struct buffer_head *b_prev;      /* doubly linked hash list        */
  struct buffer_head *b_prev_free; /* doubly linked list of buffers  */
  struct buffer_head *b_reqnext;   /* request queue                  */
};
device
系统中每个网络设备都用一个设备数据结构来表示。
struct device
{
  /*
   * This is the first field of the "visible" part of this structure
   * (i.e. as seen by users in the "Space.c" file).  It is the name
   * the interface.
   */
  char                    *name;
  /* I/O specific fields                                           */
  unsigned long           rmem_end;        /* shmem "recv" end     */
  unsigned long           rmem_start;      /* shmem "recv" start   */
  unsigned long           mem_end;         /* shared mem end       */
  unsigned long           mem_start;       /* shared mem start     */
  unsigned long           base_addr;       /* device I/O address   */
  unsigned char           irq;             /* device IRQ number    */
  /* Low-level status flags. */
  volatile unsigned char  start,           /* start an operation   */
                          interrupt;       /* interrupt arrived    */
  unsigned long           tbusy;           /* transmitter busy     */
  struct device           *next;
  /* The device initialization function. Called only once.         */
  int                     (*init)(struct device *dev);
  /* Some hardware also needs these fields, but they are not part of
     the usual set specified in Space.c. */
  unsigned char           if_port;         /* Selectable AUI,TP,   */
  unsigned char           dma;             /* DMA channel          */
  struct enet_statistics* (*get_stats)(struct device *dev);
  /*
   * This marks the end of the "visible" part of the structure. All
   * fields hereafter are internal to the system, and may change at
   * will (read: may be cleaned up at will).
   */
  /* These may be needed for future network-power-down code.       */
  unsigned long           trans_start;     /* Time (jiffies) of
                                              last transmit        */
  unsigned long           last_rx;         /* Time of last Rx      */
  unsigned short          flags;           /* interface flags (BSD)*/
  unsigned short          family;          /* address family ID    */
  unsigned short          metric;          /* routing metric       */
  unsigned short          mtu;             /* MTU value            */
  unsigned short          type;            /* hardware type        */
  unsigned short          hard_header_len; /* hardware hdr len     */
  void                    *priv;           /* private data         */
  /* Interface address info. */
  unsigned char           broadcast[MAX_ADDR_LEN];
  unsigned char           pad;
  unsigned char           dev_addr[MAX_ADDR_LEN];
  unsigned char           addr_len;        /* hardware addr len    */
  unsigned long           pa_addr;         /* protocol address     */
  unsigned long           pa_brdaddr;      /* protocol broadcast addr*/
  unsigned long           pa_dstaddr;      /* protocol P-P other addr*/
  unsigned long           pa_mask;         /* protocol netmask     */
  unsigned short          pa_alen;         /* protocol address len */
  struct dev_mc_list      *mc_list;        /* M'cast mac addrs     */
  int                     mc_count;        /* No installed mcasts  */
  struct ip_mc_list       *ip_mc_list;     /* IP m'cast filter chain */
  __u32                   tx_queue_len;    /* Max frames per queue   */
  /* For load balancing driver pair support */
  unsigned long           pkt_queue;       /* Packets queued       */
  struct device           *slave;          /* Slave device         */
  struct net_alias_info   *alias_info;     /* main dev alias info  */
  struct net_alias        *my_alias;       /* alias devs           */
  /* Pointer to the interface buffers. */
  struct sk_buff_head     buffs[DEV_NUMBUFFS];
  /* Pointers to interface service routines. */
  int                     (*open)(struct device *dev);
  int                     (*stop)(struct device *dev);
  int                     (*hard_start_xmit) (struct sk_buff *skb,
                                              struct device *dev);
  int                     (*hard_header) (struct sk_buff *skb,
                                          struct device *dev,
                                          unsigned short type,
                                          void *daddr,
                                          void *saddr,
                                          unsigned len);
  int                     (*rebuild_header)(void *eth,
                                          struct device *dev,
                                          unsigned long raddr,
                                          struct sk_buff *skb);
  void                    (*set_multicast_list)(struct device *dev);
  int                     (*set_mac_address)(struct device *dev,
                                          void *addr);
  int                     (*do_ioctl)(struct device *dev,
                                          struct ifreq *ifr,
                                          int cmd);
  int                     (*set_config)(struct device *dev,
                                          struct ifmap *map);
  void                    (*header_cache_bind)(struct hh_cache **hhp,
                                          struct device *dev,
                                          unsigned short htype,
                                          __u32 daddr);
  void                    (*header_cache_update)(struct hh_cache *hh,
                                          struct device *dev,
                                          unsigned char *  haddr);
  int                     (*change_mtu)(struct device *dev,
                                          int new_mtu);
  struct iw_statistics*   (*get_wireless_stats)(struct device *dev);
};
device_struct
此结构被块设备和字符设备用来向核心登记(包含设备名称以及可对此设备进行的
文件操作)。chrdevs和blkdevs中的每个有效分别表示一个字符设备和块设备。
struct device_struct {
    const char * name;
    struct file_operations * fops;
};
file
每个打开的文件、套接口都用此结构表示。
struct file {
  mode_t f_mode;
  loff_t f_pos;
  unsigned short f_flags;
  unsigned short f_count;
  unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
  struct file *f_next, *f_prev;
  int f_owner;         /* pid or -pgrp where SIGIO should be sent */
  struct inode * f_inode;
  struct file_operations * f_op;
  unsigned long f_version;
  void *private_data;  /* needed for tty driver, and maybe others */
};
files_struct
描叙被某进程打开的所有文件。
struct files_struct {
  int count;
  fd_set close_on_exec;
  fd_set open_fds;
  struct file * fd[NR_OPEN];
};
fs_struct
struct fs_struct {
  int count;
  unsigned short umask;
  struct inode * root, * pwd;
};
gendisk
包含关于某个硬盘的信息。用于磁盘初始化与分区检查时。
struct hd_struct {
    long start_sect;
    long nr_sects;
};
struct gendisk {
    int major;               /* major number of driver */
    const char *major_name;  /* name of major driver */
    int minor_shift;         /* number of times minor is shifted to
                                get real minor */
    int max_p;               /* maximum partitions per device */
    int max_nr;              /* maximum number of real devices */
    void (*init)(struct gendisk *);
                             /* Initialization called before we
                                do our thing */
    struct hd_struct *part;  /* partition table */
    int *sizes;              /* device size in blocks, copied to
                                blk_size[] */
    int nr_real;             /* number of real devices */
    void *real_devices;      /* internal use */
    struct gendisk *next;
};
inode
此VFS inode结构描叙磁盘上一个文件或目录的信息。
struct inode {
    kdev_t                       i_dev;
    unsigned long                i_ino;
    umode_t                      i_mode;
    nlink_t                      i_nlink;
    uid_t                        i_uid;
    gid_t                        i_gid;
    kdev_t                       i_rdev;
    off_t                        i_size;
    time_t                       i_atime;
    time_t                       i_mtime;
    time_t                       i_ctime;
    unsigned long                i_blksize;
    unsigned long                i_blocks;
    unsigned long                i_version;
    unsigned long                i_nrpages;
    struct semaphore             i_sem;
    struct inode_operations      *i_op;
    struct super_block           *i_sb;
    struct wait_queue            *i_wait;
    struct file_lock             *i_flock;
    struct vm_area_struct        *i_mmap;
    struct page                  *i_pages;
    struct dquot                 *i_dquot[MAXQUOTAS];
    struct inode                 *i_next, *i_prev;
    struct inode                 *i_hash_next, *i_hash_prev;
    struct inode                 *i_bound_to, *i_bound_by;
    struct inode                 *i_mount;
    unsigned short               i_count;
    unsigned short               i_flags;
    unsigned char                i_lock;
    unsigned char                i_dirt;
    unsigned char                i_pipe;
    unsigned char                i_sock;
    unsigned char                i_seek;
    unsigned char                i_update;
    unsigned short               i_writecount;
    union {
        struct pipe_inode_info   pipe_i;
        struct minix_inode_info  minix_i;
        struct ext_inode_info    ext_i;
        struct ext2_inode_info   ext2_i;
        struct hpfs_inode_info   hpfs_i;
        struct msdos_inode_info  msdos_i;
        struct umsdos_inode_info umsdos_i;
        struct iso_inode_info    isofs_i;
        struct nfs_inode_info    nfs_i;
        struct xiafs_inode_info  xiafs_i;
        struct sysv_inode_info   sysv_i;
        struct affs_inode_info   affs_i;
        struct ufs_inode_info    ufs_i;
        struct socket            socket_i;
        void                     *generic_ip;
    } u;
};
ipc_perm
此结构描叙对一个系统V IPC对象的存取权限。
struct ipc_perm
{
  key_t  key;
  ushort uid;   /* owner euid and egid */
  ushort gid;
  ushort cuid;  /* creator euid and egid */
  ushort cgid;
  ushort mode;  /* access modes see mode flags below */
  ushort seq;   /* sequence number */
};
irqaction
用来描叙系统的中断处理过程。
struct irqaction {
  void (*handler)(int, void *, struct pt_regs *);
  unsigned long flags;
  unsigned long mask;
  const char *name;
  void *dev_id;
  struct irqaction *next;
};
linux_binfmt
用来表示可被Linux理解的二进制文件格式。
struct linux_binfmt {
  struct linux_binfmt * next;
  long *use_count;
  int (*load_binary)(struct linux_binprm *, struct  pt_regs * regs);
  int (*load_shlib)(int fd);
  int (*core_dump)(long signr, struct pt_regs * regs);
};
mem_map_t
用来保存每个物理页面的信息。
typedef struct page {
  /* these must be first (free area handling) */
  struct page        *next;
  struct page        *prev;
  struct inode       *inode;
  unsigned long      offset;
  struct page        *next_hash;
  atomic_t           count;
  unsigned           flags;     /* atomic flags, some possibly
                                   updated asynchronously */
  unsigned           dirty:16,
                     age:8;
  struct wait_queue  *wait;
  struct page        *prev_hash;
  struct buffer_head *buffers;
  unsigned long      swap_unlock_entry;
  unsigned long      map_nr;    /* page->;map_nr == page - mem_map */
} mem_map_t;
mm_struct
用来描叙某任务或进程的虚拟内存。
struct mm_struct {
  int count;
  pgd_t * pgd;
  unsigned long context;
  unsigned long start_code, end_code, start_data, end_data;
  unsigned long start_brk, brk, start_stack, start_mmap;
  unsigned long arg_start, arg_end, env_start, env_end;
  unsigned long rss, total_vm, locked_vm;
  unsigned long def_flags;
  struct vm_area_struct * mmap;
  struct vm_area_struct * mmap_avl;
  struct semaphore mmap_sem;
};
pci_bus
表示系统中的一个PCI总线。
struct pci_bus {
  struct pci_bus  *parent;     /* parent bus this bridge is on */
  struct pci_bus  *children;   /* chain of P2P bridges on this bus */
  struct pci_bus  *next;       /* chain of all PCI buses */
  struct pci_dev  *self;       /* bridge device as seen by parent */
  struct pci_dev  *devices;    /* devices behind this bridge */
  void    *sysdata;            /* hook for sys-specific extension */
  unsigned char  number;       /* bus number */
  unsigned char  primary;      /* number of primary bridge */
  unsigned char  secondary;    /* number of secondary bridge */
  unsigned char  subordinate;  /* max number of subordinate buses */
};
pci_dev
表示系统中的每个PCI设备,包括PCI-PCI和PCI-PCI桥接器。
/*
* There is one pci_dev structure for each slot-number/function-number
* combination:
*/
struct pci_dev {
  struct pci_bus  *bus;      /* bus this device is on */
  struct pci_dev  *sibling;  /* next device on this bus */
  struct pci_dev  *next;     /* chain of all devices */
  void    *sysdata;          /* hook for sys-specific extension */
  unsigned int  devfn;       /* encoded device & function index */
  unsigned short  vendor;
  unsigned short  device;
  unsigned int  class;       /* 3 bytes: (base,sub,prog-if) */
  unsigned int  master : 1;  /* set if device is master capable */
  /*
   * In theory, the irq level can be read from configuration
   * space and all would be fine.  However, old PCI chips don't
   * support these registers and return 0 instead.  For example,
   * the Vision864-P rev 0 chip can uses INTA, but returns 0 in
   * the interrupt line and pin registers.  pci_init()
   * initializes this field with the value at PCI_INTERRUPT_LINE
   * and it is the job of pcibios_fixup() to change it if
   * necessary.  The field must not be 0 unless the device
   * cannot generate interrupts at all.
   */
  unsigned char  irq;        /* irq generated by this device */
};
request
被用来向系统的块设备发送请求。它总是向buffer cache读出或写入数据块。
struct request {
    volatile int rq_status;
#define RQ_INACTIVE            (-1)
#define RQ_ACTIVE              1
#define RQ_SCSI_BUSY           0xffff
#define RQ_SCSI_DONE           0xfffe
#define RQ_SCSI_DISCONNECTING  0xffe0
    kdev_t rq_dev;
    int cmd;        /* READ or WRITE */
    int errors;
    unsigned long sector;
    unsigned long nr_sectors;
    unsigned long current_nr_sectors;
    char * buffer;
    struct semaphore * sem;
    struct buffer_head * bh;
    struct buffer_head * bhtail;
    struct request * next;
};
rtable
用来描叙向某个IP主机发送包的路由信息。此结构在IP路由cache内部实用。
struct rtable
{
    struct rtable     *rt_next;
    __u32             rt_dst;
    __u32             rt_src;
    __u32             rt_gateway;
    atomic_t          rt_refcnt;
    atomic_t          rt_use;
    unsigned long     rt_window;
    atomic_t          rt_lastuse;
    struct hh_cache   *rt_hh;
    struct device     *rt_dev;
    unsigned short    rt_flags;
    unsigned short    rt_mtu;
    unsigned short    rt_irtt;
    unsigned char     rt_tos;
};
semaphore
保护临界区数据结构和代码信号灯。
struct semaphore {
    int count;
    int waking;
    int lock ;                /* to make waking testing atomic */
    struct wait_queue *wait;
};
sk_buff
用来描叙在协议层之间交换的网络数据。
struct sk_buff
{
  struct sk_buff      *next;       /* Next buffer in list
*/
  struct sk_buff      *prev;       /* Previous buffer in list
*/
  struct sk_buff_head *list;       /* List we are on
*/
  int                 magic_debug_cookie;
  struct sk_buff      *link3;      /* Link for IP protocol level buffer chai
ns *
  struct sock         *sk;         /* Socket we are owned by
*/
  unsigned long       when;        /* used to compute rtt's
*/
  struct timeval      stamp;       /* Time we arrived
*/
  struct device       *dev;        /* Device we arrived on/are leaving by
*/
  union
  {
      struct tcphdr   *th;
      struct ethhdr   *eth;
      struct iphdr    *iph;
      struct udphdr   *uh;
      unsigned char   *raw;
      /* for passing file handles in a unix domain socket */
      void            *filp;
  } h;
  union
  {
      /* As yet incomplete physical layer views */
      unsigned char   *raw;
      struct ethhdr   *ethernet;
  } mac;
  struct iphdr        *ip_hdr;     /* For IPPROTO_RAW
*/
  unsigned long       len;         /* Length of actual data
*/
  unsigned long       csum;        /* Checksum
*/
  __u32               saddr;       /* IP source address
*/
  __u32               daddr;       /* IP target address
*/
  __u32               raddr;       /* IP next hop address
*/
  __u32               seq;         /* TCP sequence number
*/
  __u32               end_seq;     /* seq [+ fin] [+ syn] + datalen
*/
  __u32               ack_seq;     /* TCP ack sequence number
*/
  unsigned char       proto_priv[16];
  volatile char       acked,       /* Are we acked ?
*/
                      used,        /* Are we in use ?
*/
                      free,        /* How to free this buffer
*/
                      arp;         /* Has IP/ARP resolution finished
*/
  unsigned char       tries,       /* Times tried
*/
                      lock,        /* Are we locked ?
*/
                      localroute,  /* Local routing asserted for this frame
*/
                      pkt_type,    /* Packet class
*/
                      pkt_bridged, /* Tracker for bridging
*/
                      ip_summed;   /* Driver fed us an IP checksum
*/
#define PACKET_HOST         0        /* To us
  */
#define PACKET_BROADCAST    1        /* To all
  */
#define PACKET_MULTICAST    2        /* To group
  */
#define PACKET_OTHERHOST    3        /* To someone else
  */
  unsigned short      users;       /* User count - see datagram.c,tcp.c
*/
  unsigned short      protocol;    /* Packet protocol from driver.
*/
  unsigned int        truesize;    /* Buffer size
*/
  atomic_t            count;       /* reference count
*/
  struct sk_buff      *data_skb;   /* Link to the actual data skb
*/
  unsigned char       *head;       /* Head of buffer
*/
  unsigned char       *data;       /* Data head pointer
*/
  unsigned char       *tail;       /* Tail pointer
*/
  unsigned char       *end;        /* End pointer
*/
  void                (*destructor)(struct sk_buff *); /* Destruct function
*/
  __u16               redirport;   /* Redirect port
*/
};
sock
包含BSD套接口的协议相关信息。例如对于一个INET(Internet AddressDomain)套接口

此数据结构 包含TCP/IP和UDP/IP信息。
struct sock
{
    /* This must be first. */
    struct sock             *sklist_next;
    struct sock             *sklist_prev;
    struct options          *opt;
    atomic_t                wmem_alloc;
    atomic_t                rmem_alloc;
    unsigned long           allocation;       /* Allocation mode */
    __u32                   write_seq;
    __u32                   sent_seq;
    __u32                   acked_seq;
    __u32                   copied_seq;
    __u32                   rcv_ack_seq;
    unsigned short          rcv_ack_cnt;      /* count of same ack */
    __u32                   window_seq;
    __u32                   fin_seq;
    __u32                   urg_seq;
    __u32                   urg_data;
    __u32                   syn_seq;
    int                     users;            /* user count */
  /*
   *    Not all are volatile, but some are, so we
   *     might as well say they all are.
   */
    volatile char           dead,
                            urginline,
                            intr,
                            blog,
                            done,
                            reuse,
                            keepopen,
                            linger,
                            delay_acks,
                            destroy,
                            ack_timed,
                            no_check,
                            zapped,
                            broadcast,
                            nonagle,
                            bsdism;
    unsigned long           lingertime;
    int                     proc;
    struct sock             *next;
    struct sock             **pprev;
    struct sock             *bind_next;
    struct sock             **bind_pprev;
    struct sock             *pair;
    int                     hashent;
    struct sock             *prev;
    struct sk_buff          *volatile send_head;
    struct sk_buff          *volatile send_next;
    struct sk_buff          *volatile send_tail;
    struct sk_buff_head     back_log;
    struct sk_buff          *partial;
    struct timer_list       partial_timer;
    long                    retransmits;
    struct sk_buff_head     write_queue,
                            receive_queue;
    struct proto            *prot;
    struct wait_queue       **sleep;
    __u32                   daddr;
    __u32                   saddr;            /* Sending source */
    __u32                   rcv_saddr;        /* Bound address */
    unsigned short          max_unacked;
    unsigned short          window;
    __u32                   lastwin_seq;      /* sequence number when we las
t
                                                 updated the window we offer
*/
    __u32                   high_seq;         /* sequence number when we did

                                                 current fast retransmit */
    volatile unsigned long  ato;              /* ack timeout */
    volatile unsigned long  lrcvtime;         /* jiffies at last data rcv */





[目录]

--------------------------------------------------------------------------------


重新编译

1.核心的源程序:
    我现在在用TLC, REDHAT也用过, SLACKWARE也用过. 无论哪一种, 都是把核心源程
序放到 /usr/src/linux 下, 因为有些别的应用程序在编译时好像也会从这个路径来引
用一些头文件之类. 一般来说这个 linux 目录都只是个符号连接, 有一点点像WIN下的
Shortcut, 而实际上它对应的目录可能是 /usr/src/linux-2.0.35 之类. RedHat的缺省
安装好像并不装源程序, 只有些头文件.
    以现在的2.2.5 核心为例, 我装的时候就是这样(其实什么版本都一样
    cd /usr/src
    rm linux
    # 这个linux只是个符号连接, 删掉它没事的. 可以 ls -l 看看, 如果看到这个:
    # linux ->; linux-XXXXX, 就表示它是个连接而已. 原来的源程序在箭头后的目录.
    tar zxvf XXXXXXX/linux-2.2.5.tar.gz
    # 这个包解开后, 新核心的源程序就放在了新建立的linux目录下, 这可是个货真价
    # 实的目录.
    mv linux linux-2.2.5
    ln -s linux-2.2.5 linux
    # 按照惯例, 还是把目录另命个名, 再重新做个linux的符号连接
2.准备编译:
    现在要做一些准备工作. 对于新释放出来的核心源程序也没啥好做的, 就打一个:
    cd /usr/src/linux
    make menuconfig

    然后就会看到一个很友好的界面(在LINUX下...已经是很友好的了), 大致上有点像
WIN 9X安装时的选择安装项目. 这就是在配置核心, 选择哪些内容要, 哪些不要.
然后选EXIT退出来, 问是否保存修改时答YES. 然后会有一些提示. 如果看到了有叫你
"make dep", 就要打"make dep"先. 完了后就打 make bzImage. 如果提示信息中没有
叫你"make dep", 只有叫你 "make zImage", "make zdisk" 或 "make zlilo" 的,
就直接打 make bzImage 就行了.

一点说明: make dep 是作一些准备工作, make bzImage 则是开始编译生成核心. 而
          make bzImage与make zImage的区别在于, 作成bzImage的核心压缩率比zImage
          高, 核心就更小一些. make zdisk 与 make zlilo 是做别的用处的核心的.

    然后就等吧(有得你等的). 一般从5分钟到半个钟头不等, 看你的机器了. 第一次编
译会 比较慢. 以后再改了配置后make就会快很多了.

    等这个完了后一定还要 make modules 和 make modules_install.

make bzImage 完后会显示核心放在什么地方, 一般是/usr/src/linux/arch/i386/boot/
下. 把bzImage拷到根下. 然后修改 /etc/lilo.conf, 照着原来的image = XXXXX来加上
image = /bzImage
  root = /dev/hda1 (这里视你的LINUX安装而定, 照你原有的改)
  label = linux
  read-only
    把原来的 label = linux 改一下, 如 label = oldlinux.
    把image = /bzImage 这一节加在原来的前面, 这样会自动作为缺省的核心. 你也可以在
LILO时打linux或oldlinux来启动不同的核心. 关于这一段, 也可以参考俺前面的"ALS007
发声经过". 最后, 切记切记, 一定要打个lilo来重新生成LILO程序.

好了, 重启...





[目录]

--------------------------------------------------------------------------------


重建内核选项

       prompt for development and/or incomplete code/drivers
             很多参考书上说这是那些开发人员认为还不是很稳定的功能,但
             是根据我的经验,这个是应该选的一个选项,因为现代的LINUX是
             建立在这些基础上的,所以应该可以回答Y,除非你只是想使用
             LINUX中已经完全定型的东西,但性能肯定不会好到哪,而且对系
             统特性的支持也不会好。
       processor family (386,486/cx486,586/k5/5x86/6x86,pentinum/k6/tsc,ppro/6x86)
             这应该没有太多可说的吧,选择你的CPU的种类,BIOS可以自检得
             到,注意系统的启动信息。需要注意的是不能选择比你的CPU类型
             还高级的CPU,否则可能不能正常工作。

       math emulation
             模拟数学协处理器,如果你的机器没有数学协处理器,那就选上
             以提高性能,但486以后数学协处理器就集成到CPU内部了,应该是
             用不上的,所以一般的选择是N。当然选上也不会有什么问题,除
             了内 松陨 变大外。

       mttr(memory type range register) support
             这个选项是用来启动pentinum pro和pentinum II 的特殊功能,如果你用
             的不是这类CPU就选N,否则也仅仅是使内核变大而已。

       symmetric multi-processing support
             同步处理器支持,如果你有多个CPU就选上吧。

       enable loadable module support
             这会启动动态载入额外模块的功能,所以一定选上。

       set version information on all symbols for modules
             这个选项可以为某个版本的内核而编译的模块在另一个版本的内
             核下使用,但一般用不上。

        kernel module loader
             如果你启用这个选项,你可以通过kerneld程序的帮助在需要的时候
             自动载入或卸载那些可载入式的模块。建议选上。

         networking support
             如果你用到任何网络就应该选上

         pci bios support
             这个一般是应该选上的,除非你用没有任何PCI设备的机器。PCI
             BIOS是用来侦测并启用PCI设备的。

         pci bridge optimization(v1.3)
             当这个选项被启动时,操作系统会对从CPU和系统内存在PCI总线
             来往的数据做最佳化,这个功能已经完成实验阶段,使用起来应
             该很安全,而且还可增进系统的效率。

         system v ipc
             起用这个选项可以使内核支持System V 的进程间通信的功能
             (IPC),有些从System V转移过来的程序会需要这个功能,建议启
             用该功能。

         sysctl support
             除非你的内存少的可怜,否则你应该启动这个功能,启用该选项
             后内核会大8K,但能让你直接改变内核的参数而不必重新开机。

         kernel support for elf binaries
             该选项让你的系统得以执行用ELF格式存储的可执行文件,而ELF
             是现代LINUX的可执行文件、目标文件和系统函数库的标准格式。
             当操作系统要和编译器以及连接器合作时会需要这些标准,所以
             应该回答Y。

         compile kernel as elf
             这选项让你的内核本身以ELF的格式编译,如果你的系统上的过程
             gcc默认产生ELF格式的可执行文件,那么你就应该启动这个选项。
             先看看你的编译器的版本再决定。

         parallel port support
             如果你有任何并行口的设备并且想让LINUX使用,那么就可以启用
             这个选项。LINUX不仅可以使用并口的打印机,还可以支持PLIP
             (一种为并行口而设计的网络通讯协定),ZIP磁盘驱动器、扫描
             仪等。在大多情况下,你需要额外的驱动程序才能使用外接的并
             口设备。

         plug and play support
             支持PNP设备并非Microsoft的专利,如果你要让LINUX也支持PNP设
             备,只要启用该选项就可以,但有些情况下会和其他设备产生冲
             突(I/O,DMA,IRQ等)。这个选项对PCI设备没有影响,因为他们
             天生就是PNP设备。

         normal floppy disk support
             除非你不想在LINUX下使用软盘,否则就应该回答Y。但对于一些
             不需要支持软盘驱动器的系统而言,这个选项可以节省一些内
             存。

         enhanced ide/mfm/dll disk support
             除非你不需要MFM/DLL/IDE硬盘的的支持,否则就应该回答Y,但如
             果你只有SCSI的硬盘,关掉这个选项会比较安全。

         enhanced ide/mfm/dll cdrom support
             和上面的类似,只不过是对CDROM的支持而已。

         enhanced ide/mfm/dll tape support
             一般没有多少人在用磁带机吧,所以回答N是比较好的答案。

        enhanced ide/mfm/dll floppy support
             这个设备好象一般也没有人用,所以也可以回答N。

        xt harddisk support
             如果你有这种石器时代的XT硬盘,那么恭喜你你可以用上他了。

        parallel port ide device support
             LINUX是支持这种很新的并口的IDE设备的,如果你有的话就用上
             吧。

        networking options
             如果你在前面选了支持网络的话,在这里会回答很多问题。除非
             你有特别的需求,否则使用默认的选项应该就足够了。

        scsi support
             如果你有任何一种SCSI控制卡,这个选项就应该回答Y。事先搞清
             楚你的硬件的类型,因为这些问题都是针对特定的SCSI控制芯片和
             控制卡的,如果你不确定自己使用的是哪一种,查看你的硬件的
             说明文件或者LINUX的HOWTO文档。同样也会让你回答很多SCSI设
             备的支持(硬盘、CDROM、Tape、floppy等),依据你的情况选择。
             如果你没有SCSI设备的话,建议不要支持,因为这会节约很多内核
             空间。

         network device support
             这里面有很多关于网络控制卡的问题,如果你无法确定如何正确
             选择,查看硬件文档或LINUX HOWTO文档。

         amateur radio support
             这个选项可以用来启动无线网络的基本支持,目前的无线网络可
             以通过公众频率传输数据,如果你有此类设备就可以启用,具体
             请参考AX25和HAM HOWTO 文档。
             isdn subsystem
             如果你有ISDN硬件就应该启用该选项并安装合适的硬件驱动程
             序,你应该还会需要启用Support synchronous PPP选项(参考PPP over
             ISDN)。

         old cd-rom drivers
             这是针对一些特殊光盘驱动器程序的问题,如果你有IDE或SCSI的
             CDROM控制卡,那么就不用启用该选项了。

      
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP