Linux系统中断处理框架(3)

Linux系统中断处理框架的初始化调用流程为:


//init/main.c
asmlinkage void __init start_kernel(void)

{
……
    trap_init(); //空函数
……

   early_irq_init();

   init_IRQ();

……

}

在start_kernel()函数中调用了early_irq_init()函数,根据内核配置时是否选择了CONFIG_SPARSE_IRQ,而可以选择两个不同版本的该函数early_irq_init()中的一个进行编译。CONFIG_SPARSE_IRQ配置项,用于支持稀疏irq号,对于发行版的内核很有用,它允许定义一个高CONFIG_NR_CPUS值,但仍然不希望消耗太多内存的情况。

//arch/arm/kernel/irq/irqdesc.c/
int __init early_irq_init(void)
{
        int i, initcnt, node = first_online_node;
        struct irq_desc *desc;

        init_irq_default_affinity();  //由CONFIG_SMP宏决定是否为空函数,见下面分析一

        /* Let arch update nr_irqs and return the nr of preallocated irqs */
        initcnt = arch_probe_nr_irqs();//体系结构相关的代码来决定预先分配的中断描述符的个数见分析二
       
        if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS))  //见下面分析三
                nr_irqs = IRQ_BITMAP_BITS;

        if (WARN_ON(initcnt > IRQ_BITMAP_BITS))
                initcnt = IRQ_BITMAP_BITS;

        if (initcnt > nr_irqs)
                nr_irqs = initcnt;
        for (i = 0; i < initcnt; i++) {
                desc = alloc_desc(i, node, NULL);  //分配 struct irq_desc结构,分析四
                set_bit(i, allocated_irqs);  //设置相应的位数组,分析三
                irq_insert_desc(i, desc);  //保存irq_desc指针,分析四
        }
        return arch_early_irq_init(); //kernel/softirq.c中定义,为空函数
}
//arch/arm/kernel/irq.c
void __init init_IRQ(void)
{
        int ret;
        /*
         *在.config文件中CONFIG_OF有定义,并且通过分析2可知machine_desc->init_irq为空。
         *
         */
        if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq) 
                irqchip_init(); //函数被执行,分析五
        else
                machine_desc->init_irq();
       //machine_desc->l2c_aux_mask和machine_desc->l2c_aux_val初始化为零所以下面不执行
        if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_CACHE_L2X0) &&  
            (machine_desc->l2c_aux_mask || machine_desc->l2c_aux_val)) {
                if (!outer_cache.write_sec)
                        outer_cache.write_sec = machine_desc->l2c_write_sec;
                ret = l2x0_of_init(machine_desc->l2c_aux_val,
                                   machine_desc->l2c_aux_mask);
                if (ret)
                        pr_err("L2C: failed to init: %d\n", ret);
        }

        uniphier_cache_init();  //arch/arm/include/asm/hardware/cache-uniphier.h 为空
}

分析1: static void __init init_irq_default_affinity(void)

//arch/arm/kernel/irq/irqdesc.c
#if defined(CONFIG_SMP)
static void __init init_irq_default_affinity(void)
{
        alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
        cpumask_setall(irq_default_affinity);
}
#else
static void __init init_irq_default_affinity(void)
{
}
#endif

分析2:int __init arch_probe_nr_irqs(void)

//arch/arm/kernel/irq.c
#ifdef CONFIG_SPARSE_IRQ
int __init arch_probe_nr_irqs(void)
{
        nr_irqs = machine_desc->nr_irqs ? machine_desc->nr_irqs : NR_IRQS;//NR_IRQS   16
        return nr_irqs;  //分析下面的分析,得知返回的是NR_IRQS
}
#endif


/*
 *NR_IRQS //体系结构相关的代码来决定预先分配的中断描述符的个数
 *arch/arm/kernel/irq.c中包含#include <linux/irq.h>
 *include/linux/irq.h中包含#include <asm/irq.h>
 */
//arch/arm/include/asm/irq.h
#define NR_IRQS_LEGACY  16

#ifndef CONFIG_SPARSE_IRQ
#include <mach/irqs.h>
#else
#define NR_IRQS NR_IRQS_LEGACY
#endif


/*
 *machine_desc在setup_arch中赋值,machine_desc指向了arch/arm/mach-s5pv210/s5pv210.c中定义的
 *DT_MACHINE_START(S5PV210_DT, "Samsung S5PC110/S5PV210-based board")
 *具体分析如下
 */
//arch/arm/kernel/setup.c
const struct machine_desc *machine_desc __initdata;
 

//arch/arm/mach-s5pv210/s5pv210.c
DT_MACHINE_START(S5PV210_DT, "Samsung S5PC110/S5PV210-based board")
        .dt_compat = s5pv210_dt_compat,
        .map_io = s5pv210_dt_map_io,
        .restart = s5pv210_dt_restart,
        .init_late = s5pv210_dt_init_late,
MACHINE_END


/*
 * Set of macros to define architecture features.  This is built into
 * a table by the linker.
 */
#define MACHINE_START(_type,_name)                      \
static const struct machine_desc __mach_desc_##_type    \
 __used                                                 \
 __attribute__((__section__(".arch.info.init"))) = {    \
        .nr             = MACH_TYPE_##_type,            \
        .name           = _name,

#define MACHINE_END                             \
};


#define DT_MACHINE_START(_name, _namestr)               \
static const struct machine_desc __mach_desc_##_name    \
 __used                                                 \
 __attribute__((__section__(".arch.info.init"))) = {    \
        .nr             = ~0,                           \
        .name           = _namestr,

#endif


//arch/arm/include/asm/mach/arch.h
struct machine_desc {
        unsigned int            nr;             /* architecture number  */
        const char              *name;          /* architecture name    */
        unsigned long           atag_offset;    /* tagged list (relative) */
        const char *const       *dt_compat;     /* array of device tree
                                                 * 'compatible' strings */

        unsigned int            nr_irqs;        /* number of IRQs */

#ifdef CONFIG_ZONE_DMA
        phys_addr_t             dma_zone_size;  /* size of DMA-able area */
#endif

        unsigned int            video_start;    /* start of video RAM   */
        unsigned int            video_end;      /* end of video RAM     */

        unsigned char           reserve_lp0 :1; /* never has lp0        */
        unsigned char           reserve_lp1 :1; /* never has lp1        */
        unsigned char           reserve_lp2 :1; /* never has lp2        */
        enum reboot_mode        reboot_mode;    /* default restart mode */
        unsigned                l2c_aux_val;    /* L2 cache aux value   */
        unsigned                l2c_aux_mask;   /* L2 cache aux mask    */
        void                    (*l2c_write_sec)(unsigned long, unsigned);
        const struct smp_operations     *smp;   /* SMP operations       */
        bool                    (*smp_init)(void);
        void                    (*fixup)(struct tag *, char **);
        void                    (*dt_fixup)(void);
        long long               (*pv_fixup)(void);
        void                    (*reserve)(void);/* reserve mem blocks  */
        void                    (*map_io)(void);/* IO mapping function  */
        void                    (*init_early)(void);
        void                    (*init_irq)(void);
        void                    (*init_time)(void);
        void                    (*init_machine)(void);
        void                    (*init_late)(void);
#ifdef CONFIG_MULTI_IRQ_HANDLER
        void                    (*handle_irq)(struct pt_regs *);
#endif
        void                    (*restart)(enum reboot_mode, const char *);
};

分析三:IRQ_BITMAP_BITS

//kernel/irq/internals.h
#ifdef CONFIG_SPARSE_IRQ
#define IRQ_BITMAP_BITS (NR_IRQS + 8196)
#else
#define IRQ_BITMAP_BITS NR_IRQS
#endif


//include/linux/types.h
#define DECLARE_BITMAP(name,bits) \
        unsigned long name[BITS_TO_LONGS(bits)]

//arch/arm/include/asm/bitops.h
#define set_bit(nr,p)                   ATOMIC_BITOP(set_bit,nr,p)    //_set_bit
#define clear_bit(nr,p)                 ATOMIC_BITOP(clear_bit,nr,p)
#define change_bit(nr,p)                ATOMIC_BITOP(change_bit,nr,p)
#define test_and_set_bit(nr,p)          ATOMIC_BITOP(test_and_set_bit,nr,p)
#define test_and_clear_bit(nr,p)        ATOMIC_BITOP(test_and_clear_bit,nr,p)
#define test_and_change_bit(nr,p)       ATOMIC_BITOP(test_and_change_bit,nr,p)


/*
 * __builtin_constant_p 是编译器gcc内置函数,用于判断一个值是否为编译时常量,
 * 如果是常数,函数返回1 ,否则返回0。此内置函数的典型用法是在宏中用于手动编译时优化
 */
#ifndef CONFIG_SMP  //此宏在.config中未定义
/*
 * The __* form of bitops are non-atomic and may be reordered.
 */
#define ATOMIC_BITOP(name,nr,p)                 \
        (__builtin_constant_p(nr) ? ____atomic_##name(nr, p) : _##name(nr,p))  
#else
#define ATOMIC_BITOP(name,nr,p)         _##name(nr,p)
#endif


//set_bit函数实现分析
#define set_bit(nr,p)                   ATOMIC_BITOP(set_bit,nr,p)    //_set_bit


//arch/arm/lib/setbit.S
/*
 *  linux/arch/arm/lib/setbit.S
 *
 *  Copyright (C) 1995-1996 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/linkage.h>
#include <asm/assembler.h>
#include "bitops.h"
                .text

bitop   _set_bit, orr 


//arch/arm/lib/bitops.h
        .macro  bitop, name, instr
ENTRY(  \name           )
UNWIND( .fnstart        )
        ands    ip, r1, #3
        strneb  r1, [ip]                @ assert word-aligned
        mov     r2, #1
        and     r3, r0, #31             @ Get bit offset
        mov     r0, r0, lsr #5
        add     r1, r1, r0, lsl #2      @ Get word offset
#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
        .arch_extension mp
        ALT_SMP(W(pldw) [r1])
        ALT_UP(W(nop))
#endif
        mov     r3, r2, lsl r3
1:      ldrex   r2, [r1]
        \instr  r2, r2, r3
        strex   r0, r2, [r1]
        cmp     r0, #0
        bne     1b  
        bx      lr  
UNWIND( .fnend          )
ENDPROC(\name           )
        .endm

分析四  alloc_desc

//kernel/irq/irqdesc.c
static RADIX_TREE(irq_desc_tree, GFP_KERNEL);  //基数树

static void irq_insert_desc(unsigned int irq, struct irq_desc *desc)
{
        radix_tree_insert(&irq_desc_tree, irq, desc);
}

struct irq_desc *irq_to_desc(unsigned int irq)
{
        return radix_tree_lookup(&irq_desc_tree, irq);
}
EXPORT_SYMBOL(irq_to_desc);

static void delete_irq_desc(unsigned int irq)
{
        radix_tree_delete(&irq_desc_tree, irq);
}

static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
{
        struct irq_desc *desc;
        gfp_t gfp = GFP_KERNEL;

        desc = kzalloc_node(sizeof(*desc), gfp, node);
        if (!desc)
                return NULL;
        /* allocate based on nr_cpu_ids */
        desc->kstat_irqs = alloc_percpu(unsigned int);
        if (!desc->kstat_irqs)
                goto err_desc;

        if (alloc_masks(desc, gfp, node))
                goto err_kstat;

        raw_spin_lock_init(&desc->lock);
        lockdep_set_class(&desc->lock, &irq_desc_lock_class);

        desc_set_defaults(irq, desc, node, owner);

        return desc;

err_kstat:
        free_percpu(desc->kstat_irqs);
err_desc:
        kfree(desc);
        return NULL;
}


static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,struct module *owner)                
{
        int cpu;

        desc->irq_common_data.handler_data = NULL;
        desc->irq_common_data.msi_desc = NULL;

        desc->irq_data.common = &desc->irq_common_data;
        desc->irq_data.irq = irq;
        desc->irq_data.chip = &no_irq_chip;
        desc->irq_data.chip_data = NULL;
        irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS);
        irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
        desc->handle_irq = handle_bad_irq;
        desc->depth = 1;
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;
        desc->name = NULL;
        desc->owner = owner;
        for_each_possible_cpu(cpu)
                *per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
        desc_smp_init(desc, node);
}


//include/linux/irqdesc.h
/**
 * struct irq_desc - interrupt descriptor
 * @irq_common_data:    per irq and chip data passed down to chip functions
 * @kstat_irqs:         irq stats per cpu
 * @handle_irq:         highlevel irq-events handler
 * @preflow_handler:    handler called before the flow handler (currently used by sparc)
 * @action:             the irq action chain
 * @status:             status information
 * @core_internal_state__do_not_mess_with_it: core internal status information
 * @depth:              disable-depth, for nested irq_disable() calls
 * @wake_depth:         enable depth, for multiple irq_set_irq_wake() callers
 * @irq_count:          stats field to detect stalled irqs
 * @last_unhandled:     aging timer for unhandled count
 * @irqs_unhandled:     stats field for spurious unhandled interrupts
 * @threads_handled:    stats field for deferred spurious detection of threaded handlers
 * @threads_handled_last: comparator field for deferred spurious detection of theraded handlers
 * @lock:               locking for SMP
 * @affinity_hint:      hint to user space for preferred irq affinity
 * @affinity_notify:    context for notification of affinity changes
 * @pending_mask:       pending rebalanced interrupts
 * @threads_oneshot:    bitfield to handle shared oneshot threads
 * @threads_active:     number of irqaction threads currently running
 * @wait_for_threads:   wait queue for sync_irq to wait for threaded handlers
 * @nr_actions:         number of installed actions on this descriptor
 * @no_suspend_depth:   number of irqactions on a irq descriptor with
 *                      IRQF_NO_SUSPEND set
 * @force_resume_depth: number of irqactions on a irq descriptor with
 *                      IRQF_FORCE_RESUME set
 * @dir:                /proc/irq/ procfs entry
 * @name:               flow handler name for /proc/interrupts output
 */
struct irq_desc {
        struct irq_common_data  irq_common_data;
        struct irq_data         irq_data;
        unsigned int __percpu   *kstat_irqs;
        irq_flow_handler_t      handle_irq;
#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
        irq_preflow_handler_t   preflow_handler;
#endif
        struct irqaction        *action;        /* IRQ action list */
        unsigned int            status_use_accessors;
        unsigned int            core_internal_state__do_not_mess_with_it;
        unsigned int            depth;          /* nested irq disables */
        unsigned int            wake_depth;     /* nested wake enables */
        unsigned int            irq_count;      /* For detecting broken IRQs */
        unsigned long           last_unhandled; /* Aging timer for unhandled count */
        unsigned int            irqs_unhandled;
        atomic_t                threads_handled;
        int                     threads_handled_last;
        raw_spinlock_t          lock;
        struct cpumask          *percpu_enabled;
#ifdef CONFIG_SMP
        const struct cpumask    *affinity_hint;
        struct irq_affinity_notify *affinity_notify;
#ifdef CONFIG_GENERIC_PENDING_IRQ
        cpumask_var_t           pending_mask;
#endif
#endif
        unsigned long           threads_oneshot;
  atomic_t                threads_active;
        wait_queue_head_t       wait_for_threads;
#ifdef CONFIG_PM_SLEEP
        unsigned int            nr_actions;
        unsigned int            no_suspend_depth;
        unsigned int            cond_suspend_depth;
        unsigned int            force_resume_depth;
#endif
#ifdef CONFIG_PROC_FS
        struct proc_dir_entry   *dir;
#endif
        int                     parent_irq;
        struct module           *owner;
        const char              *name;
} ____cacheline_internodealigned_in_smp;



分析五

//drivers/irqchip/irqchip.c
/*
 * Copyright (C) 2012 Thomas Petazzoni
 *
 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 *
 * This file is licensed under the terms of the GNU General Public
 * License version 2.  This program is licensed "as is" without any
 * warranty of any kind, whether express or implied.
 */

#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/of_irq.h>
#include <linux/irqchip.h>

/*
 * This special of_device_id is the sentinel at the end of the
 * of_device_id[] array of all irqchips. It is automatically placed at
 * the end of the array by the linker, thanks to being part of a
 * special section.
 */
static const struct of_device_id
irqchip_of_match_end __used __section(__irqchip_of_table_end);

//__irqchip_of_table定义在链接脚本arch/arm/kernel/vmlinux.lds
extern struct of_device_id __irqchip_of_table[];

void __init irqchip_init(void)
{
        of_irq_init(__irqchip_of_table);  //分析六
        acpi_probe_device_table(irqchip);
}


/*
 *__irqchip_of_table实际上是一个struct of_device_id结构体的数组,
 *__irqchip_of_table数组里的每一个元素使用IRQCHIP_DECLARE宏定义而来,
 *数组的每个元素都被放在了__irqchip_of_table段中
 */
 
/*
 * include/linux/irqchip.h
 * @name: name that must be unique accross all IRQCHIP_DECLARE of the
 * same file.
 * @compstr: compatible string of the irqchip driver
 * @fn: initialization function
 */
#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)


//include/linux/of.h
#ifdef CONFIG_OF
#define _OF_DECLARE(table, name, compat, fn, fn_type)                   \
        static const struct of_device_id __of_table_##name              \
                __used __section(__##table##_of_table)                  \
                 = { .compatible = compat,                              \
                     .data = (fn == (fn_type)NULL) ? fn : fn  }
#else
#define _OF_DECLARE(table, name, compat, fn, fn_type)                   \
        static const struct of_device_id __of_table_##name              \
                __attribute__((unused))                                 \
                 = { .compatible = compat,                              \
                     .data = (fn == (fn_type)NULL) ? fn : fn }
#endif

typedef int (*of_init_fn_2)(struct device_node *, struct device_node *);
typedef void (*of_init_fn_1)(struct device_node *);

#define OF_DECLARE_1(table, name, compat, fn) \
                _OF_DECLARE(table, name, compat, fn, of_init_fn_1)
#define OF_DECLARE_2(table, name, compat, fn) \
                _OF_DECLARE(table, name, compat, fn, of_init_fn_2)


分析六 of_irq_init

//drivers/of/irq.c
struct of_intc_desc {
        struct list_head        list;
        struct device_node      *dev;
        struct device_node      *interrupt_parent;
};

/**
 * of_irq_init - Scan and init matching interrupt controllers in DT
 * @matches: 0 terminated array of nodes to match and init function to call
 *
 * This function scans the device tree for matching interrupt controller nodes,
 * and calls their initialization functions in order with parents first.
 */
void __init of_irq_init(const struct of_device_id *matches)
{
        struct device_node *np, *parent = NULL;
        struct of_intc_desc *desc, *temp_desc;
        struct list_head intc_desc_list, intc_parent_list;

        INIT_LIST_HEAD(&intc_desc_list);
        INIT_LIST_HEAD(&intc_parent_list);
        for_each_matching_node(np, matches) {
                if (!of_find_property(np, "interrupt-controller", NULL) ||
                                !of_device_is_available(np))
                        continue;
                /*
                 * Here, we allocate and populate an of_intc_desc with the node
                 * pointer, interrupt-parent device_node etc.
                 */
                desc = kzalloc(sizeof(*desc), GFP_KERNEL);
                if (WARN_ON(!desc)) {
                        of_node_put(np);
                        goto err;
                }

                desc->dev = of_node_get(np);
                desc->interrupt_parent = of_irq_find_parent(np);
                if (desc->interrupt_parent == np)
                        desc->interrupt_parent = NULL;
                list_add_tail(&desc->list, &intc_desc_list);
        }

 /*
         * The root irq controller is the one without an interrupt-parent.
         * That one goes first, followed by the controllers that reference it,
         * followed by the ones that reference the 2nd level controllers, etc.
         */
        while (!list_empty(&intc_desc_list)) {
                /*
                 * Process all controllers with the current 'parent'.
                 * First pass will be looking for NULL as the parent.
                 * The assumption is that NULL parent means a root controller.
                 */
                list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
                        const struct of_device_id *match;
                        int ret;
                        of_irq_init_cb_t irq_init_cb;

                        if (desc->interrupt_parent != parent)
                                continue;

                        list_del(&desc->list);
                        match = of_match_node(matches, desc->dev);
                        if (WARN(!match->data,
                            "of_irq_init: no init function for %s\n",
                            match->compatible)) {
                                kfree(desc);
                                continue;
                        }

                        pr_debug("of_irq_init: init %s @ %p, parent %p\n",
                                 match->compatible,
                                 desc->dev, desc->interrupt_parent);
                        irq_init_cb = (of_irq_init_cb_t)match->data;
                        /*
                         *执行IRQCHIP_DECLARE宏定义全局变量里的函数,
                         *此函数就是驱动代码了,这部分驱动代对arm一般
                         *gic驱动或者vic(pl192)的驱动。
                         */
                        ret = irq_init_cb(desc->dev, desc->interrupt_parent); 
                        if (ret) {
                                kfree(desc);
                                continue;
                        }

                        /*
                         * This one is now set up; add it to the parent list so
                         * its children can get processed in a subsequent pass.
                         */
                        list_add_tail(&desc->list, &intc_parent_list);
                }

                /* Get the next pending parent that might have children */
                desc = list_first_entry_or_null(&intc_parent_list,
                                                typeof(*desc), list);
                if (!desc) {
                        pr_err("of_irq_init: children remain, but no parents\n");
                        break;
                }
                list_del(&desc->list);
                parent = desc->dev;
                kfree(desc);
        }

        list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
                list_del(&desc->list);
                kfree(desc);
        }
err:
        list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
                list_del(&desc->list);
                of_node_put(desc->dev);
                kfree(desc);
        }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1章 操作系统概述 1 1.1 认识操作系统 1 1.1.1 从使用者角度 1 1.1.2 从程序开发者角度 2 1.1.3 从操作系统在整个计算机系统中所处位置 2 1.1.4 从操作系统设计者的角度 3 1.2 操作系统的发展 4 1.2.1 操作系统的演变 4 1.2.2 硬件的发展轨迹 5 1.2.3 软件的轨迹 6 1.2.4 单内核与微内核操作系统 7 1.3 开放源代码的Unix/Linux操作系统 8 1.3.1 Unix的诞生和发展 8 1.3.2 Linux的诞生 9 1.3.3 操作系统标准POSIX 9 1.3.4 GNU和Linux 9 1.3.5 Linux的开发模式 10 1.4 Linux内核 10 1.4.1 Linux内核的位置 10 1.4.2 Linux内核的作用 11 1.4.3 Linux内核子系统 11 1.5 Linux内核源代码 13 1.5.1 多版本的内核源代码 13 1.5.2 Linux内核源代码的结构 13 1.5.3 Linux内核源代码分析工具 14 习题1 15 第2章 内存寻址 17 2.1 内存寻址简介 17 2.1.1 Intel x86 CPU寻址方式的演变 18 2.1.2 IA32寄存器简介 19 2.1.3 物理地址、虚拟地址及线性地址 21 2.2 分段机制 22 2.2.1 地址转换及保护 24 2.2.2 Linux中的段 24 2.3 分页机制 25 2.3.1 页与页表 25 2.3.2 线性地址到物理地址的转换 28 2.3.3 分页示例 28 2.3.4 页面高速缓存(cache) 29 2.3.5 Linux中的分页机制 30 2.4 Linux中的汇编语言 31 2.4.1 AT&T与Intel汇编语言的比较 31 2.4.2 AT&T汇编语言的相关知识 32 2.5 Linux系统地址映射示例 33 习题2 35 第3章 进程 37 3.1 进程介绍 37 3.1.1 程序和进程 37 3.1.2 进程的层次结构 38 3.1.3 进程状态 39 3.1.4 进程实例 40 3.2 进程控制块 41 3.2.1 进程状态 42 3.2.2 进程标识符 43 3.2.3 进程之间的亲属关系 43 3.2.4 进程控制块的存放 44 3.3 进程的组织方式 45 3.3.1 进程链表 45 3.3.2 散列表 46 3.3.3 可运行队列 47 3.3.4 等待队列 47 3.4 进程调度 48 3.4.1 基本原理 48 3.4.2 时间片 50 3.4.3 Linux进程调度时机 50 3.4.4 进程调度的依据 51 3.4.5 调度函数schedule()的实现 52 3.5 进程的创建 54 3.5.1 创建进程 55 3.5.2 线程及其创建 56 3.6 与进程相关的系统调用及其应用 58 3.6.1 fork系统调用 58 3.6.2 exec系统调用 59 3.6.3 wait系统调用 60 3.6.4 exit系统调用 62 3.6.5 进程的一生 63 3.7 与调度相关的系统调用及应用 63 习题3 65 第4章 内存管理 67 4.1 Linux的内存管理概述 67 4.1.1 虚拟内存、内核空间和用户空间 67 4.1.2 虚拟内存实现机制间的关系 69 4.2 进程用户空间的管理 70 4.2.1 进程用户空间的描述 71 4.2.2 进程用户空间的创建 74 4.2.3 虚存映射 76 4.2.4 进程的虚存区示例 76 4.2.5 与用户空间相关的系统调用 78 4.3 请页机制 79 4.3.1 缺页异常处理程序 79 4.3.2 请求调页 81 4.3.3 写时复制 83 4.4 物理内存的分配与回收 83 4.4.1 伙伴算法 85 4.4.2 物理页面的分配 86 4.4.3 物理页面的回收 88 4.4.4 slab分配模式 89 4.4.5 内核空间非连续内存区的分配 93 4.5 交换机制 95 4.5.1 交换的基本原理 95 4.5.2 页面交换守护进程kswapd 99 4.6 内存管理实例 99 4.6.1 相关背景知识 100 4.6.2 代码体系结构介绍 100 4.6.3 实现步骤 103 4.6.4 程序代码 103 习题4 108 第5章 中断和异常 110 5.1 中断的基本知识 110 5.1.1 中断向量 110 5.1.2 外设可屏蔽中断 111 5.1.3 异常及非屏蔽中断 112 5.1.4 中断描述符表 112 5.1.5 相关汇编指令 113 5.2 中断描述符表的初始化 114 5.2.1 IDT表项的设置 114 5.2.2 对陷阱门和系统门的初始化 115 5.2.3 中断门的设置 116 5.3 中断处理 116 5.3.1 中断和异常的硬件处理 116 5.3.2 中断请求队列的建立 117 5.3.3 中断处理程序的执行 119 5.3.4 从中断返回 121 5.4 中断的下半部处理机制 121 5.4.1 为什么把中断分为两部分来处理 122 5.4.2 小任务机制 122 5.4.3 下半部 124 5.4.4 任务队列 125 5.5 中断应用——时钟中断 125 5.5.1 时钟 125 5.5.2 时钟运作机制 126 5.5.3 Linux的时间系统 127 5.5.4 时钟中断处理程序 128 5.5.5 时钟中断的下半部处理 129 5.5.6 定时器及其应用 129 习题5 132 第6章 系统调用 133 6.1 系统调用与应用编程接口、系统命令、内核函数的关系 133 6.1.1 系统调用与API 133 6.1.2 系统调用与系统命令 134 6.1.3 系统调用与内核函数 134 6.2 系统调用处理程序及服务例程 135 6.2.1 初始化系统调用 136 6.2.2 system_call()函数 136 6.2.3 参数传递 137 6.2.4 跟踪系统调用的执行 139 6.3 封装例程 140 6.4 添加新系统调用 141 6.5 实例——利用系统调用实现一个调用日志收集系统 143 6.5.1 代码体系结构 143 6.5.2 把代码集成到内核中 146 6.5.3 实现步骤 148 习题6 148 第7章 内核中的同步 149 7.1 临界区和竞争状态 149 7.1.1 临界区举例 149 7.1.2 共享队列和加锁 150 7.1.3 确定保护对象 151 7.1.4 死锁 152 7.1.5 并发执行的原因 153 7.2 内核同步方法 153 7.2.1 原子操作 153 7.2.2 自旋锁 155 7.2.3 信号量 156 7.3 并发控制实例 157 7.3.1 内核任务及其并发关系 158 7.3.2 实现机制 158 7.3.3 关键代码解释 162 7.3.4 实现步骤 163 习题7 164 第8章 文件系统 165 8.1 Linux文件系统基础 165 8.1.1 Linux文件结构 165 8.1.2 Linux文件系统 166 8.1.3 文件类型 167 8.1.4 文件访问权限 168 8.2 虚拟文件系统 168 8.2.1 虚拟文件系统的引入 168 8.2.2 VFS中的数据结构 170 8.2.3 VFS超级块数据结构 171 8.2.4 VFS的索引节点 173 8.2.5 目录项对象 174 8.2.6 与进程相关的文件结构 176 8.2.7 主要的数据结构之间的关系 179 8.3 文件系统的注册、安装与卸载 180 8.3.1 文件系统的注册和注销 180 8.3.2 文件系统的安装 181 8.3.3 文件系统的卸载 183 8.4 页缓冲区 183 8.4.1 address_space对象 183 8.4.2 address_space对象的操作函数表 184 8.5 文件的打开与读写 185 8.5.1 打开文件 185 8.5.2 读写文件 187 8.6 编写一个文件系统 189 8.6.1 Linux文件系统的实现要素 189 8.6.2 什么是romfs文件系统 191 8.6.3 romfs文件系统的布局与文件结构 191 8.6.4 具体实现的对象 192 习题8 195 第9章 设备驱动 196 9.1 概述 196 9.2 设备驱动程序基础 198 9.2.1 I/O端口 199 9.2.2 设备文件 200 9.2.3 中断处理 201 9.2.4 设备驱动程序框架 203 9.3 字符设备驱动程序 204 9.3.1 字符设备驱动程序的注册 204 9.3.2 简单的字符设备驱动程序示例 205 9.4 块设备驱动程序 208 9.4.1 块设备驱动程序的注册 209 9.4.2 块设备请求 212 习题9 215 附录A 内核中的链表 216 A.1 链表数据结构简介 216 A.2 内核链表数据结构的定义及初始化 217 A.3 操作链表的接口 218 A.4 遍历链表 219 附录B 内核模块 221 B.1 什么是模块 221 B.2 编写一个简单的模块 221 B.3 模块编程的基础知识 222 B.4 模块的编译 224 B.5 模块实用程序modutils 226 附录C Linux内核编译 228 C.1 内核简介 228 C.2 为什么重新编译内核 228 C.3 内核编译模式 229 C.4 新版本内核的获取和更新 229 C.5 内核编译 230 C.6 修改并重启管理器 232 附录D Linux编程基础(C语言环境) 233 D.1 Linux编程常识 233 D.1.1 相关标准(ANSI C、POSIX、SVID、XPG) 233 D.1.2 函数库和系统调用 234 D.1.3 在线文档(man、info、HOWTO) 235 D.1.4 C语言编程风格 237 D.2 Linux上的C/C++编译器和调试器 238 D.2.1 运行gcc/egcs 238 D.2.2 gcc/egcs的主要选项 240 D.2.3 gdb简介 240 D.2.4 gdb的常用命令 241 D.2.5 gdb使用示例 242 D.3 GNU make和makefile 243 D.3.1 GNU make 243 D.3.2 makefile的基本结构 243 D.3.3 makefile的变量 244 D.3.4 GNU make的主要预定义变量 245 D.3.5 GNU make的隐含规则 245 D.3.6 运行make 246

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值