tag:blogger.com,1999:blog-303145962024-03-07T11:03:15.260-08:00adam's homeliyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.comBlogger93125tag:blogger.com,1999:blog-30314596.post-71063609946038843252009-06-24T01:45:00.000-07:002009-06-24T02:50:12.714-07:000624<pre><code><br />1. GDB:<br /><br />"display" in three flavors:<br /><br />display expr<br /> Add the expression expr to the list of expressions to display each time your program stops. See section Expressions.<br /><br /> display does not repeat if you press RET again after using it.<br /><br />display/fmt expr<br /> For fmt specifying only a display format and not a size or count, add the expression expr to the auto-display list but arrange to display it each time in the specified format fmt. See section Output Formats.<br /><br />display/fmt addr<br /> For fmt `i' or `s', or including a unit-size or a number of units, add the expression addr as a memory address to be examined each time your program stops. Examining means in effect doing `x/fmt addr'. See section Examining Memory. <br /><br /><br />Example for the 3rd usage: <br /> display/1xh 0xffc00fc0<br /><br />This is useful to examine a 16-bit register<br /><br />2. /proc/devices: show the major number<br /><br />root:/> cat /proc/devices <br />Character devices:<br /> 1 mem<br /> 5 /dev/tty<br /> 5 /dev/console<br /> 5 /dev/ptmx<br /> 10 misc<br /> 13 input<br />128 ptm<br />136 pts<br />150 rtpipe<br />204 ttyBF<br />254 rtc<br /><br />Block devices:<br /> 1 ramdisk<br />259 blkext<br /> 31 mtdblock<br /><br />3. About Trace Buffer<br /><br />Blackfin records every program sequence change in trace buffer, if trace buffer is enabled. There is a 16-entry TBUF register table.<br /><br />- A bit (TBUGOVF) in the TB control register can enable exception when the TBUF overflows (>16 entry). In the exception handler, TBUF can be read into memory, so that we can record more than 16 traces.<br />- The trace buffer can be configured to omit the recording of changes in program flow that match either the last entry or one of the last two entries.<br />- If TBUFOVF = 1, then the Trace Unit does not record discontinuities in the exception, NMI, and reset routines, because TB itself triggers exception.<br />- Setting TBUFOVF have impact on performance - every 16 sequence change would trigger an exception.<br /><br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-19811464338499719722009-04-15T02:12:00.000-07:002009-04-15T02:14:00.160-07:00bfin spi device<pre><code><br />从小就有种强烈的恐惧感。在空间中渺小无比,在时间中如流星一瞬而又无法重复。没有“我”的宇宙依然如故,而“我”却最终空无一物,无踪无影。这一切残酷,却又是无法回避的现实。<br /><br />想到这里,万物皆空,万念俱灰。<br /><br /><br />-------------------------------------------------------------------------------<br /><br />struct spi_device {<br /> struct device dev;<br /> struct spi_master *master;<br /> u32 max_speed_hz;<br /> u8 chip_select;<br /> u8 mode;<br />#define SPI_CPHA 0x01 /* clock phase */<br />#define SPI_CPOL 0x02 /* clock polarity */<br />#define SPI_MODE_0 (0|0) /* (original MicroWire) */<br />#define SPI_MODE_1 (0|SPI_CPHA)<br />#define SPI_MODE_2 (SPI_CPOL|0)<br />#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)<br />#define SPI_CS_HIGH 0x04 /* chipselect active high? */<br />#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */<br />#define SPI_3WIRE 0x10 /* SI/SO signals shared */<br />#define SPI_LOOP 0x20 /* loopback mode */<br /> u8 bits_per_word;<br /> int irq;<br /> void *controller_state;<br /> void *controller_data;<br /> const char *modalias;<br />};<br /><br />-------------------------------------------------------------------------------<br />struct bfin5xx_spi_chip {<br /> u16 ctl_reg;<br /> u8 enable_dma;<br /> u8 bits_per_word;<br /> u8 cs_change_per_word;<br /> u16 cs_chg_udelay; /* Some devices require 16-bit delays */<br /> u32 cs_gpio;<br /> /* Value to send if no TX value is supplied, usually 0x0 or 0xFFFF */<br /> u16 idle_tx_val;<br />};<br /><br /><br />#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)<br />static struct bfin5xx_spi_chip enc28j60_spi_chip_info = {<br /> .enable_dma = 1,<br /> .bits_per_word = 8,<br /> .cs_gpio = GPIO_PF10,<br />};<br />#endif<br /><br /><br /><br />------------------------------------------------------------------------------<br /><br />/*<br /> * These structures are used in two places. Their primary role is to<br /> * be stored in tables of board-specific device descriptors, which are<br /> * declared early in board initialization and then used (much later) to<br /> * populate a controller's device tree after the that controller's driver<br /> * initializes. A secondary (and atypical) role is as a parameter to<br /> * spi_new_device() call, which happens after those controller drivers<br /> * are active in some dynamic board configuration models.<br /> */<br />struct spi_board_info {<br /> /* the device name and module name are coupled, like platform_bus;<br /> * "modalias" is normally the driver name.<br /> *<br /> * platform_data goes to spi_device.dev.platform_data,<br /> * controller_data goes to spi_device.controller_data,<br /> * irq is copied too<br /> */<br /> char modalias[32];<br /> const void *platform_data;<br /> void *controller_data;<br /> int irq;<br /><br /> /* slower signaling on noisy or low voltage boards */<br /> u32 max_speed_hz;<br /><br /><br /> /* bus_num is board specific and matches the bus_num of some<br /> * spi_master that will probably be registered later.<br /> *<br /> * chip_select reflects how this chip is wired to that master;<br /> * it's less than num_chipselect.<br /> */<br /> u16 bus_num;<br /> u16 chip_select;<br /><br /> /* mode becomes spi_device.mode, and is essential for chips<br /> * where the default of SPI_CS_HIGH = 0 is wrong.<br /> */<br /> u8 mode;<br /><br /> /* ... may need additional spi_device chip config data here.<br /> * avoid stuff protocol drivers can set; but include stuff<br /> * needed to behave without being bound to a driver:<br /> * - quirks like clock rate mattering when not selected<br /> */<br />};<br /><br />static struct spi_board_info bfin_spi_board_info[] __initdata = {<br /><br />[snip]<br /><br />#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)<br /> {<br /> .modalias = "enc28j60",<br /> .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */<br /> .irq = IRQ_PF6,<br /> .bus_num = 0,<br /> .chip_select = 0, /* GPIO controlled SSEL */<br /> .controller_data = &enc28j60_spi_chip_info,<br /> .mode = SPI_MODE_0,<br /> },<br />#endif<br /><br />[snip]<br /><br />}<br /><br />static int __init stamp_init(void)<br />{<br /> printk(KERN_INFO "%s(): registering device resources\n", __func__);<br /> i2c_register_board_info(0, bfin_i2c_board_info,<br /> ARRAY_SIZE(bfin_i2c_board_info));<br /> bfin_plat_nand_init();<br /> platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));<br /> spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));<br /><br />[snip]<br />}<br /><br />later in:<br />int spi_register_master(struct spi_master *master) --><br /> static void scan_boardinfo(struct spi_master *master) --><br /> struct spi_device *spi_new_device(struct spi_master *master, struct spi_board_info *chip)<br /><br />in spi_new_device(), spi_board_info will be copied to struct spi_device.<br /><br />spi_board_info.controller_data (i.e enc28j60_spi_chip_info) will be copied to spi_device.controller_data.<br /><br />In bfin_spi_setup() --> spi_set_ctldata(spi, chip); // this will set spi_device.controller_state.<br /><br />--------------------------------------------------------------------------<br /><br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-76954985186341484062009-03-17T02:51:00.000-07:002009-03-17T03:14:23.329-07:000317 log<pre><code><br />How do I remove a file whose name begins with a "-" ?<br /><br />rm ./-filename<br /><br />or<br /><br />rm -- -filename<br /><br />http://www.faqs.org/faqs/unix-faq/faq/part2/section-1.html<br /><br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-30494806419855524982009-03-11T21:29:00.002-07:002009-03-11T21:30:20.174-07:00bfin generic irq handling<pre><code><br />Docs:<br />================<br />linux/Document/Docbook/genericirq/ (make htmldoc)<br /><br />LWN: A new generic IRQ layer - http://lwn.net/Articles/184750/<br /><br />Summery:<br />================<br /><br />"struct irq_desc" represents an IRQ. "struct irq_chip" - chip level handling.<br />Arch code need to define its "irq_chip" structures. See bellow.<br /><br />All the chip level initialization is done in init_arch_irq(), it calls set_irq_handler(), set_irq_chip() to initialize each "irq desc" structures.<br />This setups the the generic irq framework.<br /><br />A driver need to call request_irq() to register an irq handler.<br /><br />When an irq happens, the arch code finally calls into irq_desc->handler(), (this handler is intialized in init_arch_irq()), then finally, a list of irq_action is walked through,<br />the driver's registered handler is finally called.<br /><br />irq chips:<br />======================<br />static struct irq_chip bfin_core_irqchip = {<br /> .name = "CORE",<br /> .ack = bfin_ack_noop,<br /> .mask = bfin_core_mask_irq,<br /> .unmask = bfin_core_unmask_irq,<br />};<br /><br />static struct irq_chip bfin_internal_irqchip = {<br /> .name = "INTN",<br /> .ack = bfin_ack_noop,<br /> .mask = bfin_internal_mask_irq,<br /> .unmask = bfin_internal_unmask_irq,<br /> .mask_ack = bfin_internal_mask_irq,<br /> .disable = bfin_internal_mask_irq,<br /> .enable = bfin_internal_unmask_irq,<br />#ifdef CONFIG_PM<br /> .set_wake = bfin_internal_set_wake,<br />#endif<br />};<br />static struct irq_chip bfin_generic_error_irqchip = {<br /> .name = "ERROR",<br /> .ack = bfin_ack_noop,<br /> .mask_ack = bfin_generic_error_mask_irq,<br /> .mask = bfin_generic_error_mask_irq,<br /> .unmask = bfin_generic_error_unmask_irq,<br />};<br /><br />static struct irq_chip bfin_gpio_irqchip = {<br /> .name = "GPIO",<br /> .ack = bfin_gpio_ack_irq,<br /> .mask = bfin_gpio_mask_irq,<br /> .mask_ack = bfin_gpio_mask_ack_irq,<br /> .unmask = bfin_gpio_unmask_irq,<br /> .disable = bfin_gpio_mask_irq,<br /> .enable = bfin_gpio_unmask_irq,<br /> .set_type = bfin_gpio_irq_type,<br /> .startup = bfin_gpio_irq_startup,<br /> .shutdown = bfin_gpio_irq_shutdown,<br />#ifdef CONFIG_PM<br /> .set_wake = bfin_gpio_set_wake,<br />#endif<br />};<br /><br />struct irq_desc:<br />====================<br />Each interrupt is described by an interrupt descriptor structure irq_desc<br /><br />/**<br /> * struct irq_desc - interrupt descriptor<br /> * @irq: interrupt number for this descriptor<br /> * @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()]<br /> * @chip: low level interrupt hardware access<br /> * @msi_desc: MSI descriptor<br /> * @handler_data: per-IRQ data for the irq_chip methods<br /> * @chip_data: platform-specific per-chip private data for the chip<br /> * methods, to allow shared chip implementations<br /> * @action: the irq action chain<br /> * @status: status information<br /> * @depth: disable-depth, for nested irq_disable() calls<br /> * @wake_depth: enable depth, for multiple set_irq_wake() callers<br /> * @irq_count: stats field to detect stalled irqs<br /> * @irqs_unhandled: stats field for spurious unhandled interrupts<br /> * @last_unhandled: aging timer for unhandled count<br /> * @lock: locking for SMP<br /> * @affinity: IRQ affinity on SMP<br /> * @cpu: cpu index useful for balancing<br /> * @pending_mask: pending rebalanced interrupts<br /> * @dir: /proc/irq/ procfs entry<br /> * @name: flow handler name for /proc/interrupts output<br /> */<br />struct irq_desc {<br /> unsigned int irq;<br /> irq_flow_handler_t handle_irq;<br /> struct irq_chip *chip;<br /> struct msi_desc *msi_desc;<br /> void *handler_data;<br /> void *chip_data;<br /> struct irqaction *action; /* IRQ action list */<br /> unsigned int status; /* IRQ status */<br /><br /> unsigned int depth; /* nested irq disables */<br /> unsigned int wake_depth; /* nested wake enables */<br /> unsigned int irq_count; /* For detecting broken IRQs */<br /> unsigned int irqs_unhandled;<br /> unsigned long last_unhandled; /* Aging timer for unhandled count */<br /> spinlock_t lock;<br />#ifdef CONFIG_SMP<br /> cpumask_t affinity;<br /> unsigned int cpu;<br />#endif<br />#ifdef CONFIG_GENERIC_PENDING_IRQ<br /> cpumask_t pending_mask;<br />#endif<br />#ifdef CONFIG_PROC_FS<br /> struct proc_dir_entry *dir;<br />#endif<br /> const char *name;<br />} ____cacheline_internodealigned_in_smp;<br /><br /><br />struct irq_chip:<br />===================================================<br />/**<br /> * struct irq_chip - hardware interrupt chip descriptor<br /> *<br /> * @name: name for /proc/interrupts<br /> * @startup: start up the interrupt (defaults to ->enable if NULL)<br /> * @shutdown: shut down the interrupt (defaults to ->disable if NULL)<br /> * @enable: enable the interrupt (defaults to chip->unmask if NULL)<br /> * @disable: disable the interrupt (defaults to chip->mask if NULL)<br /> * @ack: start of a new interrupt<br /> * @mask: mask an interrupt source<br /> * @mask_ack: ack and mask an interrupt source<br /> * @unmask: unmask an interrupt source<br /> * @eoi: end of interrupt - chip level<br /> * @end: end of interrupt - flow level<br /> * @set_affinity: set the CPU affinity on SMP machines<br /> * @retrigger: resend an IRQ to the CPU<br /> * @set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ<br /> * @set_wake: enable/disable power-management wake-on of an IRQ<br /> *<br /> * @release: release function solely used by UML<br /> * @typename: obsoleted by name, kept as migration helper<br /> */<br />struct irq_chip {<br /> const char *name;<br /> unsigned int (*startup)(unsigned int irq);<br /> void (*shutdown)(unsigned int irq);<br /> void (*enable)(unsigned int irq);<br /> void (*disable)(unsigned int irq);<br /><br /> void (*ack)(unsigned int irq);irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)<br />{<br /> irqreturn_t ret, retval = IRQ_NONE;<br /> unsigned int status = 0;<br /><br /> if (!(action->flags & IRQF_DISABLED))<br /> local_irq_enable_in_hardirq();<br /><br /> do {<br /> ret = action->handler(irq, action->dev_id);<br /> if (ret == IRQ_HANDLED)<br /> status |= action->flags;<br /> retval |= ret;<br /> action = action->next;<br /> } while (action);<br /><br /> if (status & IRQF_SAMPLE_RANDOM)<br /> add_interrupt_randomness(irq);<br /> local_irq_disable();<br /><br /> return retval;<br />}<br /> void (*mask)(unsigned int irq);<br /> void (*mask_ack)(unsigned int irq);<br /> void (*unmask)(unsigned int irq);<br /> void (*eoi)(unsigned int irq);<br /><br /> void (*end)(unsigned int irq);<br /> void (*set_affinity)(unsigned int irq, cpumask_t dest);<br /> int (*retrigger)(unsigned int irq);<br /> int (*set_type)(unsigned int irq, unsigned int flow_type);<br /> int (*set_wake)(unsigned int irq, unsigned int on);<br /><br /> /* Currently used only by UML, might disappear one day.*/<br />#ifdef CONFIG_IRQ_RELEASE_METHOD<br /> void (*release)(unsigned int irq, void *dev_id);<br />#endif<br /> /*<br /> * For compatibility, ->typename is copied into ->name.<br /> * Will disappear.<br /> */<br /> const char *typename;<br />};<br /><br /><br />irq flow<br />=======================================<br />Low level arch code will finally calls <br />"irq_desc[irq]-> handler()"<br /><br />asm_do_IRQ() --><br /> generic_handle_irq() --><br /> desc->handle_irq() --> (Or __do_IRQ() if desc->handle_irq == NULL)<br /> (In init_arch_irq() desc->handle_irq() is assigned to default handlers: handle_simple_irq(), handle_level_irq(), etc.)<br /> --> handle_IRQ_event() (handle the irqaction chains).<br /><br /><br />static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)<br />{<br />#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ<br /> desc->handle_irq(irq, desc);<br />#else<br /> if (likely(desc->handle_irq))<br /> desc->handle_irq(irq, desc);<br /> else<br /> __do_IRQ(irq);<br />#endif<br />}<br /><br /><br />Register an IRQ:<br />=======================================================================<br />request_irq() --><br /> __setup_irq() --><br /> __irq_set_trigger() --><br /> chip->set_type(irq, flags & IRQF_TRIGGER_MASK) --><br /> bfin_gpio_irq_type() [mach-common/ints-priority.c]<br /><br />static int<br />__setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)<br />{<br /> struct irqaction *old, **p;<br /> const char *old_name = NULL;<br /> unsigned long flags;<br /> int shared = 0;<br /> int ret;<br /><br /> if (!desc)<br /> return -EINVAL;<br /><br /> if (desc->chip == &no_irq_chip)<br /> return -ENOSYS;<br /> /*<br /> * Some drivers like serial.c use request_irq() heavily,<br /> * so we have to be careful not to interfere with a<br /> * running system.<br /> */<br /> if (new->flags & IRQF_SAMPLE_RANDOM) {<br /> /*<br /> * This function might sleep, we want to call it first,<br /> * outside of the atomic block.<br /> * Yes, this might clear the entropy pool if the wrong<br /> * driver is attempted to be loaded, without actually<br /> * installing a new handler, but is this really a problem,<br /> * only the sysadmin is able to do this.<br /> */<br /> rand_initialize_irq(irq);<br /> }<br /><br /> /*<br /> * The following block of code has to be executed atomically<br /> */<br /> spin_lock_irqsave(&desc->lock, flags);<br /> p = &desc->action;<br /> old = *p;<br /> if (old) {<br /> /*<br /> * Can't share interrupts unless both agree to and are<br /> * the same type (level, edge, polarity). So both flag<br /> * fields must have IRQF_SHARED set and the bits which<br /> * set the trigger type must match.<br /> */<br /> if (!((old->flags & new->flags) & IRQF_SHARED) ||<br /> ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {<br /> old_name = old->name;<br /> goto mismatch;<br /> }<br /><br />#if defined(CONFIG_IRQ_PER_CPU)<br /> /* All handlers must agree on per-cpuness */<br /> if ((old->flags & IRQF_PERCPU) !=<br /> (new->flags & IRQF_PERCPU))<br /> goto mismatch;<br />#endif<br /><br /> /* add new interrupt at end of irq queue */<br /> do {<br /> p = &old->next;<br /> old = *p;<br /> } while (old);<br /> shared = 1;<br /> }<br /><br /> if (!shared) {<br /> irq_chip_set_defaults(desc->chip);<br /><br /> /* Setup the type (level, edge polarity) if configured: */<br /> if (new->flags & IRQF_TRIGGER_MASK) {<br /> ret = __irq_set_trigger(desc, irq, new->flags);<br /><br /> if (ret) {<br /> spin_unlock_irqrestore(&desc->lock, flags);<br /> return ret;<br /> }<br /> } else<br /> compat_irq_chip_set_default_handler(desc);<br />#if defined(CONFIG_IRQ_PER_CPU)<br /> if (new->flags & IRQF_PERCPU)<br /> desc->status |= IRQ_PER_CPU;<br />#endif<br /><br /> desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |<br /> IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);<br /><br /> if (!(desc->status & IRQ_NOAUTOEN)) {<br /> desc->depth = 0;<br /> desc->status &= ~IRQ_DISABLED;<br /> desc->chip->startup(irq);<br /> } else<br /> /* Undo nested disables: */<br /> desc->depth = 1;<br /><br /> /* Exclude IRQ from balancing if requested */<br /> if (new->flags & IRQF_NOBALANCING)<br /> desc->status |= IRQ_NO_BALANCING;<br /><br /> /* Set default affinity mask once everything is setup */<br /> do_irq_select_affinity(irq, desc);<br /><br /> } else if ((new->flags & IRQF_TRIGGER_MASK)<br /> && (new->flags & IRQF_TRIGGER_MASK)<br /> != (desc->status & IRQ_TYPE_SENSE_MASK)) {<br /> /* hope the handler works with the actual trigger mode... */<br /> pr_warning("IRQ %d uses trigger mode %d; requested %d\n",<br /> irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK),<br /> (int)(new->flags & IRQF_TRIGGER_MASK));<br /> }<br /><br /> *p = new;<br /><br /> /* Reset broken irq detection when installing new handler */<br /> desc->irq_count = 0;<br /> desc->irqs_unhandled = 0;<br /><br /> /*<br /> * Check whether we disabled the irq via the spurious handler<br /> * before. Reenable it and give it another chance.<br /> */<br /> if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {<br /> desc->status &= ~IRQ_SPURIOUS_DISABLED;<br /> __enable_irq(desc, irq);<br /> }<br /><br /> spin_unlock_irqrestore(&desc->lock, flags);<br /><br /> new->irq = irq;<br /> register_irq_proc(irq, desc);<br /> new->dir = NULL;<br /> register_handler_proc(irq, new);<br /><br /> return 0;<br /><br />mismatch:<br />#ifdef CONFIG_DEBUG_SHIRQ<br /> if (!(new->flags & IRQF_PROBE_SHARED)) {<br /> printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);<br /> if (old_name)<br /> printk(KERN_ERR "current handler: %s\n", old_name);<br /> dump_stack();<br /> }<br />#endif<br /> spin_unlock_irqrestore(&desc->lock, flags);<br /> return -EBUSY;<br />}<br /> <br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-20396467738424948772009-03-10T00:42:00.000-07:002009-03-10T02:00:08.231-07:00linker - relocation<pre><code><br />http://www.airs.com/blog/archives/category/programming/page/14/<br /><br />Basic Linker Data Types<br /><br />The linker operates on a small number of basic data types: symbols, relocations, and contents. These are defined in the input object files. Here is an overview of each of these.<br /><br />A symbol is basically a name and a value. Many symbols represent static objects in the original source code–that is, objects which exist in a single place for the duration of the program. For example, in an object file generated from C code, there will be a symbol for each function and for each global and static variable. The value of such a symbol is simply an offset into the contents. This type of symbol is known as a defined symbol. It’s important not to confuse the value of the symbol representing the variable my_global_var with the value of my_global_var itself. The value of the symbol is roughly the address of the variable: the value you would get from the expression &my_global_var in C.<br /><br />Symbols are also used to indicate a reference to a name defined in a different object file. Such a reference is known as an undefined symbol. There are other less commonly used types of symbols which I will describe later.<br /><br />During the linking process, the linker will assign an address to each defined symbol, and will resolve each undefined symbol by finding a defined symbol with the same name.<br /><br />A relocation is a computation to perform on the contents. Most relocations refer to a symbol and to an offset within the contents. Many relocations will also provide an additional operand, known as the addend. A simple, and commonly used, relocation is “set this location in the contents to the value of this symbol plus this addend.” The types of computations that relocations do are inherently dependent on the architecture of the processor for which the linker is generating code. For example, RISC processors which require two or more instructions to form a memory address will have separate relocations to be used with each of those instructions; for example, “set this location in the contents to the lower 16 bits of the value of this symbol.”<br /><br />During the linking process, the linker will perform all of the relocation computations as directed. A relocation in an object file may refer to an undefined symbol. If the linker is unable to resolve that symbol, it will normally issue an error (but not always: for some symbol types or some relocation types an error may not be appropriate).<br /><br />The contents are what memory should look like during the execution of the program. Contents have a size, an array of bytes, and a type. They contain the machine code generated by the compiler and assembler (known as text). They contain the values of initialized variables (data). They contain static unnamed data like string constants and switch tables (read-only data or rdata). They contain uninitialized variables, in which case the array of bytes is generally omitted and assumed to contain only zeroes (bss). The compiler and the assembler work hard to generate exactly the right contents, but the linker really doesn’t care about them except as raw data. The linker reads the contents from each file, concatenates them all together sorted by type, applies the relocations, and writes the result into the executable file.<br /><br />Basic Linker Operation<br /><br />At this point we already know enough to understand the basic steps used by every linker.<br /><br /> * Read the input object files. Determine the length and type of the contents. Read the symbols.<br /> * Build a symbol table containing all the symbols, linking undefined symbols to their definitions.<br /> * Decide where all the contents should go in the output executable file, which means deciding where they should go in memory when the program runs.<br /> * Read the contents data and the relocations. Apply the relocations to the contents. Write the result to the output file.<br /> * Optionally write out the complete symbol table with the final values of the symbols.<br /><br /><br />In the common case, code may be compiled in two different modes. By default, code is position dependent. Putting position dependent code into a shared library will cause the program linker to generate a lot of relocation information, and cause the dynamic linker to do a lot of processing at runtime. Code may also be compiled in position independent mode, typically with the -fpic option. Position independent code is slightly slower when it calls a non-static function or refers to a global or static variable. However, it requires much less relocation information, and thus the dynamic linker will start the program faster.<br /><br />Position independent code will call non-static functions via the Procedure Linkage Table or PLT. This PLT does not exist in .o files. In a .o file, use of the PLT is indicated by a special relocation. When the program linker processes such a relocation, it will create an entry in the PLT. It will adjust the instruction such that it becomes a PC-relative call to the PLT entry. PC-relative calls are inherently position independent and thus do not require a relocation entry themselves. The program linker will create a relocation for the PLT entry which tells the dynamic linker which symbol is associated with that entry. This process reduces the number of dynamic relocations in the shared library from one per function call to one per function called.<br /><br /><br />A detailed example can be found here:<br /><br />http://bottomupcs.sourceforge.net/csbu/x3867.htm<br /><br />Libraries<br />The Procedure Lookup Table<br /><br />Libraries may contain many functions, and a program may end up including many libraries to get its work done. A program may only use one or two functions from each library of the many available, and depending on the run-time path through the code may use some functions and not others.<br /><br />As we have seen, the process of dynamic linking is a fairly computationally intensive one, since it involves looking up and searching through many tables. Anything that can be done to reduce the overheads will increase performance.<br /><br />The Procedure Lookup Table (PLT) facilitates what is called lazy binding in programs. Binding is synonymous with the fix-up process described above for variables located in the GOT. When an entry has been "fixed-up" it is said to be "bound" to its real address.<br /><br />As we mentioned, sometimes a program will include a function from a library but never actually call that function, depending on user input. The process of binding this function is quite intensive, involving loading code, searching through tables and writing memory. To go through the process of binding a function that is not used is simply a waste of time.<br /><br />Lazy binding defers this expense until the actual function is called by using a PLT.<br /><br />Each library function has an entry in the PLT, which initially points to some special dummy code. When the program calls the function, it actually calls the PLT entry (in the same was as variables are referenced through the GOT).<br /><br />This dummy function will load a few parameters that need to be passed to the dynamic linker for it to resolve the function and then call into a special lookup function of the dynamic linker. The dynamic linker finds the real address of the function, and writes that location into the calling binary over the top of the dummy function call.<br /><br />Thus, the next time the function is called the address can be loaded without having to go back into the dynamic loader again. If a function is never called, then the PLT entry will never be modified but there will be no runtime overhead.<br />The PLT in action<br /><br />Things start to get a bit hairy here! If nothing else, you should begin to appreciate that there is a fair bit of work in resolving a dynamic symbol!<br /><br />Let us consider the simple "hello World" application. This will only make one library call to printf to output the string to the user.<br /><br />Example 9-8. Hello World PLT example<br /><br /> $ cat hello.c<br /> #include <stdio.h><br /> <br /> int main(void)<br /> 5 {<br /> printf("Hello, World!\n");<br /> return 0;<br /> }<br /> <br /> 10 $ gcc -o hello hello.c<br /> <br /> $ readelf --relocs ./hello<br /> <br /> Relocation section '.rela.dyn' at offset 0x3f0 contains 2 entries:<br /> 15 Offset Info Type Sym. Value Sym. Name + Addend<br /> 6000000000000ed8 000700000047 R_IA64_FPTR64LSB 0000000000000000 _Jv_RegisterClasses + 0<br /> 6000000000000ee0 000900000047 R_IA64_FPTR64LSB 0000000000000000 __gmon_start__ + 0<br /> <br /> Relocation section '.rela.IA_64.pltoff' at offset 0x420 contains 3 entries:<br /> 20 Offset Info Type Sym. Value Sym. Name + Addend<br /> 6000000000000f10 000200000081 R_IA64_IPLTLSB 0000000000000000 printf + 0<br /> 6000000000000f20 000800000081 R_IA64_IPLTLSB 0000000000000000 __libc_start_main + 0<br /> 6000000000000f30 000900000081 R_IA64_IPLTLSB 0000000000000000 __gmon_start__ + 0;<br /><br />We can see above that we have a R_IA64_IPLTLSB relocation for our printf symbol. This is saying "put the address of symbol printf into memory address 0x6000000000000f10". We have to start digging deeper to find the exact procedure that gets us the function.<br /><br />Below we have a look at the disassembly of the main() function of the program.<br /><br />Example 9-9. Hello world main()<br /><br /> 4000000000000790 <main>:<br /> 4000000000000790: 00 08 15 08 80 05 [MII] alloc r33=ar.pfs,5,4,0<br /> 4000000000000796: 20 02 30 00 42 60 mov r34=r12<br /> 400000000000079c: 04 08 00 84 mov r35=r1<br /> 5 40000000000007a0: 01 00 00 00 01 00 [MII] nop.m 0x0<br /> 40000000000007a6: 00 02 00 62 00 c0 mov r32=b0<br /> 40000000000007ac: 81 0c 00 90 addl r14=72,r1;;<br /> 40000000000007b0: 1c 20 01 1c 18 10 [MFB] ld8 r36=[r14]<br /> 40000000000007b6: 00 00 00 02 00 00 nop.f 0x0<br /> 10 40000000000007bc: 78 fd ff 58 br.call.sptk.many b0=4000000000000520 <_init+0xb0><br /> 40000000000007c0: 02 08 00 46 00 21 [MII] mov r1=r35<br /> 40000000000007c6: e0 00 00 00 42 00 mov r14=r0;;<br /> 40000000000007cc: 01 70 00 84 mov r8=r14<br /> 40000000000007d0: 00 00 00 00 01 00 [MII] nop.m 0x0<br /> 15 40000000000007d6: 00 08 01 55 00 00 mov.i ar.pfs=r33<br /> 40000000000007dc: 00 0a 00 07 mov b0=r32<br /> 40000000000007e0: 1d 60 00 44 00 21 [MFB] mov r12=r34<br /> 40000000000007e6: 00 00 00 02 00 80 nop.f 0x0<br /> 40000000000007ec: 08 00 84 00 br.ret.sptk.many b0;;;<br /><br />The call to 0x4000000000000520 must be us calling the printf function. We can find out where this is by looking at the sections with readelf.<br /><br />Example 9-10. Hello world sections<br /><br /> $ readelf --sections ./hello<br /> There are 40 section headers, starting at offset 0x25c0:<br /> <br /> Section Headers:<br /> 5 [Nr] Name Type Address Offset<br /> Size EntSize Flags Link Info Align<br /> [ 0] NULL 0000000000000000 00000000<br /> 0000000000000000 0000000000000000 0 0 0<br /> ...<br /> 10 [11] .plt PROGBITS 40000000000004c0 000004c0<br /> 00000000000000c0 0000000000000000 AX 0 0 32<br /> [12] .text PROGBITS 4000000000000580 00000580<br /> 00000000000004a0 0000000000000000 AX 0 0 32<br /> [13] .fini PROGBITS 4000000000000a20 00000a20<br /> 15 0000000000000040 0000000000000000 AX 0 0 16<br /> [14] .rodata PROGBITS 4000000000000a60 00000a60<br /> 000000000000000f 0000000000000000 A 0 0 8<br /> [15] .opd PROGBITS 4000000000000a70 00000a70<br /> 0000000000000070 0000000000000000 A 0 0 16<br /> 20 [16] .IA_64.unwind_inf PROGBITS 4000000000000ae0 00000ae0<br /> 00000000000000f0 0000000000000000 A 0 0 8<br /> [17] .IA_64.unwind IA_64_UNWIND 4000000000000bd0 00000bd0<br /> 00000000000000c0 0000000000000000 AL 12 c 8<br /> [18] .init_array INIT_ARRAY 6000000000000c90 00000c90<br /> 25 0000000000000018 0000000000000000 WA 0 0 8<br /> [19] .fini_array FINI_ARRAY 6000000000000ca8 00000ca8<br /> 0000000000000008 0000000000000000 WA 0 0 8<br /> [20] .data PROGBITS 6000000000000cb0 00000cb0<br /> 0000000000000004 0000000000000000 WA 0 0 4<br /> 30 [21] .dynamic DYNAMIC 6000000000000cb8 00000cb8<br /> 00000000000001e0 0000000000000010 WA 5 0 8<br /> [22] .ctors PROGBITS 6000000000000e98 00000e98<br /> 0000000000000010 0000000000000000 WA 0 0 8<br /> [23] .dtors PROGBITS 6000000000000ea8 00000ea8<br /> 35 0000000000000010 0000000000000000 WA 0 0 8<br /> [24] .jcr PROGBITS 6000000000000eb8 00000eb8<br /> 0000000000000008 0000000000000000 WA 0 0 8<br /> [25] .got PROGBITS 6000000000000ec0 00000ec0<br /> 0000000000000050 0000000000000000 WAp 0 0 8<br /> 40 [26] .IA_64.pltoff PROGBITS 6000000000000f10 00000f10<br /> 0000000000000030 0000000000000000 WAp 0 0 16<br /> [27] .sdata PROGBITS 6000000000000f40 00000f40<br /> 0000000000000010 0000000000000000 WAp 0 0 8<br /> [28] .sbss NOBITS 6000000000000f50 00000f50<br /> 45 0000000000000008 0000000000000000 WA 0 0 8<br /> [29] .bss NOBITS 6000000000000f58 00000f50<br /> 0000000000000008 0000000000000000 WA 0 0 8<br /> [30] .comment PROGBITS 0000000000000000 00000f50<br /> 00000000000000b9 0000000000000000 0 0 1<br /> 50 [31] .debug_aranges PROGBITS 0000000000000000 00001010<br /> 0000000000000090 0000000000000000 0 0 16<br /> [32] .debug_pubnames PROGBITS 0000000000000000 000010a0<br /> 0000000000000025 0000000000000000 0 0 1<br /> [33] .debug_info PROGBITS 0000000000000000 000010c5<br /> 55 00000000000009c4 0000000000000000 0 0 1<br /> [34] .debug_abbrev PROGBITS 0000000000000000 00001a89<br /> 0000000000000124 0000000000000000 0 0 1<br /> [35] .debug_line PROGBITS 0000000000000000 00001bad<br /> 00000000000001fe 0000000000000000 0 0 1<br /> 60 [36] .debug_str PROGBITS 0000000000000000 00001dab<br /> 00000000000006a1 0000000000000001 MS 0 0 1<br /> [37] .shstrtab STRTAB 0000000000000000 0000244c<br /> 000000000000016f 0000000000000000 0 0 1<br /> [38] .symtab SYMTAB 0000000000000000 00002fc0<br /> 65 0000000000000b58 0000000000000018 39 60 8<br /> [39] .strtab STRTAB 0000000000000000 00003b18<br /> 0000000000000479 0000000000000000 0 0 1<br /> Key to Flags:<br /> W (write), A (alloc), X (execute), M (merge), S (strings)<br /> 70 I (info), L (link order), G (group), x (unknown)<br /> O (extra OS processing required) o (OS specific), p (processor specific);<br /><br />That address is (unsurprisingly) in the .plt section. So there we have our call into the PLT! But we're not satisfied with that, let's keep digging further to see what we can uncover. We disassemble the .plt section to see what that call actually does.<br /><br />Example 9-11. Hello world PLT<br /><br /> 40000000000004c0 <.plt>:<br /> 40000000000004c0: 0b 10 00 1c 00 21 [MMI] mov r2=r14;;<br /> 40000000000004c6: e0 00 08 00 48 00 addl r14=0,r2<br /> 40000000000004cc: 00 00 04 00 nop.i 0x0;;<br /> 5 40000000000004d0: 0b 80 20 1c 18 14 [MMI] ld8 r16=[r14],8;;<br /> 40000000000004d6: 10 41 38 30 28 00 ld8 r17=[r14],8<br /> 40000000000004dc: 00 00 04 00 nop.i 0x0;;<br /> 40000000000004e0: 11 08 00 1c 18 10 [MIB] ld8 r1=[r14]<br /> 40000000000004e6: 60 88 04 80 03 00 mov b6=r17<br /> 10 40000000000004ec: 60 00 80 00 br.few b6;;<br /> 40000000000004f0: 11 78 00 00 00 24 [MIB] mov r15=0<br /> 40000000000004f6: 00 00 00 02 00 00 nop.i 0x0<br /> 40000000000004fc: d0 ff ff 48 br.few 40000000000004c0 <_init+0x50>;;<br /> 4000000000000500: 11 78 04 00 00 24 [MIB] mov r15=1<br /> 15 4000000000000506: 00 00 00 02 00 00 nop.i 0x0<br /> 400000000000050c: c0 ff ff 48 br.few 40000000000004c0 <_init+0x50>;;<br /> 4000000000000510: 11 78 08 00 00 24 [MIB] mov r15=2<br /> 4000000000000516: 00 00 00 02 00 00 nop.i 0x0<br /> 400000000000051c: b0 ff ff 48 br.few 40000000000004c0 <_init+0x50>;;<br /> 20 4000000000000520: 0b 78 40 03 00 24 [MMI] addl r15=80,r1;;<br /> 4000000000000526: 00 41 3c 70 29 c0 ld8.acq r16=[r15],8<br /> 400000000000052c: 01 08 00 84 mov r14=r1;;<br /> 4000000000000530: 11 08 00 1e 18 10 [MIB] ld8 r1=[r15]<br /> 4000000000000536: 60 80 04 80 03 00 mov b6=r16<br /> 25 400000000000053c: 60 00 80 00 br.few b6;;<br /> 4000000000000540: 0b 78 80 03 00 24 [MMI] addl r15=96,r1;;<br /> 4000000000000546: 00 41 3c 70 29 c0 ld8.acq r16=[r15],8<br /> 400000000000054c: 01 08 00 84 mov r14=r1;;<br /> 4000000000000550: 11 08 00 1e 18 10 [MIB] ld8 r1=[r15]<br /> 30 4000000000000556: 60 80 04 80 03 00 mov b6=r16<br /> 400000000000055c: 60 00 80 00 br.few b6;;<br /> 4000000000000560: 0b 78 c0 03 00 24 [MMI] addl r15=112,r1;;<br /> 4000000000000566: 00 41 3c 70 29 c0 ld8.acq r16=[r15],8<br /> 400000000000056c: 01 08 00 84 mov r14=r1;;<br /> 35 4000000000000570: 11 08 00 1e 18 10 [MIB] ld8 r1=[r15]<br /> 4000000000000576: 60 80 04 80 03 00 mov b6=r16<br /> 400000000000057c: 60 00 80 00 br.few b6;;;<br /><br />Let us step through the instructions. Firstly, we add 80 to the value in r1, storing it in r15. We know from before that r1 will be pointing to the GOT, so this is saying "store in r15 80 bytes into the GOT". The next thing we do is load into r16 the value stored in this location in the GOT, and post increment the value in r15 by 8 bytes. We then store r1 (the location of the GOT) in r14 and set r1 to be the value in the next 8 bytes after r15. Then we branch to r16.<br /><br />In the previous chapter we discussed how functions are actually called through a function descriptor which contains the function address and the address of the global pointer. Here we can see that the PLT entry is first loading the function value, moving on 8 bytes to the second part of the function descriptor and then loading that value into the gp register before calling the function.<br /><br />But what exactly are we loading? We know that r1 will be pointing to the GOT. We go 80 bytes past the got (0x50)<br /><br />Example 9-12. Hello world GOT<br /><br /> $ objdump --disassemble-all ./hello <br /> Disassembly of section .got:<br /> <br /> 6000000000000ec0 <.got>:<br /> 5 ...<br /> 6000000000000ee8: 80 0a 00 00 00 00 data8 0x02a000000<br /> 6000000000000eee: 00 40 90 0a dep r0=r0,r0,63,1<br /> 6000000000000ef2: 00 00 00 00 00 40 [MIB] (p20) break.m 0x1<br /> 6000000000000ef8: a0 0a 00 00 00 00 data8 0x02a810000<br /> 10 6000000000000efe: 00 40 50 0f br.few 6000000000000ef0 <_GLOBAL_OFFSET_TABLE_+0x30><br /> 6000000000000f02: 00 00 00 00 00 60 [MIB] (p58) break.m 0x1<br /> 6000000000000f08: 60 0a 00 00 00 00 data8 0x029818000<br /> 6000000000000f0e: 00 40 90 06 br.few 6000000000000f00 <_GLOBAL_OFFSET_TABLE_+0x40><br /> Disassembly of section .IA_64.pltoff:<br /> 15 <br /> 6000000000000f10 <.IA_64.pltoff>:<br /> 6000000000000f10: f0 04 00 00 00 00 [MIB] (p39) break.m 0x0<br /> 6000000000000f16: 00 40 c0 0e 00 00 data8 0x03b010000<br /> 6000000000000f1c: 00 00 00 60 data8 0xc000000000<br /> 20 6000000000000f20: 00 05 00 00 00 00 [MII] (p40) break.m 0x0<br /> 6000000000000f26: 00 40 c0 0e 00 00 data8 0x03b010000<br /> 6000000000000f2c: 00 00 00 60 data8 0xc000000000<br /> 6000000000000f30: 10 05 00 00 00 00 [MIB] (p40) break.m 0x0<br /> 6000000000000f36: 00 40 c0 0e 00 00 data8 0x03b010000<br /> 25 6000000000000f3c: 00 00 00 60 data8 0xc000000000;<br /><br />0x6000000000000ec0 + 0x50 = 0x6000000000000f10, or the .IA_64.pltoff section. Now we're starting to get somewhere!<br /><br />We can decode the objdump output so we can see exactly what is being loaded here. Swapping the byte order of the first 8 bytes f0 04 00 00 00 00 00 40 we end up with 0x4000000000004f0. Now that address looks familiar! Looking back up at the assemble output of the PLT we see that address.<br /><br />The code at 0x4000000000004f0 firstly puts a zero value into r15, and then branches back to 0x40000000000004c0. Wait a minute! That's the start of our PLT section.<br /><br />We can trace this code through too. Firstly we save the value of the global pointer (r2) then we load three 8 byte values into r16, r17 and finally, r1. We then branch to the address in r17. What we are seeing here is the actual call into the dynamic linker!<br /><br />We need to delve into the ABI to understand exactly what is being loaded at this point. The ABI says two things -- dynamically linked programs must have a special section (called the DT_IA_64_PLT_RESERVE section) that can hold three 8 byte values. There is a pointer where this reserved area in the dynamic segment of the binary.<br /><br />Example 9-13. Dynamic Segment<br /><br /> Dynamic segment at offset 0xcb8 contains 25 entries:<br /> Tag Type Name/Value<br /> 0x0000000000000001 (NEEDED) Shared library: [libc.so.6.1]<br /> 0x000000000000000c (INIT) 0x4000000000000470<br /> 5 0x000000000000000d (FINI) 0x4000000000000a20<br /> 0x0000000000000019 (INIT_ARRAY) 0x6000000000000c90<br /> 0x000000000000001b (INIT_ARRAYSZ) 24 (bytes)<br /> 0x000000000000001a (FINI_ARRAY) 0x6000000000000ca8<br /> 0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)<br /> 10 0x0000000000000004 (HASH) 0x4000000000000200<br /> 0x0000000000000005 (STRTAB) 0x4000000000000330<br /> 0x0000000000000006 (SYMTAB) 0x4000000000000240<br /> 0x000000000000000a (STRSZ) 138 (bytes)<br /> 0x000000000000000b (SYMENT) 24 (bytes)<br /> 15 0x0000000000000015 (DEBUG) 0x0<br /> 0x0000000070000000 (IA_64_PLT_RESERVE) 0x6000000000000ec0 -- 0x6000000000000ed8<br /> 0x0000000000000003 (PLTGOT) 0x6000000000000ec0<br /> 0x0000000000000002 (PLTRELSZ) 72 (bytes)<br /> 0x0000000000000014 (PLTREL) RELA<br /> 20 0x0000000000000017 (JMPREL) 0x4000000000000420<br /> 0x0000000000000007 (RELA) 0x40000000000003f0<br /> 0x0000000000000008 (RELASZ) 48 (bytes)<br /> 0x0000000000000009 (RELAENT) 24 (bytes)<br /> 0x000000006ffffffe (VERNEED) 0x40000000000003d0<br /> 25 0x000000006fffffff (VERNEEDNUM) 1<br /> 0x000000006ffffff0 (VERSYM) 0x40000000000003ba<br /> 0x0000000000000000 (NULL) 0x0;<br /><br />Do you notice anything about it? It's the same value as the GOT. This means that the first three 8 byte entries in the GOT are actually the reserved area; thus will always be pointed to by the global pointer.<br /><br />When the dynamic linker starts it is its duty to fill these values in. The ABI says that the first value will be filled in by the dynamic linker giving this module a unique ID. The second value is the global pointer value for the dynamic linker, and the third value is the address of the function that finds and fixes up the symbol.<br /><br />Example 9-14. Code in the dynamic linker for setting up special values (from libc sysdeps/ia64/dl-machine.h)<br /><br /> /* Set up the loaded object described by L so its unrelocated PLT<br /> entries will jump to the on-demand fixup code in dl-runtime.c. */<br /> <br /> static inline int __attribute__ ((unused, always_inline))<br /> 5 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)<br /> {<br /> extern void _dl_runtime_resolve (void);<br /> extern void _dl_runtime_profile (void);<br /> <br /> 10 if (lazy)<br /> {<br /> register Elf64_Addr gp __asm__ ("gp");<br /> Elf64_Addr *reserve, doit;<br /> <br /> 15 /*<br /> * Careful with the typecast here or it will try to add l-l_addr<br /> * pointer elements<br /> */<br /> reserve = ((Elf64_Addr *)<br /> 20 (l->l_info[DT_IA_64 (PLT_RESERVE)]->d_un.d_ptr + l->l_addr));<br /> /* Identify this shared object. */<br /> reserve[0] = (Elf64_Addr) l;<br /> <br /> /* This function will be called to perform the relocation. */<br /> 25 if (!profile)<br /> doit = (Elf64_Addr) ((struct fdesc *) &_dl_runtime_resolve)->ip;<br /> else<br /> {<br /> if (GLRO(dl_profile) != NULL<br /> 30 && _dl_name_match_p (GLRO(dl_profile), l))<br /> {<br /> /* This is the object we are looking for. Say that we really<br /> want profiling and the timers are started. */<br /> GL(dl_profile_map) = l;<br /> 35 }<br /> doit = (Elf64_Addr) ((struct fdesc *) &_dl_runtime_profile)->ip;<br /> }<br /> <br /> reserve[1] = doit;<br /> 40 reserve[2] = gp;<br /> }<br /> <br /> return lazy;<br /> };<br /><br />We can see how this gets setup by the dynamic linker by looking at the function that does this for the binary. The reserve variable is set from the PLT_RESERVE section pointer in the binary. The unique value (put into reserve[0]) is the address of the link map for this object. Link maps are the internal representation within glibc for shared objects. We then put in the address of _dl_runtime_resolve to the second value (assuming we are not using profiling). reserve[2] is finally set to gp, which has been found from r2 with the __asm__ call.<br /><br />Looking back at the ABI, we see that the relocation index for the entry must be placed in r15 and the unique identifier must be passed in r16.<br /><br />r15 has previously been set in the stub code, before we jumped back to the start of the PLT. Have a look down the entries, and notice how each PLT entry loads r15 with an incremented value? It should come as no surprise if you look at the relocations the printf relocation is number zero.<br /><br />r16 we load up from the values that have been initialised by the dynamic linker, as previously discussed. Once that is ready, we can load the function address and global pointer and branch into the function.<br /><br />What happens at this point is the dynamic linker function _dl_runtime_resolve is run. It finds the relocation; remember how the relocation specified the name of the symbol? It uses this name to find the right function; this might involve loading the library from disk if it is not already in memory, or otherwise sharing the code.<br /><br />The relocation record provides the dynamic linker with the address it needs to "fix up"; remember it was in the GOT and loaded by the initial PLT stub? This means that after the first time the function is called, the second time it is loaded it will get the direct address of the function; short circuiting the dynamic linker.<br />Summary<br /><br />You've seen the exact mechanism behind the PLT, and consequently the inner workings of the dynamic linker. The important points to remember are<br /><br /> *<br /><br /> Library calls in your program actually call a stub of code in the PLT of the binary.<br /> *<br /><br /> That stub code loads an address and jumps to it.<br /> *<br /><br /> Initially, that address points to a function in the dynamic linker which is capable of looking up the "real" function, given the information in the relocation entry for that function.<br /> *<br /><br /> The dynamic linker re-writes the address that the stub code reads, so that the next time the function is called it will go straight to the right address.<br /><br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-69760124416709370482009-02-12T02:16:00.000-08:002009-02-12T02:18:41.906-08:002009-02-12 log<pre><code><br />cat /home/adam/Desktop/work_log/0212.log<br />svn export - export a clean tree from repository or a work copy.<br /><br />svn branches:<br /><br />- create a branch:<br /><br />$ svn copy http://svn.example.com/repos/calc/trunk \<br /> http://svn.example.com/repos/calc/branches/my-calc-branch \<br /> -m "Creating a private branch of /calc/trunk."<br /><br />Committed revision 341.<br /><br />This command causes a near-instantaneous commit in the repository, creating a new directory in revision 341. The new directory is a copy of /calc/trunk. This is shown in Figure 4.3, “Repository with new copy”. [20] While it's also possible to create a branch by using svn copy to duplicate a directory within the working copy, this technique isn't recommended. It can be quite slow, in fact! Copying a directory on the client side is a linear-time operation, in that it actually has to duplicate every file and subdirectory on the local disk. Copying a directory on the server, however, is a constant-time operation, and it's the way most people create branches.<br /><br />- run svn log -r 9238 to read about the exact changeset that fixed the bug, and run svn diff -c 9238 to see the patch itself.<br /><br />GDB:<br /><br />It is often useful to do `display/i $pc' when stepping by machine instructions. This makes GDB automatically display the next instruction to be executed, each time your program stops. See section Automatic Display. <br /><br />GCC manual on inline asm:<br /><br />5.37 Assembler Instructions with C Expression Operands<br />http://gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/Extended-Asm.html#Extended-Asm<br /><br /><br />patch:<br /> -N or --forward<br /> Ignore patches that seem to be reversed or already applied. See also -R.<br /><br />adam@adam-desktop:~$ cat /home/adam/Desktop/work_log/0212.log<br />svn export - export a clean tree from repository or a work copy.<br /><br />svn branches:<br /><br />- create a branch:<br /><br />$ svn copy http://svn.example.com/repos/calc/trunk \<br /> http://svn.example.com/repos/calc/branches/my-calc-branch \<br /> -m "Creating a private branch of /calc/trunk."<br /><br />Committed revision 341.<br /><br />This command causes a near-instantaneous commit in the repository, creating a new directory in revision 341. The new directory is a copy of /calc/trunk. This is shown in Figure 4.3, “Repository with new copy”. [20] While it's also possible to create a branch by using svn copy to duplicate a directory within the working copy, this technique isn't recommended. It can be quite slow, in fact! Copying a directory on the client side is a linear-time operation, in that it actually has to duplicate every file and subdirectory on the local disk. Copying a directory on the server, however, is a constant-time operation, and it's the way most people create branches.<br /><br />- run svn log -r 9238 to read about the exact changeset that fixed the bug, and run svn diff -c 9238 to see the patch itself.<br /><br />GDB:<br /><br />It is often useful to do `display/i $pc' when stepping by machine instructions. This makes GDB automatically display the next instruction to be executed, each time your program stops. See section Automatic Display. <br /><br />GCC manual on inline asm:<br /><br />5.37 Assembler Instructions with C Expression Operands<br />http://gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/Extended-Asm.html#Extended-Asm<br /><br /><br />patch:<br /> -N or --forward<br /> Ignore patches that seem to be reversed or already applied. See also -R.<br /><br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-43031837832985021662009-02-09T02:40:00.001-08:002009-02-09T02:40:50.444-08:002009-02-09 logplat_nand.c driver for BF537-STAMP nand flash driver:<br /><br />http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:drivers:bfin_async_nand<br /><br />Clockevents and dyntick<br />http://lwn.net/Articles/223185/<br />linux/Documentation/timers/<br />http://kernelnewbies.org/Linux_2_6_21#head-8547911895fda9cdff32a94771c8f5706d66bba0liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-67893121272468775612009-02-02T01:45:00.000-08:002009-02-02T02:00:07.624-08:00fstabKey points:<br /><br />One can use Label, UUID, besides the device nodes to mount a device.<br /><br />More information can be found at http://ubuntuforums.org/showthread.php?t=283131<br /><br /><pre><code><br />Understanding fstab<br /><br />Sorry this is such a long post.<br /><br />I added much of this information to the Ubuntu wiki.<br /><br />Ubuntu Wiki : fstab<br /><br />There are essentially 5 sections:<br /><br /> 1. Introduction / Mount.<br /> 2. "fstab syntax" - Syntax and fstab options.<br /> 3. How to label, FAT and Linux file systems.<br /> 4. Examples, FAT and Linux native file systems.<br /> 5. References<br /><br /><br />Scroll down to the section you need.<br /><br />Introduction<br /><br />/etc/fstab is a system configuration file and is used to tell the Linux kernel which partitions (file systems) to mount and where on the file system tree.<br /><br />/etc/mtab is an index of all mounted partitions/file systems.<br /><br />Note: See references section at the end of this how to for useful links.<br /><br />How to mount<br /><br />The mount command and fstab go hand in hand:<br /><br /> 1. Options for mount and fstab are similar.<br /> 2. If a device/partition is not listed in fstab ONLY ROOT may mount the device/partition.<br /> 3. Users can mount a removable device using pmount.<br /> 4. Users may mount a device/partition if the device is in fstab with the proper options.<br /><br /><br />How to mount<br />Mount Partitions Automatically (At BOOT).<br />Filesystems and Mounting Thanks Hermanzone<br /><br />mount has a multitude of options. Manpage: man mount<br /><br />pmount: Pmount allows a user to mount removable media.<br />pmount uses /media/<NAME> as the mount point.<br /><br />Syntax:<br />Quote:<br />pmount <device> <NAME><br />Example:<br />Code:<br /><br />pmount /dev/dsa1 data<br /><br />This creates a directory "data" in /media (mount point is /media/data) and mounts your removable device there.<br /><br />To unmount:<br />Code:<br /><br />pumount <NAME><br /><br />Note: pmount does not like to mount to an existing directory in /media.<br /><br /> * For example, if you have a directory /media/usb ; pmount /dev/sda1 usb may fail.<br /> * If you are having problems with gnome-volume-manager or pmount check the contents of /media and delete directories as needed.<br /> * Obviously do not delete a directory in /media if a device is mounted to this mount point.<br /><br /><br />Configure pmount for internal drives<br /><br />To show your partitions/usb devices, first plug in your usb card.<br /><br />To list your mounted partitions:<br />Code:<br /><br />mount<br /><br />To list all your partitions, mounted or not:<br />Code:<br /><br />sudo fdisk -l<br /><br />To list all your partitions by UUID:<br />First connect all your devices, then:<br />Code:<br /><br />ls /dev/disk/by-uuid -alh<br /><br />============== END OF INTRODUCTION ===============<br /><br /><br />fstab Syntax<br /><br />Quote:<br />[Device] [Mount Point] [File_system] [Options] [dump] [fsck order]<br />Device = Physical location.<br /><br />/dev/hdxy or /dev/sdxy.<br /><br />x will be a letter starting with a, then b,c,....<br />y will be a number starting with 1, then 2,3,....<br /><br />Thus hda1 = First partition on the master HD.<br /><br /> See Basic partitioning for more information<br /><br />Note: zip discs are always numbered "4".<br />Example: USB Zip = /dev/sda4.<br /><br />Note: You can also identify a device by udev, volume label (AKA LABEL), or uuid.<br /><br />These fstab techniques are helpful for removable media because the device (/dev/sdxy) may change. For example, sometimes the USB device will be assigned /dev/sda1, other times /dev/sdb1. This depends on what order you connect USB devices, and where (which USB slot) you use to connect. This can be a major aggravation as you must identify the device before you can mount it. fstab does not work well if the device name keeps changing.<br /><br />To list your devices, first put connect your USB device (it does not need to be mounted).<br />By volume label:<br />Code:<br /><br />ls /dev/disk/by-label -lah<br /><br />By id:<br />Code:<br /><br />ls /dev/disk/by-id -lah<br /><br />By uuid:<br />Code:<br /><br />ls /dev/disk/by-uuid -lah<br /><br />IMO, LABEL is easiest to use as you can set a label and it is human readable.<br /><br />The format to use instead of the device name in the fstab file is:<br /><br />LABEL=<label> (Where <label> is the volume label name, ex. "data").<br /><br />UUID=<uuid> (Where <uuid> is some alphanumeric (hex) like fab05680-eb08-4420-959a-ff915cdfcb44).<br /><br />Again, IMO, using a label has a strong advantage with removable media (flash drives).<br /><br />See How to use Labels below.<br /><br />For udev: udev does the same thing as LABEL, but I find it more complicated.<br />See How to udev for a very nice how to on udev.<br /><br /><br />Mount point.<br />This is where the partition is mounted or accessed within the "tree" (ie /mnt/hda1).<br />You can use any name you like.<br />In general<br /><br /> 1. /mnt Typically used for fixed hard drives HD/SCSI.<br /> 2. /media Typically used for removable media (CD/DVD/USB/Zip).<br /><br /><br />Examples:<br /><br /> 1. /mnt/windows<br /> 2. /mnt/data<br /> 3. /media/usb<br /><br /><br />To make a mount point:<br />Code:<br /><br />sudo mkdir /media/usb<br /><br />File types:<br /><br />auto: The file system type (ext3, iso9660, etc) it detected automatically. Usually works. Used for removable devices (CD/DVD, Floppy drives, or USB/Flash drives) as the file system may vary on these devices.<br /><br /><br />Linux file systems: ext2, ext3, jfs, reiserfs, reiser4, xfs, swap.<br /><br />Windows:<br />vfat = FAT 32, FAT 16<br />ntfs= NTFS<br /><br />Note: For NTFS rw ntfs-3g<br /><br />CD/DVD/iso: iso9660<br /><br /> To mount an iso image (*.iso NOT CD/DVD device):<br /> Code:<br /><br /> sudo mount -t iso9660 -o ro,loop=/dev/loop0 <ISO_File> <Mount_Point><br /><br />Network file systems: This section assumes the server and client are already setup.<br /><br /><br />nfs Example:<br />Quote:<br />server:/shared_directory /mnt/nfs nfs <options> 0 0<br /><br /> More detailed information on nfs<br /><br />smb (samba) : Samba mounts can be performed very easily via gui tools (See Ubuntu Wiki Setting up Samba). If you mount a samba share with the gui tools it will be placed in ~/.gvfs , a hidden directory in your home directory.<br /><br />This section is limited to fstab and you will need a fstab entry to mount samba shares at boot.<br /><br />smbfs is now depreciated for cifs : http://linux-cifs.samba.org/<br /><br />cifs still uses a credentials file to avoid the need to enter a password. If you do not use a credentials file, you will mount a samba share with sudo and enter your username and password in a terminal.<br /><br />Quote:<br />//Server/share /mnt/samba cifs users,auto,credentials=/path/credentials_file,noexec 0 0<br /><br /> * Server = Name (if in /etc/hosts) or IP Address of samba server.<br /> * share = Name of shared directory (folder).<br /> * /mnt/samba = your desired mount point.<br /> * /path/credentials_file = full path to your credentials file. A credentials file should be owned by root (permissions 400) and contain two lines :<br /> Quote:<br /> username = samba_user<br /> password = samba_user_password<br /><br /> samba_user = samba user (on server).<br /><br /> samba_user_password = samba user password (on server).<br /><br /> * noexec for security (it can be bypassed ...).<br /><br /><br />smbfs : depreciated, but similar.<br /><br />Quote:<br />//win_box/shared_folder /mnt/samba smbfs rw,credentials=/home/user_name/winbox-credentials.txt 0 0<br />And from Buck2348:<br /><br /> Quote:<br /> I don't mount any vfat shares but uid and gid work with smbfs shares. I might have to try out your syntax.<br /><br /> I could not automount at boot my smbfs shares until I found the this fix in the Forums. I hope it will help someone else. I think the problem was related to the fact that I don't use a username and password in the Windows systems. All I had to do was add<br /> Code:<br /><br /> username=share,password=<br /><br /> to the options list in the fstab line for these shares.<br /><br /> More detailed information on samba<br /><br />sshfs : Network shares over ssh<br /><br />http://ubuntu.wordpress.com/2005/10/...m-using-sshfs/<br /><br />Code:<br /><br />sshfs#user@server:/share fuse user,allow_other 0 0<br /><br /> * "Server" = Samba server (by IP or name if you have an entry for the server in your hosts file<br /> * "share" = name of the shared directory<br /><br /><br /><br />Options:<br /><br />Ubuntu 8.04 now defaults to "relatime". For a discussion of this option see : http://lwn.net/Articles/244829/<br /><br />defaults = rw, suid, dev, exec, auto, nouser, and async.<br /><br />Options for a separate /home : nodev,nosuid,relatime<br /><br />My recommended options for removable (USB) drives are in green.<br /><br />auto= mounted at boot<br />noauto= not mounted at boot<br /><br />user= when mounted the mount point is owned by the user who mounted the partition<br />users= when mounted the mount point is owned by the user who mounted the partition and the group users<br /><br />ro= read only<br />rw= read/write<br /><br />VFAT/NTFS:<br /><br />Ownership and permissios of vfat / ntfs are set at the time of mounting. This is often a source of confusion.<br /><br />uid= Sets owner. Syntax: may use user_name or user ID #.<br />gid= sets group ownership of mount point. Again may use group_name or GID #.<br /><br />umask can be used to set permissions if you wish to change the default.<br />Syntax is "odd" at first.<br />To set a permissions of 777, umask=000<br />To set permissions of 700, umask=077<br /><br />Best is to set directories with executable permissions and file with read write. To do this, use fmask and dmask (rather then umask):<br />dmask=027<br />fmask=137<br /><br />With these options files are not executable (all colored green in a terminal w/ ls)<br /><br /><br />Linux native file systems: Use defaults or users. To change ownership and permissions, mount the partition, then use chown and chmod.<br /><br />Note: Warning re: sync and flash devices:<br />Warning<br /><br />Additional Options: (From wiki.linuxquestions.org/wiki/Fstab):<br /><br /> * sync/async - All I/O to the file system should be done (a)synchronously.<br /> * auto - The filesystem can be mounted automatically (at bootup, or when mount is passed the -a option). This is really unnecessary as this is the default action of mount -a anyway.<br /> * noauto - The filesystem will NOT be automatically mounted at startup, or when mount passed -a. You must explicitly mount the filesystem.<br /> * dev/nodev - Interpret/Do not interpret character or block special devices on the file system.<br /> * exec / noexec - Permit/Prevent the execution of binaries from the filesystem.<br /> * suid/nosuid - Permit/Block the operation of suid, and sgid bits.<br /> * ro - Mount read-only.<br /> * rw - Mount read-write.<br /> * user - Permit any user to mount the filesystem. This automatically implies noexec, nosuid,nodev unless overridden.<br /> * nouser - Only permit root to mount the filesystem. This is also a default setting.<br /> * defaults - Use default settings. Equivalent to rw, suid, dev, exec, auto, nouser, async.<br /> * _netdev - this is a network device, mount it after bringing up the network. Only valid with fstype nfs.<br /><br /><br /><br />Dump<br />Dump: Dump field sets whether the backup utility dump will backup file system. If set to "0" file system ignored, "1" file system is backed up.<br /><br /><br /><br />Fsck order<br />Fsck: Fsck order is to tell fsck what order to check the file systems, if set to "0" file system is ignored.<br /><br />See also: Tuning the Filesystem Check at Bootup<br /><br />Fstab Examples<br /><br /><br />Quote:<br />/dev/sda14 /mnt/zen ext3 relatime 0 2<br /><br /># Usb device (assuming vfat)<br />/dev/sdb1 /media/usb auto users,uid=1000,gid=100,utf8,dmask=027,fmask=137 0 0<br /><br />#Data partition<br />LABEL=data /mnt/usr_data ext3 auto,users,rw,relatime 0 0<br /><br /># Flash drive By UUID<br />UUID=fab05680-eb08-4420-959a-ff915cdfcb44 /media/flash vfat user,uid=1000,gid=100,utf8,dmask=027,fmask=137 0 0<br /><br /><br />/dev/disk/by-id/usb-IOMEGA_ZIP_250_059B00301400B0F1-part4 /mnt/zip vfat users,uid=1000,gid=100,utf8,dmask=027,fmask=137 0 0<br /><br />/dev/hda1 /mnt/windows ntfs-3g auto,users,uid=1000,gid=100,utf8,dmask=027,fmask=1 37 0 0<br /><br /># VFAT<br /># FAT ~ Linux calls FAT file systems vfat)<br /># /dev/hda1<br />UUID=12102C02102CEB83 /media/windows vfat auto,users,uid=1000,gid=100,utf8,dmask=027,fmask=1 37 0 0<br /><br /># NTFS ~ Use ntfs-3g for write access (rw)<br /># /dev/hda1<br />UUID=12102C02102CEB83 /media/windows ntfs-3g auto,users,uid=1000,gid=100,utf8,dmask=027,fmask=1 37 0 0<br /><br /><br /># Separate Home<br /># /dev/sda7<br />UUID=413eee0c-61ff-4cb7-a299-89d12b075093 /home ext3 nodev,nosuid,relatime 0 2<br /><br /># Samba<br />//server/share /media/samba cifs user=user,uid=1000,gid=100 0 0<br /># "Server" = Samba server (by IP or name if you have an entry for the server in your hosts file<br /># "share" = name of the shared directory<br /># "user" = your samba user<br /># This set up will ask for a password when mounting the samba share. If you do not want to enter a password, use a credentials file.<br /># replace "user=user" with "credentials=/etc/samba/credentials" In the credentials file put two lines<br /># user=user<br /># password=password<br /># make the file owned by root and ro by root (sudo chown root.root /etc/samba/credentials && sudo chmod 400 /etc/samba/credentials)<br /><br /># NFS<br />Server:/share /media/nfs nfs rsize=8192 and wsize=8192,noexec,nosuid<br /># "Server" = Samba server (by IP or name if you have an entry for the server in your hosts file<br /># "share" = name of the shared directory<br /><br />#SSHFS<br />Sshfs#user@server:/share fuse user,allow_other 0 0<br /># "Server" = Samba server (by IP or name if you have an entry for the server in your hosts file<br /># "share" = name of the shared directory<br />=========== End of fstab =============<br /><br /><br />How to Label<br /><br />Linux: How the label and the UUID are set depends on the file system type used. It can normally be set when creating/formatting the file system and the file system type usually has some tool to change it later on (e.g. e2tunefs,xfs_admin,reiserfstune,etc.)<br /><br />Labels<br /><br />Mke2fs/e2label/tune2fs:<br /><br />Note: For either ext2 or ext3 file systems.<br /><br />WARNING: mke2fs will reformat your partition and set a label at the same time. This will delete any data on the target partition.<br /><br />To set a label without reformatting use e2label or tune2fs<br /><br /> 1. Make a label:<br /> Code:<br /><br /> mke2fs -L <label> <dev><br /><br /> OR<br /> Code:<br /><br /> e2label <dev> <label><br /><br /> OR<br /> Code:<br /><br /> tune2fs -L <label> <dev><br /><br /> Examples:<br /> Quote:<br /> mke2fs -L data /dev/hda3<br /> OR<br /> Quote:<br /> e2label /dev/hda3 data<br /> OR<br /> Quote:<br /> tune2fs -L data /dev/hda3<br /> 2. Create a mount point:<br /> Code:<br /><br /> sudo mkdir /media/data<br /><br /> 3. Add an entry to /etc/fstab:<br /> Quote:<br /> LABEL=data /media/data ext3 defaults 0 0<br /> 4. To mount:<br /> Code:<br /><br /> sudo mount LABEL=data<br /><br /><br /><br />ReiserFS:<br />Use reiserfstune:<br />Code:<br /><br />reiserfstune --l <Label> <device><br /><br /> Note:That is a small "L" and not the number 1.<br /><br />JFS:<br />Use jfs_tune:<br />Code:<br /><br />jfs_tune -L <Label> <device><br /><br />To show the label:<br />Code:<br /><br />jfs_tune -l <device><br /><br /> Note:That is a small "L" and not the number 1.<br /><br />XFS:<br />Use xfs_admin:<br />Code:<br /><br />sudo xfs_admin -L <Label> <device><br /><br />To show the label:<br />Code:<br /><br />xfs_admin -l <device><br /><br /> Note:That is a small "L" and not the number 1.<br /><br />FAT (Windows partitions):<br /><br />Use mtools to label a FAT partition:<br /><br /> 1. Install mtools:<br /> Code:<br /><br /> sudo aptitude install mtools<br /><br /> 2. Copy the mtools configuration file to ~:<br /> Code:<br /><br /> cp /etc/mtools.conf ~/.mtoolsrc<br /><br /> Note: ~ is shorthand for /home/user_name.<br /> 3. Mount your flash drive.<br /> 4. Edit ~/.mtoolsrc:<br /> Code:<br /><br /> gedit ~/.mtoolsrc<br /><br /> 5. Add these lines to the end of ~/.mtoolsrc:<br /> Quote:<br /> drive i: file="<device>"<br /> mtools_skip_check=1<br /> Where <device> is the device assigned to your mounted USB device/flash drive (ie sda1, sdb1, ...).<br /> Note: You can do this from the command line:<br /> Code:<br /><br /> echo 'drive i: file="<device>"' >> ~/.mtoolsrc<br /> echo mtools_skip_check=1 >> ~/.mtoolsrc<br /><br /> Although you will need to edit ~/.mtoolsrc for each new device if the device assignment changes.<br /><br /> Example: = drive i: file="/dev/sda1"<br /> 6. Change to drive i:<br /> Code:<br /><br /> mcd i:<br /><br /> 7. Check the current label:<br /> Code:<br /><br /> mlabel -s i:<br /><br /> 8. Change the current label:<br /> Code:<br /><br /> sudo mlabel -s i:DATA<br /><br /> 9. Or<br /> Code:<br /><br /> sudo mlabel i:DATA<br /><br /> pieroxy reports the -s flag did not work, thanks pieroxy<br /><br /> Note: mlabel USES ALL CAPS.<br /><br /> 10. Add an entry to fstab:<br /> Quote:<br /> LABEL=DATA <mount_point> vfat defaults 0 0<br /> Note: You can also mount the usb device with:<br /> Code:<br /><br /> mount LABEL=<label><br /><br /><br />NTFS (Windows partitions):<br /><br /> Thanks to rudyj for pointing out the oversight.<br /><br />Use ntfsprogs:<br /><br />First install ntfsprogs:<br />Code:<br /><br />sudo aptitude install ntfsprogs<br /><br />Or use Synaptic.<br /><br />Then:<br /><br /> 1. Show label:<br /> Code:<br /><br /> ntfslabel <device><br /><br /> 2. Change label:<br /> Code:<br /><br /> ntfslabel <device> <label><br /><br /> Where:<br /> * <label> = your new label<br /> * <device> = your partition to label (/dev/hda1 perhaps)<br /><br /> 3. Add an entry to fstab:<br /> Quote:<br /> LABEL=DATA <mount_point> ntfs(or ntfs-3g) defaults 0 0<br /> Note: You can also mount the usb device with:<br /> Code:<br /><br /> mount LABEL=<label><br /><br /><br /><br />============== END OF LABEL ===============<br /><br /><br />Examples of fstab options<br /><br /><br />********* FAT **********<br /><br />FAT partitions are easy to share between Linux and Windows as both OS will read FAT "out of the box" without additional installation or configuration.<br /><br />In this example I will use /mnt/data as my mount point.<br /><br />Code:<br /><br />sudo mkdir /mnt/data<br /><br />fstab:<br />Quote:<br />LABEL=data /mnt/data vfat <see options below> 0 0<br />Default permissions of /mnt/data:<br />Quote:<br />drwxr-xr-x 2 root root<br /><br /> 1. fstab options: defaults<br /> mount /mnt/data yields: mount: only root can mount /dev/sdb1 on /mnt/data<br /><br /> sudo mount /mnt/data mounts the device.<br /> Permissions:<br /> Quote:<br /> drwxr-xr-x 7 root root<br /> Note: ONLY ROOT has rw permissions.<br /> 2. fstab options: users,noauto,rw<br /> mount /mnt/data mounts the partition.<br /> Permissions:<br /> Quote:<br /> drwxr-xr-x 7 bodhi adm<br /> Note: The user can mount the device and has rw permissions.<br /> Note: The ownership and permissions of the mount point have changed !<br /> 3. fstab options: users,noauto,gid=100,umask=007<br /> mount /mnt/data mounts the partition.<br /> Permissions:<br /> Quote:<br /> drwxrwx--- 7 bodhi users<br /> Note: The user can mount the device and now both the user and the users group have rw permissions.<br /> Note: The ownership and permissions of the mount point have changed again !<br /><br /><br /><br />********* Linux Native File Systems **********<br /><br />In this example I will use ext3, but this holds true for ext2, reiserfs, jfs, and xfs.<br /><br />Code:<br /><br />sudo mkdir /mnt/ext3<br /><br />fstab:<br />Quote:<br />LABEL=ext3 /mnt/ext3 auto <see options below> 0 0<br /><br /> 1. fstab options: defaults<br /> mount /mnt/data yields: mount: only root can mount LABEL=ext3 on /mnt/ext3<br /><br /> sudo mount /mnt/ext3 mounts the device.<br /> Permissions:<br /> Quote:<br /> bodhi@Arch:~$ls -l /mnt | grep ext3<br /> drwxr-xr-x 3 bodhi users 1024 2006-11-07 17:26 ext3<br /> Note: Ownership has changed ! owner=bodhi, group=users, however ONLY USER (and root of course) has rw permissions.<br /> 2. fstab options: users,noauto<br /><br /> mount /mnt/ext3 mounts the partition.<br /> Permissions:<br /> Quote:<br /> bodhi@Arch:~$mount /mnt/ext3/<br /> bodhi@Arch:~$ls -l /mnt | grep ext3<br /> drwxr-xr-x 3 bodhi users 1024 2006-11-07 17:26 ext3<br /> Note: The user can mount the device and has rw permissions.<br /> Note: Ownership remains bodhi:users<br /><br /> Note: ext2 and ext3 do not take uid=xxx, gid=xxx, or umask=xxx<br /><br /> To set group rw permissions:<br /> fstab options: users,noauto<br /> 1. mount the partition: mount /mnt/ext3<br /> 2. Set permisions of the mount point: chmod 777 /mnt/ext3<br /><br /> The set ownership and permissions will remain in effect with un-mount and re-boot.<br /><br /> Example:<br /> Quote:<br /> bodhi@Arch:~$chmod 777 /mnt/ext3<br /> bodhi@Arch:~$ls -l /mnt | grep ext3<br /> drwxrwxrwx 3 bodhi users 1024 2006-11-07 17:51 ext3<br /> bodhi@Arch:~$umount /mnt/ext3/<br /> bodhi@Arch:~$ls -l /mnt | grep ext3<br /> drwxr-xr-x 2 root root 4096 2006-11-07 17:28 ext3<br /> bodhi@Arch:~$mount /mnt/ext3/<br /> bodhi@Arch:~$ls -l /mnt | grep ext3<br /> drwxrwxrwx 3 bodhi users 1024 2006-11-07 17:51 ext3<br /> bodhi@Arch:~$<br /> Note: The permissions revert when the partition is un-mounted RED<br /> Note: The permissions remain rw when the partition is re-mounted BLUE<br /> Permissions:<br /> Note: The user can mount the device and now both the user and the users group have rw permissions.<br /><br /><br /><br />============== END OF EXAMPLES ===============<br /><br /><br />References<br /><br />Partitioning: Basic partitioning<br /><br />Mount:<br /><br />How to mount filesystems in Linux<br />Ubuntu Automatically Mount Partitions<br />man mount<br />Mount Other Filesystems<br /><br />Fstab:<br />fstab wiki<br />How to edit and understand /etc/fstab<br />Tuning the Filesystem Check at Bootup<br /><br />Labels: How to use Labels<br /><br />udev: How to udev<br /><br />NTFS: ntfs-3g<br /><br />Zip dirve how-to: How to Zip Drive<br /><br />nfs:<br />How to set up NFS<br />How to NFS v4<br />Debian/Ubuntu NFS Guide Short but sweeeet !<br /><br />Mount Windows Sares: Mount Windows shares permanently<br /><br />Samba:<br />Setting up Samba<br />How to mount smbfs shares permanently<br /><br />bodhi.zazen<br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-37852973467471770232009-01-23T06:56:00.000-08:002009-01-23T07:23:36.235-08:00grub usage one caseOriginally grub is installed in MRB of /dev/sda0. Since I want to replace the disk of /dev/sd0, need to install the same grub in /dev/sda1.<br /><br />#sudo grub<br />grub> setup (hd1)<br />grub> quit<br /><br /><pre><code><br />Install Grub<br />------------------<br />In order to install GRUB as your boot loader, you need to first install the GRUB system and utilities under your UNIX-like operating system (see Obtaining and Building GRUB). You can do this either from the source tarball, or as a package for your OS.<br /><br />After you have done that, you need to install the boot loader on a drive (floppy or hard disk). There are two ways of doing that - either using the utility grub-install (see Invoking grub-install) on a UNIX-like OS, or by running GRUB itself from a floppy. These are quite similar, however the utility might probe a wrong BIOS drive, so you should be careful.<br /><br />Also, if you install GRUB on a UNIX-like OS, please make sure that you have an emergency boot disk ready, so that you can rescue your computer if, by any chance, your hard drive becomes unusable (unbootable).<br /><br />GRUB comes with boot images, which are normally put in the directory /usr/lib/grub/i386-pc. If you do not use grub-install, then you need to copy the files stage1, stage2, and *stage1_5 to the directory /boot/grub, and run the grub-set-default (see Invoking grub-set-default) if you intend to use `default saved' (see default) in your configuration file. Hereafter, the directory where GRUB images are initially placed (normally /usr/lib/grub/i386-pc) will be called the image directory, and the directory where the boot loader needs to find them (usually /boot/grub) will be called the boot directory. <br /><br /> Installing GRUB natively<br />-------------------------------<br /><br />Caution: Installing GRUB's stage1 in this manner will erase the normal boot-sector used by an OS.<br /><br />GRUB can currently boot GNU Mach, Linux, FreeBSD, NetBSD, and OpenBSD directly, so using it on a boot sector (the first sector of a partition) should be okay. But generally, it would be a good idea to back up the first sector of the partition on which you are installing GRUB's stage1. This isn't as important if you are installing GRUB on the first sector of a hard disk, since it's easy to reinitialize it (e.g. by running `FDISK /MBR' from DOS).<br /><br />If you decide to install GRUB in the native environment, which is definitely desirable, you'll need to create a GRUB boot disk, and reboot your computer with it. Otherwise, see Installing GRUB using grub-install.<br /><br />Once started, GRUB will show the command-line interface (see Command-line interface). First, set the GRUB's root device4 to the partition containing the boot directory, like this:<br /><br /> grub> root (hd0,0)<br /><br />If you are not sure which partition actually holds this directory, use the command find (see find), like this:<br /><br /> grub> find /boot/grub/stage1<br /><br />This will search for the file name /boot/grub/stage1 and show the devices which contain the file.<br /><br />Once you've set the root device correctly, run the command setup (see setup):<br /><br /> grub> setup (hd0)<br /><br />This command will install the GRUB boot loader on the Master Boot Record (MBR) of the first drive. If you want to put GRUB into the boot sector of a partition instead of putting it in the MBR, specify the partition into which you want to install GRUB:<br /><br /> grub> setup (hd0,0)<br /><br />If you install GRUB into a partition or a drive other than the first one, you must chain-load GRUB from another boot loader. Refer to the manual for the boot loader to know how to chain-load GRUB.<br /><br />After using the setup command, you will boot into GRUB without the GRUB floppy. See the chapter Booting to find out how to boot your operating systems from GRUB. <br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-29525134486531688882009-01-23T00:04:00.000-08:002009-01-23T00:14:54.983-08:00grub <pre><code>
<br />Abstract
<br />This description details the structure at the start of a hard disk in a PC, and how GRUB fits into that structure.
<br />The PC hard disk layout
<br />The diagram below is the disk layout of my linux laptop which is very standard. There are 4 primary partitions whose size and function are labeled, but this document is going to concentrate on the expanded area in the diagram at the start of the disk. I will describe its structure and how GRUB fits in. Note the structure is the same for windows systems, only the content (grub) is different.
<br />
<br />PC hard disk layout
<br />The Master Boot Record
<br />The first sector (512 bytes) is the MBR and consists of, 446 bytes bootloader, 64 bytes partition table and a 2 byte signature (0xAA55). It get its name because it is the first boot record that is loaded, which can then load other boot records from various locations on the disk. To give a hexdump of this first sector of the disk you can do dd bs=512 count=1 if=/dev/hda | od -Ax -tx1z -v (changing /dev/hda as appropriate for your setup):
<br />
<br />
<br />000000 eb 48 90 d0 bc 00 7c fb 50 07 50 1f fc be 1b 7c >.H....|.P.P....|<
<br />000010 bf 1b 06 50 57 b9 e5 01 f3 a4 cb be be 07 b1 04 >...PW...........<
<br />000020 38 2c 7c 09 75 15 83 c6 10 e2 f5 cd 18 8b 14 8b >8,|.u...........<
<br />000030 ee 83 c6 10 49 74 16 38 2c 74 f6 be 10 07 03 02 >....It.8,t......<
<br />000040 80 00 00 80 b8 85 64 00 00 08 fa 80 ca 80 ea 53 >......d........S<
<br />000050 7c 00 00 31 c0 8e d8 8e d0 bc 00 20 fb a0 40 7c >|..1....... ..@|<
<br />000060 3c ff 74 02 88 c2 52 be 79 7d e8 34 01 f6 c2 80 ><.t...R.y}.4....<
<br />000070 74 54 b4 41 bb aa 55 cd 13 5a 52 72 49 81 fb 55 >tT.A..U..ZRrI..U<
<br />000080 aa 75 43 a0 41 7c 84 c0 75 05 83 e1 01 74 37 66 >.uC.A|..u....t7f<
<br />000090 8b 4c 10 be 05 7c c6 44 ff 01 66 8b 1e 44 7c c7 >.L...|.D..f..D|.<
<br />0000a0 04 10 00 c7 44 02 01 00 66 89 5c 08 c7 44 06 00 >....D...f.\..D..<
<br />0000b0 70 66 31 c0 89 44 04 66 89 44 0c b4 42 cd 13 72 >pf1..D.f.D..B..r<
<br />0000c0 05 bb 00 70 eb 7d b4 08 cd 13 73 0a f6 c2 80 0f >...p.}....s.....<
<br />0000d0 84 f0 00 e9 8d 00 be 05 7c c6 44 ff 00 66 31 c0 >........|.D..f1.<
<br />0000e0 88 f0 40 66 89 44 04 31 d2 88 ca c1 e2 02 88 e8 >..@f.D.1........<
<br />0000f0 88 f4 40 89 44 08 31 c0 88 d0 c0 e8 02 66 89 04 >..@.D.1......f..<
<br />000100 66 a1 44 7c 66 31 d2 66 f7 34 88 54 0a 66 31 d2 >f.D|f1.f.4.T.f1.<
<br />000110 66 f7 74 04 88 54 0b 89 44 0c 3b 44 08 7d 3c 8a >f.t..T..D.;D.}<.<
<br />000120 54 0d c0 e2 06 8a 4c 0a fe c1 08 d1 8a 6c 0c 5a >T.....L......l.Z<
<br />000130 8a 74 0b bb 00 70 8e c3 31 db b8 01 02 cd 13 72 >.t...p..1......r<
<br />000140 2a 8c c3 8e 06 48 7c 60 1e b9 00 01 8e db 31 f6 >*....H|`......1.<
<br />000150 31 ff fc f3 a5 1f 61 ff 26 42 7c be 7f 7d e8 40 >1.....a.&B|..}.@<
<br />000160 00 eb 0e be 84 7d e8 38 00 eb 06 be 8e 7d e8 30 >.....}.8.....}.0<
<br />000170 00 be 93 7d e8 2a 00 eb fe 47 52 55 42 20 00 47 >...}.*...GRUB .G<
<br />000180 65 6f 6d 00 48 61 72 64 20 44 69 73 6b 00 52 65 >eom.Hard Disk.Re<
<br />000190 61 64 00 20 45 72 72 6f 72 00 bb 01 00 b4 0e cd >ad. Error.......<
<br />0001a0 10 ac 3c 00 75 f4 c3 00 00 00 00 00 00 00 00 00 >..<.u...........<
<br />0001b0 00 00 00 00 00 00 00 00 5f 00 5f 00 00 00 00 01 >........_._.....<
<br />0001c0 01 00 0b fe 7f 97 3f 00 00 00 59 03 64 00 00 00 >......?...Y.d...<
<br />0001d0 41 98 83 fe 7f a4 98 03 64 00 cd 2f 03 00 00 00 >A.......d../....<
<br />0001e0 41 a5 83 fe ff ff 65 33 67 00 fc 08 fa 00 80 fe >A.....e3g.......<
<br />0001f0 ff ff 0f fe ff ff 61 3c 61 01 1f ed f2 00 55 aa >......a<a.....U.<
<br />
<br />Note there is no mystery about or dissassembly required of the blue section above as GRUB is open source and one can download, inspect and modify its stage 1 source code.
<br />The DOS compatibility region
<br />This region is optional as far as linux is concerned at least, but is added by default by most partition managers. To understand why this region was required we need to describe how disks used to be addressed. Generally now disks are addressed in LBA mode which allows for greater capacity disks while abstracting software away from the specifics of the disk itself. Previously though disks were addressed in CHS mode, which represented the physical construction of the disk as can be seen in the diagram below:
<br />
<br />Cylinders Heads Sectors
<br />
<br />DOS had the requirement that its image did not span across cylinders, and so this region was added by partition managers so that the first partition was aligned on a cylinder boundary. Therefore this region's size is determined by the number of sectors (512 bytes) per cylinder. The maximum (and usual given todays disk sizes and LBA) sectors per cylinder is 63, which leaves 62 sectors free after the MBR (31,744 bytes).
<br />
<br />GRUB uses this region to store its stage 1.5, which is filesystem specific code used to find the operating system image on the "boot" filesystem. Currently GRUB does not need all this space as can be seen for the copies of all the stage 1.5 files in the boot partition:
<br />
<br />$ ls -lS /boot/grub/*stage1_5
<br />-rw-r--r-- 1 root root 9428 Mar 8 14:27 /boot/grub/reiserfs_stage1_5
<br />-rw-r--r-- 1 root root 9308 Mar 8 14:27 /boot/grub/xfs_stage1_5
<br />-rw-r--r-- 1 root root 8448 Mar 8 14:27 /boot/grub/jfs_stage1_5
<br />-rw-r--r-- 1 root root 7956 Mar 8 14:27 /boot/grub/e2fs_stage1_5
<br />-rw-r--r-- 1 root root 7684 Mar 8 14:27 /boot/grub/fat_stage1_5
<br />-rw-r--r-- 1 root root 7272 Mar 8 14:27 /boot/grub/ufs2_stage1_5
<br />-rw-r--r-- 1 root root 7188 Mar 8 14:27 /boot/grub/minix_stage1_5
<br />-rw-r--r-- 1 root root 7028 Mar 8 14:27 /boot/grub/iso9660_stage1_5
<br />-rw-r--r-- 1 root root 6996 Mar 8 14:27 /boot/grub/ffs_stage1_5
<br />-rw-r--r-- 1 root root 6612 Mar 8 14:27 /boot/grub/vstafs_stage1_5
<br />
<br />Therefore one could theoretically use the last 43 sectors of this region (22,016 bytes) for anything. There is no point in creating a filesystem in here as the overhead would be too much, but you could dd stuff in and out like:
<br />dd bs=512 seek=20 count=43 if=myfile of=/dev/hda
<br />dd bs=512 skip=20 count=43 if=/dev/hda of=myfile
<br />Note be very sure you know what your doing before running these commands.
<br />
<br />Note on my laptop the last sector of this region contains the first sector of a MSWIN4.1 boot record (which I understand is 3 sectors in total), as it came with winxp installed (in a FAT32 partition). GRUB makes this sector redundant even in a dual boot situation, so don't worry about overwriting it. You can inspect this sector using: dd bs=512 skip=62 count=1 if=/dev/hda | od -Ax -tx1z -v
<br />GRUB 1 boot process
<br />GRUB or the GRand Unified Bootloader is the usual bootloader used on linux systems, and resides on the system as described above. The boot process with GRUB is as follows:
<br />
<br /> * BIOS code reads MBR from a disk (looks at last 2 bytes to verify if MBR).
<br /> * Starts executing bootloader code (GRUB stage 1).
<br /> * Bootloader jumps to location (sector num) of next stage. This sector num is stored at a particular location in the bootloader "code" at GRUB install time and usually points to a stage 1.5 located in the "DOS compat space" immediately after the MBR.
<br /> * Stage 1.5 knows about the boot filesystem so it opens the filesystem on the specified (at install time) partition. It looks for the stage 2 executable here and executes it. Note since stage 1.5 knows about the boot filesystem it gives much greater flexibility in upgrading stage 2 and the kernel etc. as their new locations don't need to be written to the earlier GRUB stages.
<br /> * Stage 2 contains most of the GRUB logic. It loads the menu.lst file and executes the statements, usually providing a menu to the user etc.
<br />
<br /> Subsequent steps are distro specific but for completeness I'll describe them for my fedora linux distribution:
<br />
<br /> * When GRUB starts booting one of the entries, it reads the initial ramdisk and starts the kernel running telling it about the ramdisk.
<br /> * In the initial ramdisk, the nash shell is run to parse the /linuxrc file. It essentially finds the location of the filesystem it itself is on and passes that to the kernel as its root filesystem. This allows for greater flexibility of the devices the kernel resides on.
<br /> * The kernel reads its root filesystem and executes /bin/init by default. This in turn parses /etc/inittab which usually sets up the login consoles and starts executing the scripts in /etc/init.d
<br /> * These scripts start various subsystems, culminating in starting X. X in turn starts the display manager which gives a login prompt.
<br />
<br />GRUB 2 boot process
<br />The structure of GRUB has changed quite a bit with version 2, (which is still in development at the time of writing). Instead of stage 1, stage 1.5 and stage 2 images it has a collection of modules that can be combined in different ways. To mirror the functionality the original GRUB's stages as described above, you would have for example:
<br />
<br />stage 1 = boot.img
<br />stage 1.5 = diskboot.img+kernel.img+pc.mod+ext2.mod (the core image)
<br />stage 2 = normal.mod+_chain.mod
<br />
<br />The boot process for GRUB 2 then would be:
<br />
<br /> * BIOS code reads MBR from a disk (looks at last 2 bytes to verify if MBR).
<br /> * Starts executing bootloader code (boot.img).
<br /> * This loads the first sector of the core image (diskboot.img), whose location was stored at a particular location in boot.img at GRUB install time and usually points to the core image located in the "DOS compat space" immediately after the MBR. diskboot.img in turn loads and executes the rest of the core image.
<br /> * These core image modules know about the boot filesystem and can open the filesystem on the specified (at install time) partition. It looks for and loads modules there, including normal.mod
<br /> * normal.mod loads the grub.cfg file and executes the statements, usually providing a menu to the user etc.
<br />
<br />This is a more flexible mechanism. For example one can prepend pxeboot.img to the core image instead of diskboot.img. This will then load the whole core image from the network and then start executing kernel.img.
<br />
<br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-63696481316325593642009-01-15T02:18:00.000-08:002009-01-15T02:24:05.816-08:00I/O scheduler<div class="article" lang="en"><div class="simplesect" lang="en"><div class="titlepage"><a name="N0xa50890.0xb44b70"></a></div><p><br />Although most Linux users are familiar with the role of process<br />schedulers, such as the new O(1) scheduler, many users are not so<br />familiar with the role of I/O schedulers. I/O schedulers are similar in<br />some aspects to process schedulers; for instance, both schedule some resource<br />among multiple users. A process scheduler virtualizes the resource of<br />processor time among multiple executing processes on the system. So,<br />what does an I/O scheduler schedule?<br /></p><p><br />A naïve system would not even include an I/O scheduler. Unlike the process<br />scheduler, the I/O scheduler is not a mandatory component of the operating<br />system. Instead, performance is the I/O scheduler's sole<br /><span class="foreignphrase"><i>raison d'être</i></span>.<br /></p><p><br />To understand the role of an I/O scheduler, let's go over some background<br />information and then look at how a system behaves without an I/O<br />scheduler. Hard disks address their data using the familiar geometry-based<br />addressing of cylinders, heads and sectors. A hard<br />drive is composed of multiple platters, each consisting of a single<br />disk, spindle and read/write head. Each platter is divided further into<br />circular ring-like tracks, similar to a CD or record. Finally,<br />each track is composed of some integer number of sectors.<br /></p><p><br />To locate a specific unit of data in a hard drive, the drive's logic<br />requires three pieces of information: the cylinder, the head and the<br />sector. The cylinder specifies the track on which the data resides. If<br />you lay the platters on top of one another (as they are in a hard disk),<br />a given track forms a cylinder through each platter. The head then<br />identifies the exact read/write head (and thus the exact platter)<br />in question. The search now is narrowed down to a single track on a<br />single platter. Finally, the sector value denotes the exact sector on<br />the track. The search is complete: the hard disk knows what sector,<br />on what track, on what platter the data resides. It can position the<br />read/write head of the correct platter over the correct track and read<br />the proper sector.<br /></p><p><br /><br />Thankfully, modern hard disks do not force computers to communicate<br />with them in terms of cylinders, heads and sectors. Instead, modern<br />hard drives map a unique block number over each cylinder/head/sector<br />triplet. The unique number identifies a specific cylinder/head/sector<br />value. Modern operating systems then can address hard drives using<br />this block number—called logical block addressing—and the<br />hard drive translates the block number into the correct<br />cylinder/head/sector value.<br /></p><p><br />One thing of note about this block number: although nothing guarantees<br />it, the physical mapping tends to be sequential. That is, logical<br />block n tends to be physically adjacent to logical block<br />n+1. We discuss why that is important later on.<br /></p><p><br />Now, let's consider the typical UNIX system. Applications as varied<br />as databases, e-mail clients, Web servers and text editors issue I/O<br />requests to the disk, such as read this block and write to that<br />block. The blocks tend to be located physically all over the disk. The<br />e-mail spool may be located in an entirely different region of the disk<br />from the Web server's HTML data or the text editor's configuration<br />file. Indeed, even a single file can be strewn all over the disk if the<br />file is fragmented, that is, not laid out in sequential blocks. Because the files<br />are broken down into individual blocks, and hard drives are addressed by<br />block and not the much more abstract concepts of files, reading or writing<br />file data is broken down into a stream of many individual I/O requests,<br />each to a different block. With luck, the blocks are sequential or at<br />least physically close together. If the blocks are not near one<br />another, the disk head must move to another location on the disk. Moving<br />the disk head is called seeking, and it is one of the most expensive<br />operations in a computer. The seek time on modern hard drives is measured<br />in the tens of milliseconds. This<br />is one reason why defragmented files are a good thing.<br /></p><p><br />Unfortunately, it does not matter if the files are defragmented because<br />the system is generating I/O requests for multiple files, all over the<br />disk. The e-mail client wants a little from here and the Web server wants<br />a little from there—but wait, now the text editor wants to read a<br />file. The net effect is that the disk head is made to jump around the<br />disk. In a worst-case scenario, with interleaved I/O requests to multiple<br />files, the head can spend all of its time jumping around from<br />one location to another—not a good thing for overall system performance.<br /></p><p><br />This is where the I/O scheduler comes in. The I/O scheduler schedules<br />the pending I/O requests in order to minimize the time spent moving the<br />disk head. This, in turn, minimizes disk seek time and maximizes hard<br />disk throughput.<br /></p><p><br />This magic is accomplished through two main actions, sorting<br />and merging. First, the I/O scheduler keeps the list of pending<br />I/O requests sorted by block number. When a new I/O request is issued,<br />it is inserted, block-wise, into the list of pending requests. This<br />prevents the drive head from seeking all around the disk to service I/O<br />requests. Instead, by keeping the list sorted, the disk head moves in<br />a straight line around the disk. If the hard drive is busy servicing<br />a request at one part of the disk, and a new request comes in to the<br />same part of the disk, that request can be serviced before moving off<br />to other parts of the disk.<br /></p><p><br />Merging occurs when an I/O request is issued to an identical or adjacent<br />region of the disk. Instead of issuing the new request on its own, it<br />is merged into the identical or adjacent request. This minimizes<br />the number of outstanding requests.<br /><br /></p><p><br />Let's look at an example. Consider the case where two applications issue requests<br />to the following block numbers, such that they arrived in the kernel in<br />this order: 10, 500, 12, 502, 14, 504 and 12. The I/O scheduler-less<br />approach would service these blocks in the given order. That is seven<br />long seeks, back and forth between two parts of the disk. What a waste!<br />If the kernel sorted and merged these requests, however, and serviced<br />them in that order, the results would be much different: 10, 12, 14, 500,<br />502 and 504. Only a single far-off seek and one less request overall.<br /></p><p><br />In this manner, an I/O scheduler virtualizes the resources of<br />disk I/O among multiple I/O requests in order to maximize global<br />throughput. Because I/O throughput is so crucial to system performance<br />and because seek time is so horribly slow, the job of an I/O scheduler<br />is important.<br /></p></div><div class="simplesect" lang="en"><div class="titlepage"><a name="N0xa50890.0xb45148"></a><br />The Linus Elevator</div><p><br />The I/O scheduler found in the 2.4 Linux kernel is named the Linus<br />Elevator. I/O schedulers often are called elevator algorithms,<br />because they tackle a problem similar to that of keeping an elevator<br />moving smoothly in a large building. The Linus Elevator functions almost<br />exactly like the classic I/O scheduler described above. For the most part,<br />this was great because simplicity is a good thing and the 2.4 kernel's<br />I/O scheduler just worked. Unfortunately, in the I/O scheduler's quest<br />to maximize global I/O throughput, a trade-off was made: local<br />fairness—in particular, request latency—can go easily out the window. Let's<br />look at an example.<br /></p><p><br />Consider a stream of requests to logical disk blocks such as 20, 30,<br />700 and 25. The I/O scheduler's sorting algorithm would queue and issue<br />the requests in the following order (assuming the disk head currently<br />is at the logical start of the disk): 20, 25, 30 and 700. This is expected<br />and indeed correct. Assume, however, that halfway through servicing<br />the request to block 25, another request comes in to the same part of<br />the disk. And then another. And yet another. It is entirely feasible<br />that the request way over to block 700 is not serviced for a relatively<br />long time.<br /></p><p><br />Worse, what if the request was to read a disk block? Read requests<br />generally are synchronous. When an application issues a request to<br />read some data, it typically blocks and waits until the kernel<br />returns the data. The application must sit and wait, twiddling<br />its thumbs, until that request way over at block 700 finally<br />is serviced. Writes, on the other hand, typically are not<br />synchronous—they<br />are asynchronous. When an application issues a write, the kernel<br />copies the data and metadata into the kernel, prepares a buffer to hold<br />the data and returns to the application. The application does not really<br />care or even know when the data actually hits the disk.<br /></p><p><br />It gets worse for our friend the read request, however. Because writes<br />are asynchronous, writes tend to stream. That is, it is common<br />for a large writeback of a lot of data to occur. This implies that many<br />individual write requests are submitted to a close area of the hard<br />disk. As an example, consider saving a large file. The application dumps<br />write requests on the system and hard drive as fast as it is scheduled.<br /><br /></p><p><br />Read requests, conversely, usually do not stream. Instead, applications<br />submit read requests in small one-by-one chunks, with each chunk dependent<br />on the last. Consider reading all of the files in a directory. The<br />application opens the first file, issues a read request for a suitable<br />chunk of the file, waits for the returned data, issues a read request for<br />the next chunk, waits and continues likewise until the entire file is<br />read. Then the file is closed, the next file is opened and the process<br />repeats. Each subsequent request has to wait for the previous,<br />which means substantial delays to this application if the requests are to<br />far-off disk blocks. The phenomenon of streaming write requests starving<br />dependent read requests is called writes-starving-reads (see Sidebar<br />“Test 1. Writes-Starving-Reads”).<br /></p></div><div class="simplesect" lang="en"><div class="titlepage"><a name="N0xa50890.0xb45408"></a></div><div class="sidebar"><p class="title"><b>Test 1. Writes-Starving-Reads</b></p><p><br />In the background, perform a streaming write, such as:<br /><br /><br /><pre class="programlisting"><br />while true<br />do<br /> dd if=/dev/zero of=file bs=1M<br />done<br /></pre><br /></p><p><br />Meanwhile, time how long a simple read of a 200MB file takes:<br /><br /><pre class="programlisting"><br />time cat 200mb-file > /dev/null<br /></pre><br /></p><p><br />This test demonstrates the writes-starving-reads problem.<br /><br /></p></div><p><br />The possibility of not servicing some requests in a reasonable amount<br />of time is called starvation. Request starvation results in<br />unfairness. In the case of I/O schedulers, the system explicitly<br />has decided to trade fairness for improved global throughput. That is,<br />the system attempts to improve the overall performance of the system<br />at the possible expense of any one specific I/O request. This is<br />accepted and, indeed, desired—except that prolonged starvation is<br />bad. Starving read requests for even moderate lengths of time results in<br />high application latency for applications issuing read requests during<br />other disk activity. This high read latency adversely affects<br />system performance and feel (see Sidebar “Test 2. Effects of High<br />Read Latency”).<br /></p></div><div class="simplesect" lang="en"><div class="titlepage"><a name="N0xa50890.0xb45828"></a></div><div class="sidebar"><p class="title"><b><br />Test 2. Effects of High Read Latency</b></p><p><br />Start a streaming read in the background:<br /><br /><pre class="programlisting"><br />while true<br />do<br /> cat big-file > /dev/null<br />done<br /></pre><br /></p><p><br />Meanwhile, measure how long it takes for a read of every file in the kernel<br />source tree to complete:<br /><br /><pre class="programlisting"><br />time find . -type f -exec cat '{}' ';' > /dev/null<br /><br /></pre><br /></p><p><br />This measures the performance of a series of small dependent reads during a<br />large streaming read.<br /></p></div></div><div class="simplesect" lang="en"><div class="titlepage"><a name="N0xa50890.0xb45b98"></a><br />The Deadline I/O Scheduler</div><p><br />Preventing the starvation of requests in general, and read requests in<br />particular, was a goal of the new 2.6 I/O schedulers.<br /></p><p><br />The Deadline I/O Scheduler was introduced to solve the starvation issue<br />surrounding the 2.4 I/O scheduler and traditional elevator algorithms<br />in general. As discussed, the Linus Elevator maintains the sorted list<br />of pending I/O requests in a single queue. The I/O request at the head of<br />the queue is the next one to be serviced. The Deadline I/O Scheduler continues to<br />keep this queue, but kicks things up a notch by introducing two additional<br />queues—the read FIFO queue and the write FIFO queue. The<br />Deadline I/O Scheduler keeps the items in each of these queues sorted by<br />submission time (effectively, first in is first out). The read FIFO<br />queue, as its name suggests, contains only read requests. The write FIFO<br />queue, likewise, contains only write requests. Each FIFO queue is assigned<br />an expiration value. The read FIFO queue has an expiration time<br />of 500 milliseconds. The write FIFO queue has an expiration time of five seconds.<br /></p><p><br />When a new I/O request is submitted, it is insertion-sorted into the<br />standard queue and placed at the tail of its respective (either read<br />or write) FIFO queue. Normally, the hard drive is sent I/O requests from<br />the head of the standard sorted queue. This maximizes global throughput<br />by minimizing seeks, as the normal queue is sorted by block number,<br />as with the Linus Elevator.<br /></p><p><br />When the item at the head of one of the FIFO queues, however, grows<br />older than the expiration value associated with its queue, the I/O<br />scheduler stops dispatching I/O requests from the standard queue.<br />Instead, it services the I/O request at the head of the FIFO queue, plus a<br />couple extra for good measure. The I/O scheduler needs to check and<br />handle only the requests at the head of the FIFO queues, as those are the<br />oldest requests in the queue.<br /></p><p><br />Remember our old friend, the request to block 700? Despite the flood of<br />write requests to the faraway blocks, after 500 milliseconds the Deadline<br />I/O Scheduler would stop servicing those requests and service the read<br />over at block 700. The disk would seek to block 700, service the read<br />request and then continue servicing the other outstanding requests.<br /></p><p><br /><br />In this manner, the Deadline I/O Scheduler can enforce a soft deadline on<br />I/O requests. Although it makes no promise that an I/O request is serviced<br />before the expiration time, the I/O scheduler generally services requests<br />near their expiration times. Thus, the Deadline I/O Scheduler continues<br />to provide good global throughput without starving any one request for<br />an unacceptably long time. Because read requests are given short<br />expiration times, the writes-starving-reads problem is minimized.<br /></p></div><div class="simplesect" lang="en"><div class="titlepage"><a name="N0xa50890.0xb45eb0"></a><br />Anticipatory I/O Scheduler</div><p><br />This is all well and good, but it's not a perfect solution. Consider what<br />happens with our fictional request to block 700, which presumably is the<br />first of many dependent reads to that area of the disk. After servicing<br />the read request, the Deadline I/O Scheduler continues servicing the<br />write requests to the earlier blocks. This is fine, until the reading<br />application submits its next read request (say, to block 710). In 500<br />milliseconds, that request expires and the disk seeks over<br />to block 710, services the request, seeks back to where it was before<br />and continues servicing the streaming write. And then another read<br />arrives.<br /></p><p><br />The problem again stems from those darn dependent reads. Because reads<br />are issued in dependent chunks, the application issues the next read<br />only when the previous is returned. But by the time the application<br />receives the read data, is scheduled to run and submits the next read,<br />the I/O scheduler has moved on and begun servicing some<br />other requests. This results in a wasted pair of seeks for each read:<br />seek to the read, service it and seek back. If only there was some way<br />for the I/O scheduler to know—nay, to anticipate—that another<br />read would soon be submitted to the same part of the disk. Instead<br />of seeking back and forth, it could wait in anticipation for the next<br />read. Saving those awful seeks certainly is worth a few milliseconds of<br />waiting; we save two seeks.<br /></p><p><br />This is, of course, exactly what the Anticipatory I/O Scheduler<br />does. It began as the Deadline I/O Scheduler; it implements the<br />same deadline-based scheduling. But it was gifted with the addition<br />of an anticipation mechanism. When a read request is submitted,<br />the Anticipatory I/O Scheduler services it within its deadline, as<br />usual. Unlike the Deadline I/O Scheduler, however, the Anticipatory<br />I/O Scheduler then sits and waits, doing nothing, for up to six<br />milliseconds. Chances are good that the<br />application will issue another read to the same part of the filesystem<br />during those six milliseconds. If<br />so, that request is serviced immediately, and the Anticipatory I/O<br />Scheduler waits some more. If six milliseconds go by without a read<br />request, the Anticipatory I/O Scheduler guessed wrong and returns to<br />whatever it was doing before.<br /></p><p><br />If even a moderate number of requests are anticipated correctly, a great<br />deal of time (two expensive seeks, each) is saved (Table 1). Because most reads are<br />dependent, the anticipation pays off most of the time. To further improve<br />the odds of a correct anticipation, the Anticipatory I/O Scheduler uses a<br />heuristic to better guess for which processes to wait. To<br />this end, the scheduler maintains I/O statistics about each process to<br />keep track of its behavior. Because of these statistics and intelligent<br />heuristics, the Anticipatory I/O Scheduler correctly anticipates the<br />actions of applications a sufficiently large amount of the time to be<br />well worth the overhead.<br /></p><div class="table"><a name="N0xa50890.0xb460c0"></a><p class="title"><b><br />Table 1. The Results</b></p><table summary=" Table 1. The Results6931t1.qrk" border="1"><colgroup><col><col><col></colgroup><thead><tr><th>I/O Scheduler and Kernel</th><th>Test 1</th><th>Test 2</th></tr></thead><tbody><tr><td>Linus Elevator on 2.4</td><td>45 seconds</td><td>30 minutes, 28 seconds</td></tr><tr><td>Deadline I/O Scheduler on 2.6</td><td>40 seconds</td><td>3 minutes, 30 seconds</td></tr><tr><td>Anticipatory I/O Scheduler on 2.6</td><td>4.6 seconds</td><td>15 seconds</td></tr></tbody></table></div><p><br /><br />By minimizing unneeded seeks and more quickly servicing read requests,<br />in many workloads the Anticipatory I/O Scheduler provides both improved<br />request latency and global throughput over the Deadline I/O Scheduler<br />and the Linus Elevator. Unsurprisingly, the Anticipatory I/O Scheduler<br />is the default I/O scheduler in the 2.6 kernel. And rightly so, it rocks.<br /></p></div><div class="simplesect" lang="en"><div class="titlepage"><a name="N0xa50890.0xb3d1f8"></a><br />Acknowledgement</div><p><br />Andrea Arcangeli and Jens Axboe are the primary authors of the<br />Linus Elevator. Jens Axboe is the primary author of the Deadline I/O<br />Scheduler. Nick Piggin is the primary author of the Anticipatory I/O<br />Scheduler.<br /></p></div></div><br /><div class="authorblurb"><p><br />Robert Love (<a href="mailto:rml@tech9.net">rml@tech9.net</a>) is a kernel hacker at MontaVista Software<br />and a student at the University of Florida. He is the author of <span class="emphasis"><em>Linux<br />Kernel Development</em></span>. Robert loves O.A.R. and lives in Gainesville,<br />Florida.<br /><br /></p></div>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-1190232755347143052009-01-13T02:00:00.000-08:002009-01-13T03:03:35.569-08:00Gnu Makefile by example<pre><code><br /><br />vendor/config/bfin/config.arch:<br /><br />.EXPORT_ALL_VARIABLES:<br /><br /># tells make to export all variables to child processes by default. make adds the variable and <br /># its value to the environment for running each command. The sub-make, in turn, uses the <br /># environment to initialize its table of variable values.<br /><br /><br />include $(ROOTDIR)/vendors/config/common/config.arch<br /><br />############################################################################<br />#<br /># The makefiles need to know how to do things in different contexts<br /># To save some pain we put it all here<br />#<br /># First settings we always want for all builds<br />#<br /><br />MACHINE = bfin # this is for uClibc<br />ARCH = blackfin # this is for the kernel<br />ENDIAN = little<br /><br />ifeq ($(CONFIG_FMT_USE_FDPIC_ELF),y)<br />CONFIGURE_HOST := bfin-linux-uclibc<br />CONFIGURE_SHARED_ENABLE := --enable-shared<br />CONFIGURE_SHARED_WITH := --with-shared<br />else<br />CONFIGURE_HOST := bfin-uclinux<br />CONFIGURE_SHARED_ENABLE := --disable-shared<br />CONFIGURE_SHARED_WITH := --without-shared<br />endif<br />CROSS_COMPILE := $(CONFIGURE_HOST)-<br />CROSS := $(CROSS_COMPILE)<br />KERNEL_CROSS_COMPILE := bfin-uclinux-<br /><br /># ":=" - Simple Expanded Variable. The value of a simply expanded variable is scanned once and for all, expanding any references to other variables and functions, when the variable is defined. This makes Makefile programing simple.<br /><br />CC = $(CROSS_COMPILE)gcc<br />AS = $(CROSS_COMPILE)as<br />CXX = $(CROSS_COMPILE)g++<br />AR = $(CROSS_COMPILE)ar<br />LD = $(CROSS_COMPILE)ld<br />NM = $(CROSS_COMPILE)nm<br />OBJCOPY = $(CROSS_COMPILE)objcopy<br />OBJDUMP = $(CROSS_COMPILE)objdump<br />RANLIB = $(CROSS_COMPILE)ranlib<br />ELF2FLT = $(CROSS_COMPILE)elf2flt<br />STRIPTOOL = $(CROSS_COMPILE)strip<br />STRIP = $(STRIPTOOL)<br />CC_FOR_BUILD = gcc<br />CONFIG_SITE = $(ROOTDIR)/vendors/config/config.site<br /><br />QMAKE = $(CROSS_COMPILE)qmake<br /><br />MKIMAGE = $(ROOTDIR)/$(LINUXDIR)/scripts/mkuboot.sh<br />MKFS_CRAMFS = $(ROOTDIR)/user/cramfs/host_build/mkcramfs<br />MKFS_EXT2 = $(ROOTDIR)/user/genext2fs/build-host/genext2fs<br />MKFS_JFFS2 = $(ROOTDIR)/user/mtd-utils/mkfs.jffs2<br />MTD_SUMTOOL = $(ROOTDIR)/user/mtd-utils/sumtool<br />MKFS_ROMFS = $(ROOTDIR)/user/genromfs/genromfs<br />MKFS_UBIFS = $(ROOTDIR)/user/mtd-utils/mkfs.ubifs<br />MKFS_YAFFS = $(ROOTDIR)/user/yaffs-utils/mkfs.yaffs<br />MKFS_YAFFS2 = $(ROOTDIR)/user/yaffs-utils/mkfs.yaffs2<br /><br />############################################################################<br />#<br /># Settings for configure / autotools<br />#<br /><br />CONFIGURE_BUILD := $(shell sh $(ROOTDIR)/tools/config.guess)<br /><br /># Here "shell" is a function - The shell function performs the same function that backquotes (``') perform in most shells: it does command expansion.<br /><br />CONFIGURE_OPTS := \<br /> --host=$(CONFIGURE_HOST) \<br /> --build=$(CONFIGURE_BUILD) \<br /> --prefix=/usr \<br /> --sysconfdir=/etc \<br /> --datadir=/usr/share \<br /> --mandir=/usr/share/man \<br /> --infodir=/usr/share/info \<br /> --localstatedir=/var/lib \<br /> --disable-dependency-tracking \<br /> --enable-fast-install<br />ifneq ($(findstring s,$(MAKEFLAGS)),)<br />CONFIGURE_OPTS += --quiet<br />endif<br /><br /># $(findstring find,text) - Locate find in text.<br /># MAKEFLAGS - The flags given to make. You can set this in the environment or a makefile to set flags.<br /># "-s" : silent, quiet<br /><br />cpu-$(CONFIG_BF512) := bf512<br />cpu-$(CONFIG_BF514) := bf514<br />cpu-$(CONFIG_BF516) := bf516<br />cpu-$(CONFIG_BF518) := bf518<br />cpu-$(CONFIG_BF522) := bf522<br />cpu-$(CONFIG_BF523) := bf523<br />cpu-$(CONFIG_BF524) := bf524<br />cpu-$(CONFIG_BF525) := bf525<br />cpu-$(CONFIG_BF526) := bf526<br />cpu-$(CONFIG_BF527) := bf527<br />cpu-$(CONFIG_BF531) := bf531<br />cpu-$(CONFIG_BF532) := bf532<br />cpu-$(CONFIG_BF533) := bf533<br />cpu-$(CONFIG_BF534) := bf534<br />cpu-$(CONFIG_BF536) := bf536<br />cpu-$(CONFIG_BF537) := bf537<br />cpu-$(CONFIG_BF538) := bf538<br />cpu-$(CONFIG_BF539) := bf539<br />cpu-$(CONFIG_BF542) := bf542<br />cpu-$(CONFIG_BF544) := bf544<br />cpu-$(CONFIG_BF547) := bf547<br />cpu-$(CONFIG_BF548) := bf548<br />cpu-$(CONFIG_BF549) := bf549<br />cpu-$(CONFIG_BF561) := bf561<br /><br />rev-$(CONFIG_BF_REV_0_0) := 0.0<br />rev-$(CONFIG_BF_REV_0_1) := 0.1<br />rev-$(CONFIG_BF_REV_0_2) := 0.2<br />rev-$(CONFIG_BF_REV_0_3) := 0.3<br />rev-$(CONFIG_BF_REV_0_4) := 0.4<br />rev-$(CONFIG_BF_REV_0_5) := 0.5<br />rev-$(CONFIG_BF_REV_0_6) := 0.6<br />rev-$(CONFIG_BF_REV_ANY) := any<br />rev-$(CONFIG_BF_REV_NONE) := none<br />ifeq ($(rev-y),)<br />$(warning )<br />$(warning The Blackfin Silicon Revision you are targetting is not known.)<br />$(warning Please file a bug report about this.)<br />$(warning )<br />rev-y := any<br />endif<br /><br />ifeq ($(cpu-y),)<br />$(warning )<br />$(warning The Blackfin CPU you are targetting is not known.)<br />$(warning Please file a bug report about this.)<br />$(warning )<br />else<br />CPUFLAGS = -mcpu=$(cpu-y)-$(rev-y)<br />endif<br /><br />############################################################################<br />#<br /># Set up all our fun CFLAGS/CPPFLAGS/LDFLAGS. Normalize our<br /># settings so we don't differentiate between user and lib.<br />#<br /><br />ifneq ($(UCLINUX_BUILD_USER)$(UCLINUX_BUILD_LIB),)<br /><br />CFLAGS-y := -pipe -Wall<br />CXXFLAGS-y := -pipe -Wall<br />CPPFLAGS-y := -DEMBED -D__uClinux__ -I$(ROOTDIR)<br />LDFLAGS-y := <br />FLTFLAGS-y := <br /><br />CONFIG_ALL_DEBUG := n<br />ifdef CONFIG_LIB_DEBUG<br /> CONFIG_ALL_DEBUG := y<br />endif<br />ifdef CONFIG_USER_DEBUG<br /> CONFIG_ALL_DEBUG := y<br />endif<br /><br />ifeq ($(CONFIG_ALL_DEBUG),y)<br /> CFLAGS-y += -O0 -g<br /> STRIPTOOL := echo<br /> STRIP := $(STRIPTOOL)<br />else<br /> CFLAGS-y += $(subst ",,$(strip $(CONFIG_USER_CFLAGS)))<br />endif<br /><br /># $(strip string) - Remove excess whitespace characters from string.<br /># $(subst from,to,text) - Replace from with to in text.<br /><br />CFLAGS-$(CONFIG_BLACKFIN_CHECK_STACKFLOW) += -mstack-check-l1<br />CFLAGS-$(CONFIG_BLACKFIN_CHECK_POINTER) += -fmudflap -lmudflap<br /><br />LDFLAGS-$(CONFIG_FMT_USE_FLAT) += -Wl,-elf2flt<br />LDFLAGS-$(CONFIG_FMT_USE_SHARED_FLAT) += -Wl,-elf2flt<br />LDFLAGS-$(CONFIG_FMT_USE_SEP_DATA) += -Wl,-elf2flt<br /><br />CFLAGS-$(CONFIG_FMT_USE_SEP_DATA) += -msep-data<br />LDFLAGS-$(CONFIG_FMT_USE_SEP_DATA) += -msep-data<br /><br />CFLAGS-$(CONFIG_FMT_USE_SHARED_FLAT) += -mid-shared-library<br />CFLAGS-$(CONFIG_FMT_USE_SEP_DATA) += -msep-data<br />LDFLAGS-$(CONFIG_FMT_USE_SHARED_FLAT) += -Wl,-shared-lib-id,0 -mid-shared-library<br />LDFLAGS-$(CONFIG_FMT_USE_SEP_DATA) += -Wl,-shared-lib-id,0 -msep-data<br /><br />#<br /># This will prevent building up of code in lib/ as shared libs.<br /># You will need to build/link those by hand anyways ...<br />#<br />CFLAGS-$(CONFIG_FMT_USE_SHARED_FLAT) += -mshared-library-id=0<br />FLAT_LIBC := $(shell $(CC) $(CPUFLAGS) -mid-shared-library -print-file-name=libc.gdb)<br />LDFLAGS-$(CONFIG_FMT_USE_SHARED_FLAT) += -Wl,-R,$(FLAT_LIBC)<br /><br />CFLAGS := $(CFLAGS-y) $(VENDOR_CFLAGS) $(CPUFLAGS)<br />CXXFLAGS := $(CXXFLAGS-y) $(VENDOR_CXXFLAGS) $(CPUFLAGS)<br />CPPFLAGS := $(CPPFLAGS-y) $(VENDOR_CPPFLAGS) $(CPUFLAGS)<br />LDFLAGS := $(LDFLAGS-y) $(VENDOR_LDFLAGS) $(CPUFLAGS)<br />FLTFLAGS := $(FLTFLAGS-y) $(VENDOR_FLTFLAGS)<br /><br />endif<br /><br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-88141522718842307102008-07-28T01:11:00.000-07:002008-07-28T01:12:51.399-07:00blackfin spi device driver<pre><code><br /><br />/********************** ADAM **************************************/<br /><br />The SPI master is registered as a platform devices, while SPI slave devices are registered<br />as devices in the SPI bus.<br /><br />SPI Bus<br />~~~~~~~<br />spi.c: spi_init()<br /> status = bus_register(&spi_bus_type);<br /> status = class_register(&spi_master_class);<br /><br />root:/sys/bus/spi> ls -lR<br />.:<br />drwxr-xr-x 2 root root 0 Jan 1 01:47 devices<br />drwxr-xr-x 3 root root 0 Jan 1 2007 drivers<br />-rw-r--r-- 1 root root 4096 Jan 1 01:47 drivers_autoprobe<br />--w------- 1 root root 4096 Jan 1 01:47 drivers_probe<br /><br />./devices:<br />lrwxrwxrwx 1 root root 0 Jan 1 01:47 spi0.1 -> ../../../devices/platform/bfin-spi.0/spi0.1<br /><br />./drivers:<br />drwxr-xr-x 2 root root 0 Jan 1 01:47 spidev<br /><br />./drivers/spidev:<br />--w------- 1 root root 4096 Jan 1 01:47 bind<br />lrwxrwxrwx 1 root root 0 Jan 1 01:47 spi0.1 -> ../../../../devices/platform/bfin-spi.0/spi0.1<br />--w------- 1 root root 4096 Jan 1 01:47 unbind<br /><br /><br /><br />Setup the master (SPI controller)<br />~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br /><br />The SPI master device is registered as a platform device:<br />// stamp.c:<br /><br />struct platform_device {<br /> const char *name;<br /> u32 id;<br /> struct device dev;<br /> u32 num_resources;<br /> struct resource *resource;<br />};<br /><br />//---------------------------------------------------------------<br />stamp.c:<br /><br />static struct resource bfin_spi0_resource[] = {<br /> [0] = {<br /> .start = SPI0_REGBASE,<br /> .end = SPI0_REGBASE + 0xFF,<br /> .flags = IORESOURCE_MEM,<br /> },<br /> [1] = {<br /> .start = CH_SPI,<br /> .end = CH_SPI,<br /> .flags = IORESOURCE_IRQ,<br /> }<br />};<br /><br />/* SPI controller data */<br />static struct bfin5xx_spi_master bfin_spi0_info = {<br /> .num_chipselect = 8,<br /> .enable_dma = 1, /* master has the ability to do dma transfer */<br /> .pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},<br />};<br /><br />static struct platform_device bfin_spi0_device = {<br /> .name = "bfin-spi",<br /> .id = 0, /* Bus number */<br /> .num_resources = ARRAY_SIZE(bfin_spi0_resource),<br /> .resource = bfin_spi0_resource,<br /> .dev = {<br /> .platform_data = &bfin_spi0_info, /* Passed to driver */<br /> },<br />};<br /><br />static int __init stamp_init(void) {<br /> platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));<br /><br />}<br />//-------------------------------------------------------------------------<br /><br />The driver for SPI master:<br /><br />static struct platform_driver bfin5xx_spi_driver = {<br /> .driver = {<br /> .name = DRV_NAME,<br /> .owner = THIS_MODULE,<br /> },<br /> .suspend = bfin5xx_spi_suspend,<br /> .resume = bfin5xx_spi_resume,<br /> .remove = __devexit_p(bfin5xx_spi_remove),<br />}<br /><br />/**<br /> * platform_driver_probe - register driver for non-hotpluggable device<br /> * @drv: platform driver structure<br /> * @probe: the driver probe routine, probably from an __init section<br /> *<br /> * Use this instead of platform_driver_register() when you know the device<br /> * is not hotpluggable and has already been registered, and you want to<br /> * remove its run-once probe() infrastructure from memory after the driver<br /> * has bound to the device.<br /> *<br /> * One typical use for this would be with drivers for controllers integrated<br /> * into system-on-chip processors, where the controller devices have been<br /> * configured as part of board setup.<br /> *<br /> * Returns zero if the driver registered and bound to a device, else returns<br /> * a negative error code and with the driver not registered.<br /> */<br />static int __init bfin5xx_spi_init(void)<br />{<br /> return platform_driver_probe(&bfin5xx_spi_driver, bfin5xx_spi_probe);<br />}<br /><br />------------------------------------------------------------------------------------------<br />Bind spi slave devices and spi driver.<br /><br />platform_probe()<br /> --> bfin_spi_probe() // spi_bf5xx.c<br /> --> spi_register_master() // spi.c<br /> --> scan_board_info() // for all the devices in the table defined in board.c (stamp.c)<br /> --> spi_new_device()<br /> --> master->setup() // set up the new device HW<br /> --> device_register()<br /><br />-----------------------------------------------------------------<br />This driver defines bellow routine for spi master device <br /> master->cleanup = cleanup;<br /> master->setup = setup;<br /> master->transfer = transfer;<br />------------------------------------------------------------------<br />Set up queues for transfer:<br />// spi_bf5xx.c<br />bfin_spi_probe() <br /> ---> init_queue()<br /> ---> tasklet_init(&drv_data->pump_transfers,<br /> pump_transfers, (unsigned long)drv_data);<br /> ---> INIT_WORK(&drv_data->pump_messages, pump_messages);<br /><br />root:/sys/devices/platform/bfin-spi.0> ls -lR<br />.:<br />lrwxrwxrwx 1 root root 0 Jan 1 01:48 bus -> ../../../bus/platform<br />lrwxrwxrwx 1 root root 0 Jan 1 01:48 driver -> ../../../bus/platform/drivers/bfin-spi<br />-r--r--r-- 1 root root 4096 Jan 1 01:48 modalias<br />drwxr-xr-x 2 root root 0 Jan 1 2007 power<br />drwxr-xr-x 3 root root 0 Jan 1 2007 spi0.1<br />lrwxrwxrwx 1 root root 0 Jan 1 01:48 spi_master:spi0 -> ../../../class/spi_master/spi0<br />lrwxrwxrwx 1 root root 0 Jan 1 01:48 subsystem -> ../../../bus/platform<br />-rw-r--r-- 1 root root 4096 Jan 1 01:48 uevent<br /><br />./power:<br />-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup<br /><br />./spi0.1:<br />lrwxrwxrwx 1 root root 0 Jan 1 01:49 bus -> ../../../../bus/spi<br />lrwxrwxrwx 1 root root 0 Jan 1 01:49 driver -> ../../../../bus/spi/drivers/spidev<br />-r--r--r-- 1 root root 4096 Jan 1 01:49 modalias<br />drwxr-xr-x 2 root root 0 Jan 1 2007 power<br />lrwxrwxrwx 1 root root 0 Jan 1 01:49 spidev:spidev0.1 -> ../../../../class/spidev/spidev0.1<br />lrwxrwxrwx 1 root root 0 Jan 1 01:49 subsystem -> ../../../../bus/spi<br />-rw-r--r-- 1 root root 4096 Jan 1 01:49 uevent<br /><br />./spi0.1/power:<br />-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup<br /><br /><br /><br />For a SPI slave driver:<br />~~~~~~~~~~~~~~~~~<br /><br /> * This represents the kind of device driver that uses SPI messages to<br /> * interact with the hardware at the other end of a SPI link. It's called<br /> * a "protocol" driver because it works through messages rather than talking<br /> * directly to SPI hardware (which is what the underlying SPI controller<br /> * driver does to pass those messages). These protocols are defined in the<br /> * specification for the device(s) supported by the driver.<br /> *<br /> * As a rule, those device protocols represent the lowest level interface<br /> * supported by a driver, and it will support upper level interfaces too.<br /> * Examples of such upper levels include frameworks like MTD, networking,<br /> * MMC, RTC, filesystem character device nodes, and hardware monitoring.<br /><br />struct spi_driver {<br /> int (*probe)(struct spi_device *spi);<br /> int (*remove)(struct spi_device *spi);<br /> void (*shutdown)(struct spi_device *spi);<br /> int (*suspend)(struct spi_device *spi, pm_message_t mesg);<br /> int (*resume)(struct spi_device *spi);<br /> struct device_driver driver;<br />};<br /><br />static struct spi_driver bfin_spi_adc_driver = {<br /> .driver = {<br /> .name = "bfin_spi_adc",<br /> .bus = &spi_bus_type,<br /> .owner = THIS_MODULE,<br /> },<br /> .probe = bfin_spi_adc_probe,<br /> .remove = __devexit_p(bfin_spi_adc_remove),<br />};<br /><br /><br />spi_register_driver(&bfin_spi_adc_driver);<br /><br /><br />struct bfin_spi_adc {<br /> int opened;<br /> unsigned short *buffer;<br /> int hz;<br /> int cont;<br /> struct spi_device *spidev;<br /> dma_addr_t dma_handle;<br />};<br /><br />struct bfin_spi_adc spi_adc;<br /><br /><br />struct spi_device {<br /> struct device dev;<br /> struct spi_master *master;<br /> u32 max_speed_hz;<br /> u8 chip_select;<br /> u8 mode;<br />#define SPI_CPHA 0x01 /* clock phase */<br />#define SPI_CPOL 0x02 /* clock polarity */<br />#define SPI_MODE_0 (0|0) /* (original MicroWire) */<br />#define SPI_MODE_1 (0|SPI_CPHA)<br />#define SPI_MODE_2 (SPI_CPOL|0)<br />#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)<br />#define SPI_CS_HIGH 0x04 /* chipselect active high? */<br />#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */<br />#define SPI_3WIRE 0x10 /* SI/SO signals shared */<br />#define SPI_LOOP 0x20 /* loopback mode */<br /> u8 bits_per_word;<br /> int irq;<br /> void *controller_state;<br /> void *controller_data;<br /> const char *modalias;<br />};<br /><br /><br />root:/sys/bus/spi/drivers/spidev> ls -lR<br />.:<br />--w------- 1 root root 4096 Jan 1 01:47 bind<br />lrwxrwxrwx 1 root root 0 Jan 1 01:47 spi0.1 -> ../../../../devices/platform/bfin-spi.0/spi0.1<br />--w------- 1 root root 4096 Jan 1 01:47 unbind<br /><br />root:/sys/devices/platform/bfin-spi.0> ls -lR<br />.:<br />lrwxrwxrwx 1 root root 0 Jan 1 01:48 bus -> ../../../bus/platform<br />lrwxrwxrwx 1 root root 0 Jan 1 01:48 driver -> ../../../bus/platform/drivers/bfin-spi<br />-r--r--r-- 1 root root 4096 Jan 1 01:48 modalias<br />drwxr-xr-x 2 root root 0 Jan 1 01:49 power<br />drwxr-xr-x 3 root root 0 Jan 1 01:49 spi0.1<br />lrwxrwxrwx 1 root root 0 Jan 1 01:48 spi_master:spi0 -> ../../../class/spi_master/spi0<br />lrwxrwxrwx 1 root root 0 Jan 1 01:48 subsystem -> ../../../bus/platform<br />-rw-r--r-- 1 root root 4096 Jan 1 01:48 uevent<br /><br />./power:<br />-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup<br /><br />./spi0.1:<br />lrwxrwxrwx 1 root root 0 Jan 1 01:49 bus -> ../../../../bus/spi<br />lrwxrwxrwx 1 root root 0 Jan 1 01:49 driver -> ../../../../bus/spi/drivers/spidev<br />-r--r--r-- 1 root root 4096 Jan 1 01:49 modalias<br />drwxr-xr-x 2 root root 0 Jan 1 01:49 power<br />lrwxrwxrwx 1 root root 0 Jan 1 01:49 spidev:spidev0.1 -> ../../../../class/spidev/spidev0.1<br />lrwxrwxrwx 1 root root 0 Jan 1 01:49 subsystem -> ../../../../bus/spi<br />-rw-r--r-- 1 root root 4096 Jan 1 01:49 uevent<br /><br />./spi0.1/power:<br />-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup<br /><br />-------------------------------------------------<br />Bind the SPI protocol driver to SPI device:<br /><br />1. In driver init: calls spi_register_driver() --> driver_register()<br /><br />2. when device_register() is called, the "Driver Core" will search the list of drivers,<br />and check whether the device "match" with a driver.<br /><br />3. when driver_register() get called, the "Driver Core" will also scan existing devices<br /><br /><br /><br />To send a message:<br />~~~~~~~~~~~~~~~~~<br /><br />spi_sync() // spi.c<br /> --> spi_async();<br /> --> master->transfer(); // spi_bf5xx.c<br /> --> queue_work(drv_data->workqueue, &drv_data->pump_messages);<br /> --> pump_messages()<br /> --> tasklet_schedule(&drv_data->pump_transfers) //activate the tasklet<br /> --> pump_taskfer()<br /> --> wait_for_completion(&done)<br /><br /><br />miscellaneous device<br />~~~~~~~~~~~~~~~~~~~~~<br />Misc (or miscellaneous) drivers are simple char drivers that share certain common characteristics. The kernel<br />abstracts these commonalities into an API (implemented in drivers/char/misc.c), and this simplifies the way<br />these drivers are initialized. All misc devices are assigned a major number of 10, but each can choose a single<br />minor number. So, if a char driver needs to drive multiple devices as in the CMOS example discussed earlier, it's<br />probably not a candidate for being a misc driver.<br /><br /><br /><br />Platform devices<br />~~~~~~~~~~~~~~~~<br />Platform devices are devices that typically appear as autonomous<br />entities in the system. This includes legacy port-based devices and<br />host bridges to peripheral buses, and most controllers integrated<br />into system-on-chip platforms. What they usually have in common<br />is direct addressing from a CPU bus. Rarely, a platform_device will<br />be connected through a segment of some other kind of bus; but its<br />registers will still be directly addressable.<br /><br />Platform devices are given a name, used in driver binding, and a<br />list of resources such as addresses and IRQs.<br /><br /><br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-71235909794661489942008-07-02T02:51:00.000-07:002008-07-02T02:53:17.084-07:00blackfin serial driver<pre> <code><br />/* <br />Adam: Blackfin Serial Driver <br /><br />UART and RS232:<br /><br />http://www.freebsd.org/doc/en/articles/serial-uart/index.html#UART<br /><br />UART: Universal Asynchronous Receiver/Transmitter<br /><br />Asynchronous transmission allows data to be transmitted without the sender having to send a clock signal to the receiver. Instead, the sender and receiver must agree on timing parameters in advance and special bits are added to each word which are used to synchronize the sending and receiving units.<br /><br />When a word is given to the UART for Asynchronous transmissions, a bit called the "Start Bit" is added to the beginning of each word that is to be transmitted. The Start Bit is used to alert the receiver that a word of data is about to be sent, and to force the clock in the receiver into synchronization with the clock in the transmitter. These two clocks must be accurate enough to not have the frequency drift by more than 10% during the transmission of the remaining bits in the word. (This requirement was set in the days of mechanical teleprinters and is easily met by modern electronic equipment.)<br /><br />After the Start Bit, the individual bits of the word of data are sent, with the Least Significant Bit (LSB) being sent first. Each bit in the transmission is transmitted for exactly the same amount of time as all of the other bits, and the receiver “looks” at the wire at approximately halfway through the period assigned to each bit to determine if the bit is a 1 or a 0. For example, if it takes two seconds to send each bit, the receiver will examine the signal to determine if it is a 1 or a 0 after one second has passed, then it will wait two seconds and then examine the value of the next bit, and so on.<br /><br />The sender does not know when the receiver has “looked” at the value of the bit. The sender only knows when the clock says to begin transmitting the next bit of the word.<br /><br />When the entire data word has been sent, the transmitter may add a Parity Bit that the transmitter generates. The Parity Bit may be used by the receiver to perform simple error checking. Then at least one Stop Bit is sent by the transmitter.<br /><br />When the receiver has received all of the bits in the data word, it may check for the Parity Bits (both sender and receiver must agree on whether a Parity Bit is to be used), and then the receiver looks for a Stop Bit. If the Stop Bit does not appear when it is supposed to, the UART considers the entire word to be garbled and will report a Framing Error to the host processor when the data word is read. The usual cause of a Framing Error is that the sender and receiver clocks were not running at the same speed, or that the signal was interrupted.<br /><br />Regardless of whether the data was received correctly or not, the UART automatically discards the Start, Parity and Stop bits. If the sender and receiver are configured identically, these bits are not passed to the host.<br /><br />If another word is ready for transmission, the Start Bit for the new word can be sent as soon as the Stop Bit for the previous word has been sent.<br /><br />Because asynchronous data is “self synchronizing”, if there is no data to transmit, the transmission line can be idle.<br /><br />RS232: pins, voltage, etc.<br /><br />*/<br /><br />/*<br />Adam: What do we have in this driver:<br /><br />1. Implements functions for linux "serial-core" interface, this include:<br />static struct uart_ops bfin_serial_pops = {<br /> .tx_empty = bfin_serial_tx_empty,<br /> .set_mctrl = bfin_serial_set_mctrl,<br /> .get_mctrl = bfin_serial_get_mctrl,<br /> .stop_tx = bfin_serial_stop_tx,<br /> .start_tx = bfin_serial_start_tx,<br /> .stop_rx = bfin_serial_stop_rx,<br /> .enable_ms = bfin_serial_enable_ms,<br /> .break_ctl = bfin_serial_break_ctl,<br /> .startup = bfin_serial_startup,<br /> .shutdown = bfin_serial_shutdown,<br /> .set_termios = bfin_serial_set_termios,<br /> .type = bfin_serial_type,<br /> .release_port = bfin_serial_release_port,<br /> .request_port = bfin_serial_request_port,<br /> .config_port = bfin_serial_config_port,<br /> .verify_port = bfin_serial_verify_port,<br />};<br /><br />For definition of these functions, see: Document/serial/driver<br /><br />This makes up a serial driver:<br /><br />/dev/ttyBFx -> tty-core -> (line discipline if any) -> serial-core -> bfin_driver<br /><br />2. Implements functions for serial console, used by printk():<br /><br />static struct console bfin_serial_console = {<br /> .name = BFIN_SERIAL_NAME,<br /> .write = bfin_serial_console_write,<br /> .device = uart_console_device,<br /> .setup = bfin_serial_console_setup,<br /> .flags = CON_PRINTBUFFER,<br /> .index = -1,<br /> .data = &bfin_serial_reg,<br />};<br /><br />This would define a console driver.<br /><br />System Console: The system console is the device which receives all kernel messages <br /> and warnings and which allows logins in single user mode. <br /><br />Virtual Terminals: support for terminal devices with display and keyboard devices.<br /> These are called "virtual" because you can run several virtual<br /> terminals (also called virtual consoles) on one physical terminal.<br /><br />1) /dev/console - system console implemented in drivers/char/vt.c<br />2) /dev/tty0 - virtual terminal - drivers/char/vt.c<br />Virtual Terminals (CONFIG_VT)<br /> - CONFIG_VT_CONSOLE: System console on VT<br /> VT requires a HW specific driver for output:<br /> - CONFIG_VGA_CONSOLE<br /> - CONFIG_FRAMEBUFFER_CONSOLE<br /> - CONFIG_DUMMY_CONSOLE<br /><br />Console drivers lie in two tiers: a top level constituting drivers such as the virtual terminal driver,<br />the printer console driver,, and bottom-level drivers that are responsible for advanced operations. <br />Consequently, there are two main interface definition structures<br />used by console drivers. Top-level console drivers revolve around struct console, which defines basic<br />operations such as setup() and write(). Bottom-level drivers center on struct consw that specifies advanced<br />operations such as setting cursor properties, console switching, blanking, resizing, and setting palette<br />information. These structures are defined in include/linux/console.h.<br /><br />Bottom Console driver: <br /> - CONFIG_VGA_CONSOLE<br /> - CONFIG_FRAMEBUFFER_CONSOLE<br /> - CONFIG_DUMMY_CONSOLE<br />e.g, the fb_con.c:<br />static const struct consw fb_con = {<br /> .owner = THIS_MODULE,<br /> .con_startup = fbcon_startup,<br /> .con_init = fbcon_init,<br /> .con_deinit = fbcon_deinit,<br /> .con_clear = fbcon_clear,<br /> .con_putc = fbcon_putc,<br /> .con_putcs = fbcon_putcs,<br /> .con_cursor = fbcon_cursor,<br /> .con_scroll = fbcon_scroll,<br /> .con_bmove = fbcon_bmove,<br /> .con_switch = fbcon_switch,<br /> .con_blank = fbcon_blank,<br /> .con_font_set = fbcon_set_font,<br /> .con_font_get = fbcon_get_font,<br /> .con_font_default = fbcon_set_def_font,<br /> .con_font_copy = fbcon_copy_font,<br /> .con_set_palette = fbcon_set_palette,<br /> .con_scrolldelta = fbcon_scrolldelta,<br /> .con_set_origin = fbcon_set_origin,<br /> .con_invert_region = fbcon_invert_region,<br /> .con_screen_pos = fbcon_screen_pos,<br /> .con_getxy = fbcon_getxy,<br /> .con_resize = fbcon_resize,<br />};<br /><br />Top console driver (printer driver) - devices that want to capture printk.<br />CONFIG_SERIAL_*_CONSOLE<br />CONFIG_LP_CONSOLE<br />CONFIG_NETCONSOLE<br /><br />Early printk is a console driver.<br /><br />3. Implements bfin earlyprintk functions:<br />static struct __init console bfin_early_serial_console = {<br /> .name = "early_BFuart",<br /> .write = early_serial_write,<br /> .device = uart_console_device,<br /> .flags = CON_PRINTBUFFER,<br /> .setup = bfin_serial_console_setup,<br /> .index = -1,<br /> .data = &bfin_serial_reg,<br />}<br /><br />4. Each file (*.c) may implements several drivers:<br /><br />*/<br /><br /><br />/*<br /> * Blackfin On-Chip Serial Driver<br /> *<br /> * Copyright 2006-2007 Analog Devices Inc.<br /> *<br /> * Enter bugs at http://blackfin.uclinux.org/<br /> *<br /> * Licensed under the GPL-2 or later.<br /> */<br /><br />#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)<br />#define SUPPORT_SYSRQ<br />#endif<br /><br />#include <linux/module.h><br />#include <linux/ioport.h><br />#include <linux/init.h><br />#include <linux/console.h><br />#include <linux/sysrq.h><br />#include <linux/platform_device.h><br />#include <linux/tty.h><br />#include <linux/tty_flip.h><br />#include <linux/serial_core.h><br /><br />#ifdef CONFIG_KGDB_UART<br />#include <linux/kgdb.h><br />#include <asm/irq_regs.h><br />#endif<br /><br />#include <asm/gpio.h><br />#include <asm/mach/bfin_serial_5xx.h><br /><br />#ifdef CONFIG_SERIAL_BFIN_DMA<br />#include <linux/dma-mapping.h><br />#include <asm/io.h><br />#include <asm/irq.h><br />#include <asm/cacheflush.h><br />#endif<br /><br />/* UART name and device definitions */<br /><br />#define BFIN_SERIAL_NAME "ttyBF"<br />#define BFIN_SERIAL_MAJOR 204<br />#define BFIN_SERIAL_MINOR 64<br /><br />/*<br /> * Setup for console. Argument comes from the menuconfig<br /> */<br />#define DMA_RX_XCOUNT 512<br />#define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT)<br /><br />#define DMA_RX_FLUSH_JIFFIES (HZ / 50)<br />#define CTS_CHECK_JIFFIES (HZ / 50)<br /><br />#ifdef CONFIG_SERIAL_BFIN_DMA<br />static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);<br />#else<br />static void bfin_serial_tx_chars(struct bfin_serial_port *uart);<br />#endif<br /><br />static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);<br /><br />/*<br /> * interrupts are disabled on entry<br /> */<br />static void bfin_serial_stop_tx(struct uart_port *port)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /> struct circ_buf *xmit = &uart->port.info->xmit;<br />#if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA)<br /> unsigned short ier;<br />#endif<br /><br />#ifdef CONFIG_SERIAL_BFIN_DMA<br /> disable_dma(uart->tx_dma_channel);<br /> xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);<br /> uart->port.icount.tx += uart->tx_count;<br /> uart->tx_count = 0;<br /> uart->tx_done = 1;<br />#else<br />#ifdef CONFIG_BF54x<br /> /* Clear TFI bit */<br /> UART_PUT_LSR(uart, TFI);<br /> UART_CLEAR_IER(uart, ETBEI);<br />#else<br /> ier = UART_GET_IER(uart);<br /> ier &= ~ETBEI;<br /> UART_PUT_IER(uart, ier);<br />#endif<br />#endif<br />}<br /><br />/*<br /> * port is locked and interrupts are disabled<br /> */<br />static void bfin_serial_start_tx(struct uart_port *port)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /><br />#ifdef CONFIG_SERIAL_BFIN_DMA<br /> if (uart->tx_done)<br /> bfin_serial_dma_tx_chars(uart);<br />#else<br />#ifdef CONFIG_BF54x<br /> UART_SET_IER(uart, ETBEI);<br />#else<br /> unsigned short ier;<br /> ier = UART_GET_IER(uart);<br /> ier |= ETBEI;<br /> UART_PUT_IER(uart, ier);<br />#endif<br /> bfin_serial_tx_chars(uart);<br />#endif<br />}<br /><br />/*<br /> * Interrupts are enabled<br /> */<br />static void bfin_serial_stop_rx(struct uart_port *port)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br />#ifdef CONFIG_KGDB_UART<br /> if (uart->port.line != CONFIG_KGDB_UART_PORT) {<br />#endif<br />#ifdef CONFIG_BF54x<br /> UART_CLEAR_IER(uart, ERBFI);<br />#else<br /> unsigned short ier;<br /><br /> ier = UART_GET_IER(uart);<br /> ier &= ~ERBFI;<br /> UART_PUT_IER(uart, ier);<br />#endif<br />#ifdef CONFIG_KGDB_UART<br /> }<br />#endif<br />}<br /><br />/*<br /> * Set the modem control timer to fire immediately.<br /> */<br />static void bfin_serial_enable_ms(struct uart_port *port)<br />{<br />}<br /><br />#ifdef CONFIG_KGDB_UART<br />static int kgdb_entry_state;<br /><br />void kgdb_put_debug_char(int chr)<br />{<br /> struct bfin_serial_port *uart;<br /> <br /> if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)<br /> uart = &bfin_serial_ports[0];<br /> else<br /> uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];<br /> <br /> while (!(UART_GET_LSR(uart) & THRE)) {<br /> SSYNC();<br /> }<br /><br />#ifndef CONFIG_BF54x<br /> UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));<br /> SSYNC();<br />#endif<br /> UART_PUT_CHAR(uart, (unsigned char)chr);<br /> SSYNC();<br />}<br /><br />int kgdb_get_debug_char(void)<br />{<br /> struct bfin_serial_port *uart;<br /> unsigned char chr;<br /><br /> if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)<br /> uart = &bfin_serial_ports[0];<br /> else<br /> uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];<br /> <br /> while(!(UART_GET_LSR(uart) & DR)) {<br /> SSYNC();<br /> }<br />#ifndef CONFIG_BF54x<br /> UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));<br /> SSYNC();<br />#endif<br /> chr = UART_GET_CHAR(uart);<br /> SSYNC();<br /><br /> return chr;<br />}<br />#endif<br /><br />#if ANOMALY_05000230 && defined(CONFIG_SERIAL_BFIN_PIO)<br /># define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold)<br /># define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v))<br />#else<br /># define UART_GET_ANOMALY_THRESHOLD(uart) 0<br /># define UART_SET_ANOMALY_THRESHOLD(uart, v)<br />#endif<br /><br />#ifdef CONFIG_SERIAL_BFIN_PIO<br />static void bfin_serial_rx_chars(struct bfin_serial_port *uart)<br />{<br /> struct tty_struct *tty = uart->port.info->tty;<br /> unsigned int status, ch, flg;<br /> static struct timeval anomaly_start = { .tv_sec = 0 };<br />#ifdef CONFIG_KGDB_UART<br /> struct pt_regs *regs = get_irq_regs();<br />#endif<br /><br /> status = UART_GET_LSR(uart);<br /> UART_CLEAR_LSR(uart);<br /><br /> ch = UART_GET_CHAR(uart);<br /> uart->port.icount.rx++;<br /><br />#ifdef CONFIG_KGDB_UART<br /> if (uart->port.line == CONFIG_KGDB_UART_PORT) {<br /> if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */<br /> kgdb_breakkey_pressed(regs);<br /> return;<br /> } else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */<br /> kgdb_entry_state = 1;<br /> } else if (kgdb_entry_state == 1 && ch == 'q') {<br /> kgdb_entry_state = 0;<br /> kgdb_breakkey_pressed(regs);<br /> return;<br /> } else if (ch == 0x3) {/* Ctrl + C */<br /> kgdb_entry_state = 0;<br /> kgdb_breakkey_pressed(regs);<br /> return;<br /> } else {<br /> kgdb_entry_state = 0;<br /> }<br /> }<br />#endif<br /><br /> if (ANOMALY_05000230) {<br /> /* The BF533 (and BF561) family of processors have a nice anomaly<br /> * where they continuously generate characters for a "single" break.<br /> * We have to basically ignore this flood until the "next" valid<br /> * character comes across. Due to the nature of the flood, it is<br /> * not possible to reliably catch bytes that are sent too quickly<br /> * after this break. So application code talking to the Blackfin<br /> * which sends a break signal must allow at least 1.5 character<br /> * times after the end of the break for things to stabilize. This<br /> * timeout was picked as it must absolutely be larger than 1<br /> * character time +/- some percent. So 1.5 sounds good. All other<br /> * Blackfin families operate properly. Woo.<br /> * Note: While Anomaly 05000230 does not directly address this,<br /> * the changes that went in for it also fixed this issue.<br /> * That anomaly was fixed in 0.5+ silicon. I like bunnies.<br /> */<br /> if (anomaly_start.tv_sec) {<br /> struct timeval curr;<br /> suseconds_t usecs;<br /><br /> if ((~ch & (~ch + 1)) & 0xff)<br /> goto known_good_char;<br /><br /> do_gettimeofday(&curr);<br /> if (curr.tv_sec - anomaly_start.tv_sec > 1)<br /> goto known_good_char;<br /><br /> usecs = 0;<br /> if (curr.tv_sec != anomaly_start.tv_sec)<br /> usecs += USEC_PER_SEC;<br /> usecs += curr.tv_usec - anomaly_start.tv_usec;<br /><br /> if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))<br /> goto known_good_char;<br /><br /> if (ch)<br /> anomaly_start.tv_sec = 0;<br /> else<br /> anomaly_start = curr;<br /><br /> return;<br /><br /> known_good_char:<br /> anomaly_start.tv_sec = 0;<br /> }<br /> }<br /><br /> if (status & BI) {<br /> if (ANOMALY_05000230)<br /> if (bfin_revid() < 5)<br /> do_gettimeofday(&anomaly_start);<br /> uart->port.icount.brk++;<br /> if (uart_handle_break(&uart->port))<br /> goto ignore_char;<br /> status &= ~(PE | FE);<br /> }<br /> if (status & PE)<br /> uart->port.icount.parity++;<br /> if (status & OE)<br /> uart->port.icount.overrun++;<br /> if (status & FE)<br /> uart->port.icount.frame++;<br /><br /> status &= uart->port.read_status_mask;<br /><br /> if (status & BI)<br /> flg = TTY_BREAK;<br /> else if (status & PE)<br /> flg = TTY_PARITY;<br /> else if (status & FE)<br /> flg = TTY_FRAME;<br /> else<br /> flg = TTY_NORMAL;<br /><br /> if (uart_handle_sysrq_char(&uart->port, ch))<br /> goto ignore_char;<br /><br /> uart_insert_char(&uart->port, status, OE, ch, flg);<br /><br /> ignore_char:<br /> tty_flip_buffer_push(tty);<br />}<br /><br />static void bfin_serial_tx_chars(struct bfin_serial_port *uart)<br />{<br /> struct circ_buf *xmit = &uart->port.info->xmit;<br /><br /> /*<br /> * Check the modem control lines before<br /> * transmitting anything.<br /> */<br /> bfin_serial_mctrl_check(uart);<br /><br /> if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {<br /> bfin_serial_stop_tx(&uart->port);<br /> return;<br /> }<br /><br /> if (uart->port.x_char) {<br /> UART_PUT_CHAR(uart, uart->port.x_char);<br /> uart->port.icount.tx++;<br /> uart->port.x_char = 0;<br /> }<br /><br /> while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {<br /> UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);<br /> xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);<br /> uart->port.icount.tx++;<br /> SSYNC();<br /> }<br /><br /> if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)<br /> uart_write_wakeup(&uart->port);<br /><br /> if (uart_circ_empty(xmit))<br /> bfin_serial_stop_tx(&uart->port);<br />}<br /><br />static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)<br />{<br /> struct bfin_serial_port *uart = dev_id;<br /><br /> spin_lock(&uart->port.lock);<br /> while (UART_GET_LSR(uart) & DR)<br /> bfin_serial_rx_chars(uart);<br /> spin_unlock(&uart->port.lock);<br /><br /> return IRQ_HANDLED;<br />}<br /><br />static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)<br />{<br /> struct bfin_serial_port *uart = dev_id;<br /><br /> spin_lock(&uart->port.lock);<br /> if (UART_GET_LSR(uart) & THRE)<br /> bfin_serial_tx_chars(uart);<br /> spin_unlock(&uart->port.lock);<br /><br /> return IRQ_HANDLED;<br />}<br />#endif<br /><br />#ifdef CONFIG_SERIAL_BFIN_DMA<br />static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)<br />{<br /> struct circ_buf *xmit = &uart->port.info->xmit;<br /> unsigned short ier;<br /><br /> uart->tx_done = 0;<br /><br /> /*<br /> * Check the modem control lines before<br /> * transmitting anything.<br /> */<br /> bfin_serial_mctrl_check(uart);<br /><br /> if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {<br /> uart->tx_count = 0;<br /> uart->tx_done = 1;<br /> return;<br /> }<br /><br /> if (uart->port.x_char) {<br /> UART_PUT_CHAR(uart, uart->port.x_char);<br /> uart->port.icount.tx++;<br /> uart->port.x_char = 0;<br /> }<br /><br /> uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);<br /> if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))<br /> uart->tx_count = UART_XMIT_SIZE - xmit->tail;<br /> blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail),<br /> (unsigned long)(xmit->buf+xmit->tail+uart->tx_count));<br /> set_dma_config(uart->tx_dma_channel,<br /> set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,<br /> INTR_ON_BUF,<br /> DIMENSION_LINEAR,<br /> DATA_SIZE_8,<br /> DMA_SYNC_RESTART));<br /> set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));<br /> set_dma_x_count(uart->tx_dma_channel, uart->tx_count);<br /> set_dma_x_modify(uart->tx_dma_channel, 1);<br /> enable_dma(uart->tx_dma_channel);<br /><br />#ifdef CONFIG_BF54x<br /> UART_SET_IER(uart, ETBEI);<br />#else<br /> ier = UART_GET_IER(uart);<br /> ier |= ETBEI;<br /> UART_PUT_IER(uart, ier);<br />#endif<br />}<br /><br />static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)<br />{<br /> struct tty_struct *tty = uart->port.info->tty;<br /> int i, flg, status;<br /><br /> status = UART_GET_LSR(uart);<br /> UART_CLEAR_LSR(uart);<br /><br /> uart->port.icount.rx +=<br /> CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail,<br /> UART_XMIT_SIZE);<br /><br /> if (status & BI) {<br /> uart->port.icount.brk++;<br /> if (uart_handle_break(&uart->port))<br /> goto dma_ignore_char;<br /> status &= ~(PE | FE);<br /> }<br /> if (status & PE)<br /> uart->port.icount.parity++;<br /> if (status & OE)<br /> uart->port.icount.overrun++;<br /> if (status & FE)<br /> uart->port.icount.frame++;<br /><br /> status &= uart->port.read_status_mask;<br /><br /> if (status & BI)<br /> flg = TTY_BREAK;<br /> else if (status & PE)<br /> flg = TTY_PARITY;<br /> else if (status & FE)<br /> flg = TTY_FRAME;<br /> else<br /> flg = TTY_NORMAL;<br /><br /> for (i = uart->rx_dma_buf.tail; i != uart->rx_dma_buf.head; i++) {<br /> if (i >= UART_XMIT_SIZE)<br /> i = 0;<br /> if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))<br /> uart_insert_char(&uart->port, status, OE,<br /> uart->rx_dma_buf.buf[i], flg);<br /> }<br /><br /> dma_ignore_char:<br /> tty_flip_buffer_push(tty);<br />}<br /><br />void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)<br />{<br /> int x_pos, pos;<br /><br /> uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);<br /> x_pos = get_dma_curr_xcount(uart->rx_dma_channel);<br /> uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;<br /> if (uart->rx_dma_nrows == DMA_RX_YCOUNT)<br /> uart->rx_dma_nrows = 0;<br /> x_pos = DMA_RX_XCOUNT - x_pos;<br /> if (x_pos == DMA_RX_XCOUNT)<br /> x_pos = 0;<br /><br /> pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;<br /> if (pos != uart->rx_dma_buf.tail) {<br /> uart->rx_dma_buf.head = pos;<br /> bfin_serial_dma_rx_chars(uart);<br /> uart->rx_dma_buf.tail = uart->rx_dma_buf.head;<br /> }<br /><br /> mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);<br />}<br /><br />static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)<br />{<br /> struct bfin_serial_port *uart = dev_id;<br /> struct circ_buf *xmit = &uart->port.info->xmit;<br /> unsigned short ier;<br /><br /> spin_lock(&uart->port.lock);<br /> if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {<br /> disable_dma(uart->tx_dma_channel);<br /> clear_dma_irqstat(uart->tx_dma_channel);<br />#ifdef CONFIG_BF54x<br /> UART_CLEAR_IER(uart, ETBEI);<br />#else<br /> ier = UART_GET_IER(uart);<br /> ier &= ~ETBEI;<br /> UART_PUT_IER(uart, ier);<br />#endif<br /> xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);<br /> uart->port.icount.tx += uart->tx_count;<br /><br /> if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)<br /> uart_write_wakeup(&uart->port);<br /><br /> bfin_serial_dma_tx_chars(uart);<br /> }<br /><br /> spin_unlock(&uart->port.lock);<br /> return IRQ_HANDLED;<br />}<br /><br />static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)<br />{<br /> struct bfin_serial_port *uart = dev_id;<br /> unsigned short irqstat;<br /><br /> spin_lock(&uart->port.lock);<br /> irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);<br /> clear_dma_irqstat(uart->rx_dma_channel);<br /> spin_unlock(&uart->port.lock);<br /><br /> mod_timer(&(uart->rx_dma_timer), jiffies);<br /><br /> return IRQ_HANDLED;<br />}<br />#endif<br /><br />/*<br /> * Return TIOCSER_TEMT when transmitter is not busy.<br /> */<br />static unsigned int bfin_serial_tx_empty(struct uart_port *port)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /> unsigned short lsr;<br /><br /> lsr = UART_GET_LSR(uart);<br /> if (lsr & TEMT)<br /> return TIOCSER_TEMT;<br /> else<br /> return 0;<br />}<br /><br />static unsigned int bfin_serial_get_mctrl(struct uart_port *port)<br />{<br />#ifdef CONFIG_SERIAL_BFIN_CTSRTS<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /> if (uart->cts_pin < 0)<br /> return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;<br /><br /># ifdef BF54x<br /> if (UART_GET_MSR(uart) & CTS)<br /># else<br /> if (gpio_get_value(uart->cts_pin))<br /># endif<br /> return TIOCM_DSR | TIOCM_CAR;<br /> else<br />#endif<br /> return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;<br />}<br /><br />static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)<br />{<br />#ifdef CONFIG_SERIAL_BFIN_CTSRTS<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /> if (uart->rts_pin < 0)<br /> return;<br /><br /> if (mctrl & TIOCM_RTS)<br /># ifdef BF54x<br /> UART_PUT_MCR(uart, UART_GET_MCR(uart) & ~MRTS);<br /># else<br /> gpio_set_value(uart->rts_pin, 0);<br /># endif<br /> else<br /># ifdef BF54x<br /> UART_PUT_MCR(uart, UART_GET_MCR(uart) | MRTS);<br /># else<br /> gpio_set_value(uart->rts_pin, 1);<br /># endif<br />#endif<br />}<br /><br />/*<br /> * Handle any change of modem status signal since we were last called.<br /> */<br />static void bfin_serial_mctrl_check(struct bfin_serial_port *uart)<br />{<br />#ifdef CONFIG_SERIAL_BFIN_CTSRTS<br /> unsigned int status;<br /> struct uart_info *info = uart->port.info;<br /> struct tty_struct *tty = info->tty;<br /><br /> status = bfin_serial_get_mctrl(&uart->port);<br /> uart_handle_cts_change(&uart->port, status & TIOCM_CTS);<br /> if (!(status & TIOCM_CTS)) {<br /> tty->hw_stopped = 1;<br /> uart->cts_timer.data = (unsigned long)(uart);<br /> uart->cts_timer.function = (void *)bfin_serial_mctrl_check;<br /> uart->cts_timer.expires = jiffies + CTS_CHECK_JIFFIES;<br /> add_timer(&(uart->cts_timer));<br /> } else {<br /> tty->hw_stopped = 0;<br /> }<br />#endif<br />}<br /><br />/*<br /> * Interrupts are always disabled.<br /> */<br />static void bfin_serial_break_ctl(struct uart_port *port, int break_state)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /> u16 lcr = UART_GET_LCR(uart);<br /> if (break_state)<br /> lcr |= SB;<br /> else<br /> lcr &= ~SB;<br /> UART_PUT_LCR(uart, lcr);<br /> SSYNC();<br />}<br /><br />static int bfin_serial_startup(struct uart_port *port)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /><br />#ifdef CONFIG_SERIAL_BFIN_DMA<br /> dma_addr_t dma_handle;<br /><br /> if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) {<br /> printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n");<br /> return -EBUSY;<br /> }<br /><br /> if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) {<br /> printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n");<br /> free_dma(uart->rx_dma_channel);<br /> return -EBUSY;<br /> }<br /><br /> set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart);<br /> set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart);<br /><br /> uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA);<br /> uart->rx_dma_buf.head = 0;<br /> uart->rx_dma_buf.tail = 0;<br /> uart->rx_dma_nrows = 0;<br /><br /> set_dma_config(uart->rx_dma_channel,<br /> set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,<br /> INTR_ON_ROW, DIMENSION_2D,<br /> DATA_SIZE_8,<br /> DMA_SYNC_RESTART));<br /> set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);<br /> set_dma_x_modify(uart->rx_dma_channel, 1);<br /> set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);<br /> set_dma_y_modify(uart->rx_dma_channel, 1);<br /> set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf);<br /> enable_dma(uart->rx_dma_channel);<br /><br /> uart->rx_dma_timer.data = (unsigned long)(uart);<br /> uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout;<br /> uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;<br /> add_timer(&(uart->rx_dma_timer));<br />#else<br /> if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,<br /> "BFIN_UART_RX", uart)) {<br /># ifdef CONFIG_KGDB_UART<br /> if (uart->port.line != CONFIG_KGDB_UART_PORT) {<br /># endif<br /> printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");<br /> return -EBUSY;<br /># ifdef CONFIG_KGDB_UART<br /> }<br /># endif<br /> }<br /><br /><br /> if (request_irq<br /> (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,<br /> "BFIN_UART_TX", uart)) {<br /> printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");<br /> free_irq(uart->port.irq, uart);<br /> return -EBUSY;<br /> }<br />#endif<br />#ifdef CONFIG_BF54x<br /> UART_SET_IER(uart, ERBFI);<br />#else<br /> UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);<br />#endif<br /> return 0;<br />}<br /><br />static void bfin_serial_shutdown(struct uart_port *port)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /><br />#ifdef CONFIG_SERIAL_BFIN_DMA<br /> disable_dma(uart->tx_dma_channel);<br /> free_dma(uart->tx_dma_channel);<br /> disable_dma(uart->rx_dma_channel);<br /> free_dma(uart->rx_dma_channel);<br /> del_timer(&(uart->rx_dma_timer));<br /> dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);<br />#else<br />#ifdef CONFIG_KGDB_UART<br /> if (uart->port.line != CONFIG_KGDB_UART_PORT)<br />#endif<br /> free_irq(uart->port.irq, uart);<br /> free_irq(uart->port.irq+1, uart);<br />#endif<br />}<br /><br />/*<br /> Adam: Document/serial/driver:<br /><br /> set_termios(port,termios,oldtermios)<br /> Change the port parameters, including word length, parity, stop<br /> bits. Update read_status_mask and ignore_status_mask to indicate<br /> the types of events we are interested in receiving. Relevant<br /> termios->c_cflag bits are:<br /> CSIZE - word size<br /> CSTOPB - 2 stop bits<br /> PARENB - parity enable<br /> PARODD - odd parity (when PARENB is in force)<br /> CREAD - enable reception of characters (if not set,<br /> still receive characters from the port, but<br /> throw them away.<br /> CRTSCTS - if set, enable CTS status change reporting<br /> CLOCAL - if not set, enable modem status change<br /> reporting.<br /> Relevant termios->c_iflag bits are:<br /> INPCK - enable frame and parity error events to be<br /> passed to the TTY layer.<br /> BRKINT<br /> PARMRK - both of these enable break events to be<br /> passed to the TTY layer.<br /><br /> IGNPAR - ignore parity and framing errors<br /> IGNBRK - ignore break errors, If IGNPAR is also<br /> set, ignore overrun errors as well.<br /><br />*/<br /><br />static void<br />bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,<br /> struct ktermios *old)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /> unsigned long flags;<br /> unsigned int baud, quot;<br /> unsigned short val, ier, lsr, lcr = 0;<br /><br /> switch (termios->c_cflag & CSIZE) {<br /> case CS8:<br /> lcr = WLS(8);<br /> break;<br /> case CS7:<br /> lcr = WLS(7);<br /> break;<br /> case CS6:<br /> lcr = WLS(6);<br /> break;<br /> case CS5:<br /> lcr = WLS(5);<br /> break;<br /> default:<br /> printk(KERN_ERR "%s: word lengh not supported\n",<br /> __FUNCTION__);<br /> }<br /><br /> if (termios->c_cflag & CSTOPB)<br /> lcr |= STB;<br /> if (termios->c_cflag & PARENB)<br /> lcr |= PEN;<br /> if (!(termios->c_cflag & PARODD))<br /> lcr |= EPS;<br /> if (termios->c_cflag & CMSPAR)<br /> lcr |= STP;<br /><br /> port->read_status_mask = OE;<br /> if (termios->c_iflag & INPCK)<br /> port->read_status_mask |= (FE | PE);<br /> if (termios->c_iflag & (BRKINT | PARMRK))<br /> port->read_status_mask |= BI;<br /><br /> /*<br /> * Characters to ignore<br /> */<br /> port->ignore_status_mask = 0;<br /> if (termios->c_iflag & IGNPAR)<br /> port->ignore_status_mask |= FE | PE;<br /> if (termios->c_iflag & IGNBRK) {<br /> port->ignore_status_mask |= BI;<br /> /*<br /> * If we're ignoring parity and break indicators,<br /> * ignore overruns too (for real raw support).<br /> */<br /> if (termios->c_iflag & IGNPAR)<br /> port->ignore_status_mask |= OE;<br /> }<br /><br /> baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);<br /> quot = uart_get_divisor(port, baud);<br /> spin_lock_irqsave(&uart->port.lock, flags);<br /><br /> UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);<br /><br /> /* Disable UART */<br /> ier = UART_GET_IER(uart);<br />#ifdef CONFIG_BF54x<br /> UART_CLEAR_IER(uart, 0xF);<br />#else<br /> UART_PUT_IER(uart, 0);<br />#endif<br /><br />#ifndef CONFIG_BF54x<br /> /* Set DLAB in LCR to Access DLL and DLH */<br /> val = UART_GET_LCR(uart);<br /> val |= DLAB;<br /> UART_PUT_LCR(uart, val);<br /> SSYNC();<br />#endif<br /><br /> UART_PUT_DLL(uart, quot & 0xFF);<br /> SSYNC();<br /> UART_PUT_DLH(uart, (quot >> 8) & 0xFF);<br /> SSYNC();<br /><br />#ifndef CONFIG_BF54x<br /> /* Clear DLAB in LCR to Access THR RBR IER */<br /> val = UART_GET_LCR(uart);<br /> val &= ~DLAB;<br /> UART_PUT_LCR(uart, val);<br /> SSYNC();<br />#endif<br /><br /> UART_PUT_LCR(uart, lcr);<br /><br /> /* Enable UART */<br />#ifdef CONFIG_BF54x<br /> UART_SET_IER(uart, ier);<br />#else<br /> UART_PUT_IER(uart, ier);<br />#endif<br /><br /> val = UART_GET_GCTL(uart);<br /> val |= UCEN;<br /> UART_PUT_GCTL(uart, val);<br /><br /> spin_unlock_irqrestore(&uart->port.lock, flags);<br />}<br /><br />static const char *bfin_serial_type(struct uart_port *port)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /><br /> return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL;<br />}<br /><br />/*<br /> * Release the memory region(s) being used by 'port'.<br /> */<br />static void bfin_serial_release_port(struct uart_port *port)<br />{<br />}<br /><br />/*<br /> * Request the memory region(s) being used by 'port'.<br /> */<br />static int bfin_serial_request_port(struct uart_port *port)<br />{<br /> return 0;<br />}<br /><br />/*<br /> * Configure/autoconfigure the port.<br /> */<br />static void bfin_serial_config_port(struct uart_port *port, int flags)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /><br /> if (flags & UART_CONFIG_TYPE &&<br /> bfin_serial_request_port(&uart->port) == 0)<br /> uart->port.type = PORT_BFIN;<br />}<br /><br />/*<br /> * Verify the new serial_struct (for TIOCSSERIAL).<br /> * The only change we allow are to the flags and type, and<br /> * even then only between PORT_BFIN and PORT_UNKNOWN<br /> */<br />static int<br />bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)<br />{<br /> return 0;<br />}<br /><br />static struct uart_ops bfin_serial_pops = {<br /> .tx_empty = bfin_serial_tx_empty,<br /> .set_mctrl = bfin_serial_set_mctrl,<br /> .get_mctrl = bfin_serial_get_mctrl,<br /> .stop_tx = bfin_serial_stop_tx,<br /> .start_tx = bfin_serial_start_tx,<br /> .stop_rx = bfin_serial_stop_rx,<br /> .enable_ms = bfin_serial_enable_ms,<br /> .break_ctl = bfin_serial_break_ctl,<br /> .startup = bfin_serial_startup,<br /> .shutdown = bfin_serial_shutdown,<br /> .set_termios = bfin_serial_set_termios,<br /> .type = bfin_serial_type,<br /> .release_port = bfin_serial_release_port,<br /> .request_port = bfin_serial_request_port,<br /> .config_port = bfin_serial_config_port,<br /> .verify_port = bfin_serial_verify_port,<br />};<br /><br />static void __init bfin_serial_init_ports(void)<br />{<br /> static int first = 1;<br /> int i;<br /><br /> if (!first)<br /> return;<br /> first = 0;<br /><br /> for (i = 0; i < nr_ports; i++) {<br /> bfin_serial_ports[i].port.uartclk = get_sclk();<br /> bfin_serial_ports[i].port.ops = &bfin_serial_pops;<br /> bfin_serial_ports[i].port.line = i;<br /> bfin_serial_ports[i].port.iotype = UPIO_MEM;<br /> bfin_serial_ports[i].port.membase =<br /> (void __iomem *)bfin_serial_resource[i].uart_base_addr;<br /> bfin_serial_ports[i].port.mapbase =<br /> bfin_serial_resource[i].uart_base_addr;<br /> bfin_serial_ports[i].port.irq =<br /> bfin_serial_resource[i].uart_irq;<br /> bfin_serial_ports[i].port.flags = UPF_BOOT_AUTOCONF;<br />#ifdef CONFIG_SERIAL_BFIN_DMA<br /> bfin_serial_ports[i].tx_done = 1;<br /> bfin_serial_ports[i].tx_count = 0;<br /> bfin_serial_ports[i].tx_dma_channel =<br /> bfin_serial_resource[i].uart_tx_dma_channel;<br /> bfin_serial_ports[i].rx_dma_channel =<br /> bfin_serial_resource[i].uart_rx_dma_channel;<br /> init_timer(&(bfin_serial_ports[i].rx_dma_timer));<br />#endif<br />#ifdef CONFIG_SERIAL_BFIN_CTSRTS<br /> init_timer(&(bfin_serial_ports[i].cts_timer));<br /> bfin_serial_ports[i].cts_pin =<br /> bfin_serial_resource[i].uart_cts_pin;<br /> bfin_serial_ports[i].rts_pin =<br /> bfin_serial_resource[i].uart_rts_pin;<br />#endif<br /> bfin_serial_hw_init(&bfin_serial_ports[i]);<br /> }<br /><br />}<br /><br />#ifdef CONFIG_SERIAL_BFIN_CONSOLE<br />/*<br /> * If the port was already initialised (eg, by a boot loader),<br /> * try to determine the current setup.<br /> */<br />static void __init<br />bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,<br /> int *parity, int *bits)<br />{<br /> unsigned short status;<br /><br /> status = UART_GET_IER(uart) & (ERBFI | ETBEI);<br /> if (status == (ERBFI | ETBEI)) {<br /> /* ok, the port was enabled */<br /> unsigned short lcr, val;<br /> unsigned short dlh, dll;<br /><br /> lcr = UART_GET_LCR(uart);<br /><br /> *parity = 'n';<br /> if (lcr & PEN) {<br /> if (lcr & EPS)<br /> *parity = 'e';<br /> else<br /> *parity = 'o';<br /> }<br /> switch (lcr & 0x03) {<br /> case 0: *bits = 5; break;<br /> case 1: *bits = 6; break;<br /> case 2: *bits = 7; break;<br /> case 3: *bits = 8; break;<br /> }<br />#ifndef CONFIG_BF54x<br /> /* Set DLAB in LCR to Access DLL and DLH */<br /> val = UART_GET_LCR(uart);<br /> val |= DLAB;<br /> UART_PUT_LCR(uart, val);<br />#endif<br /><br /> dll = UART_GET_DLL(uart);<br /> dlh = UART_GET_DLH(uart);<br /><br />#ifndef CONFIG_BF54x<br /> /* Clear DLAB in LCR to Access THR RBR IER */<br /> val = UART_GET_LCR(uart);<br /> val &= ~DLAB;<br /> UART_PUT_LCR(uart, val);<br />#endif<br /><br /> *baud = get_sclk() / (16*(dll | dlh << 8));<br /> }<br /> pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);<br />}<br />#endif<br /><br />#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)<br />static struct uart_driver bfin_serial_reg;<br /><br />static int __init<br />bfin_serial_console_setup(struct console *co, char *options)<br />{<br /> struct bfin_serial_port *uart;<br /># ifdef CONFIG_SERIAL_BFIN_CONSOLE<br /> int baud = 57600;<br /> int bits = 8;<br /> int parity = 'n';<br /># ifdef CONFIG_SERIAL_BFIN_CTSRTS<br /> int flow = 'r';<br /># else<br /> int flow = 'n';<br /># endif<br /># endif<br /><br /> /*<br /> * Check whether an invalid uart number has been specified, and<br /> * if so, search for the first available port that does have<br /> * console support.<br /> */<br /> if (co->index == -1 || co->index >= nr_ports)<br /> co->index = 0;<br /> uart = &bfin_serial_ports[co->index];<br /><br /># ifdef CONFIG_SERIAL_BFIN_CONSOLE<br /> if (options)<br /> uart_parse_options(options, &baud, &parity, &bits, &flow);<br /> else<br /> bfin_serial_console_get_options(uart, &baud, &parity, &bits);<br /><br /> return uart_set_options(&uart->port, co, baud, parity, bits, flow);<br /># else<br /> return 0;<br /># endif<br />}<br />#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||<br /> defined (CONFIG_EARLY_PRINTK) */<br /><br />#ifdef CONFIG_SERIAL_BFIN_CONSOLE<br />static void bfin_serial_console_putchar(struct uart_port *port, int ch)<br />{<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /> while (!(UART_GET_LSR(uart) & THRE))<br /> barrier();<br /> UART_PUT_CHAR(uart, ch);<br /> SSYNC();<br />}<br /><br />/*<br /> * Interrupts are disabled on entering<br /> */<br />static void<br />bfin_serial_console_write(struct console *co, const char *s, unsigned int count)<br />{<br /> struct bfin_serial_port *uart = &bfin_serial_ports[co->index];<br /> int flags = 0;<br /><br /> spin_lock_irqsave(&uart->port.lock, flags);<br /> uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);<br /> spin_unlock_irqrestore(&uart->port.lock, flags);<br /><br />}<br /><br />static struct console bfin_serial_console = {<br /> .name = BFIN_SERIAL_NAME,<br /> .write = bfin_serial_console_write,<br /> .device = uart_console_device,<br /> .setup = bfin_serial_console_setup,<br /> .flags = CON_PRINTBUFFER,<br /> .index = -1,<br /> .data = &bfin_serial_reg,<br />};<br /><br />static int __init bfin_serial_rs_console_init(void)<br />{<br /> bfin_serial_init_ports();<br />/* Adam: <br /> * kernel/printk.c: register_console()<br /> * The console driver calls this routine during kernel initialization<br /> * to register the console printing procedure with printk() and to<br /> * print any messages that were printed by the kernel before the<br /> * console driver was initialized.<br /> */<br /> register_console(&bfin_serial_console);<br />#ifdef CONFIG_KGDB_UART<br /> kgdb_entry_state = 0;<br /> init_kgdb_uart();<br />#endif<br /> return 0;<br />}<br />console_initcall(bfin_serial_rs_console_init);<br /><br />#define BFIN_SERIAL_CONSOLE &bfin_serial_console<br />#else<br />#define BFIN_SERIAL_CONSOLE NULL<br />#endif /* CONFIG_SERIAL_BFIN_CONSOLE */<br /><br /><br />#ifdef CONFIG_EARLY_PRINTK<br />static __init void early_serial_putc(struct uart_port *port, int ch)<br />{<br /> unsigned timeout = 0xffff;<br /> struct bfin_serial_port *uart = (struct bfin_serial_port *)port;<br /><br /> while ((!(UART_GET_LSR(uart) & THRE)) && --timeout)<br /> cpu_relax();<br /> UART_PUT_CHAR(uart, ch);<br />}<br /><br />static __init void early_serial_write(struct console *con, const char *s,<br /> unsigned int n)<br />{<br /> struct bfin_serial_port *uart = &bfin_serial_ports[con->index];<br /> unsigned int i;<br /><br /> for (i = 0; i < n; i++, s++) {<br /> if (*s == '\n')<br /> early_serial_putc(&uart->port, '\r');<br /> early_serial_putc(&uart->port, *s);<br /> }<br />}<br /><br />static struct __init console bfin_early_serial_console = {<br /> .name = "early_BFuart",<br /> .write = early_serial_write,<br /> .device = uart_console_device,<br /> .flags = CON_PRINTBUFFER,<br /> .setup = bfin_serial_console_setup,<br /> .index = -1,<br /> .data = &bfin_serial_reg,<br />};<br /><br /><br />/* Adam:<br /> * Called from: arch/blackfin/kernel/early_printk.c: bfin_earlyserial_init()<br /><br />*/<br />struct console __init *bfin_earlyserial_init(unsigned int port,<br /> unsigned int cflag)<br />{<br /> struct bfin_serial_port *uart;<br /> struct ktermios t;<br /><br /> if (port == -1 || port >= nr_ports)<br /> port = 0;<br /> bfin_serial_init_ports();<br /> bfin_early_serial_console.index = port;<br /> uart = &bfin_serial_ports[port];<br /> t.c_cflag = cflag;<br /> t.c_iflag = 0;<br /> t.c_oflag = 0;<br /> t.c_lflag = ICANON;<br /> t.c_line = port;<br /> bfin_serial_set_termios(&uart->port, &t, &t);<br /> return &bfin_early_serial_console;<br />}<br /><br />#endif /* CONFIG_SERIAL_BFIN_CONSOLE */<br /><br />static struct uart_driver bfin_serial_reg = {<br /> .owner = THIS_MODULE,<br /> .driver_name = "bfin-uart",<br /> .dev_name = BFIN_SERIAL_NAME,<br /> .major = BFIN_SERIAL_MAJOR,<br /> .minor = BFIN_SERIAL_MINOR,<br /> .nr = NR_PORTS,<br /> .cons = BFIN_SERIAL_CONSOLE,<br />};<br /><br />static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)<br />{<br /> struct bfin_serial_port *uart = platform_get_drvdata(dev);<br /><br /> if (uart)<br /> uart_suspend_port(&bfin_serial_reg, &uart->port);<br /><br /> return 0;<br />}<br /><br />static int bfin_serial_resume(struct platform_device *dev)<br />{<br /> struct bfin_serial_port *uart = platform_get_drvdata(dev);<br /><br /> if (uart)<br /> uart_resume_port(&bfin_serial_reg, &uart->port);<br /><br /> return 0;<br />}<br /><br />static int bfin_serial_probe(struct platform_device *dev)<br />{<br /> struct resource *res = dev->resource;<br /> int i;<br /><br /> for (i = 0; i < dev->num_resources; i++, res++)<br /> if (res->flags & IORESOURCE_MEM)<br /> break;<br /><br /> if (i < dev->num_resources) {<br /> for (i = 0; i < nr_ports; i++, res++) {<br /> if (bfin_serial_ports[i].port.mapbase != res->start)<br /> continue;<br /> bfin_serial_ports[i].port.dev = &dev->dev;<br /> uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);<br /> platform_set_drvdata(dev, &bfin_serial_ports[i]);<br /> }<br /> }<br /><br /> return 0;<br />}<br /><br />static int bfin_serial_remove(struct platform_device *pdev)<br />{<br /> struct bfin_serial_port *uart = platform_get_drvdata(pdev);<br /><br /><br />#ifdef CONFIG_SERIAL_BFIN_CTSRTS<br /> gpio_free(uart->cts_pin);<br /> gpio_free(uart->rts_pin);<br />#endif<br /><br /> platform_set_drvdata(pdev, NULL);<br /><br /> if (uart)<br /> uart_remove_one_port(&bfin_serial_reg, &uart->port);<br /><br /> return 0;<br />}<br /><br />static struct platform_driver bfin_serial_driver = {<br /> .probe = bfin_serial_probe,<br /> .remove = bfin_serial_remove,<br /> .suspend = bfin_serial_suspend,<br /> .resume = bfin_serial_resume,<br /> .driver = {<br /> .name = "bfin-uart",<br /> },<br />};<br /><br />static int __init bfin_serial_init(void)<br />{<br /> int ret;<br />#ifdef CONFIG_KGDB_UART<br /> struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];<br /> struct ktermios t;<br />#endif<br /><br /> pr_info("Serial: Blackfin serial driver\n");<br /><br /> bfin_serial_init_ports();<br /><br />/**<br /> * uart_register_driver - register a driver with the uart core layer<br /> * @drv: low level driver structure<br /> *<br /> * Register a uart driver with the core driver. We in turn register<br /> * with the tty layer, and initialise the core driver per-port state.<br /> *<br /> * We have a proc file in /proc/tty/driver which is named after the<br /> * normal driver.<br /> *<br /> * drv->port should be NULL, and the per-port structures should be<br /> * registered using uart_add_one_port after this call has succeeded.<br /> */<br /><br /> ret = uart_register_driver(&bfin_serial_reg);<br /> if (ret == 0) {<br /> ret = platform_driver_register(&bfin_serial_driver);<br /> if (ret) {<br /> pr_debug("uart register failed\n");<br /> uart_unregister_driver(&bfin_serial_reg);<br /> }<br /> }<br />#ifdef CONFIG_KGDB_UART<br /> if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {<br /> request_irq(uart->port.irq, bfin_serial_rx_int,<br /> IRQF_DISABLED, "BFIN_UART_RX", uart);<br /> pr_info("Request irq for kgdb uart port\n");<br />#ifdef CONFIG_BF54x<br /> UART_SET_IER(uart, ERBFI);<br />#else<br /> UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);<br />#endif<br /> SSYNC();<br /> t.c_cflag = CS8|B57600;<br /> t.c_iflag = 0;<br /> t.c_oflag = 0;<br /> t.c_lflag = ICANON;<br /> t.c_line = CONFIG_KGDB_UART_PORT;<br /> bfin_serial_set_termios(&uart->port, &t, &t);<br /> }<br />#endif<br /> return ret;<br />}<br /><br />static void __exit bfin_serial_exit(void)<br />{<br /> platform_driver_unregister(&bfin_serial_driver);<br /> uart_unregister_driver(&bfin_serial_reg);<br />}<br /><br />module_init(bfin_serial_init);<br />module_exit(bfin_serial_exit);<br /></code> </pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-68485261173591393202008-05-29T00:36:00.001-07:002008-05-29T00:38:24.718-07:00blackfin irq handler<pre><code> <br /><br />/* Interrupt flows: <br />EVT table --> <br /> INTERRUPT_ENTRY(N) --><br /> common_int_entry() --><br /> do_irq() --><br /> asm_do_IRQ() --><br /> generic_handle_irq() --><br /> irq_desc[irq]-> handler() <br /> --> {<br /> handle_simple_irq();<br /> handle_level_irq();<br /> ...<br /> } -> handle_IRQ_event() --><br /> action->handler() (request_irq() registers the real handler)<br /> <br />*/<br /><br />/* ============Adam: init the EVT table ========================*/<br />mach-common/ints-priority.c:<br />-----------------------------<br />void __init init_exception_vectors(void)<br />{<br /> SSYNC();<br /><br /> /* cannot program in software:<br /> * evt0 - emulation (jtag)<br /> * evt1 - reset<br /> */<br /> bfin_write_EVT2(evt_nmi);<br /> bfin_write_EVT3(trap);<br /> bfin_write_EVT5(evt_ivhw);<br /> bfin_write_EVT6(evt_timer);<br /> bfin_write_EVT7(evt_evt7);<br /> bfin_write_EVT8(evt_evt8);<br /> bfin_write_EVT9(evt_evt9);<br /> bfin_write_EVT10(evt_evt10);<br /> bfin_write_EVT11(evt_evt11);<br /> bfin_write_EVT12(evt_evt12);<br /> bfin_write_EVT13(evt_evt13);<br /> bfin_write_EVT14(evt14_softirq);<br /> bfin_write_EVT15(evt_system_call);<br /> CSYNC();<br />}<br /><br />mach-common/interrupt.S<br />--------------------------------------------------------------------------------<br />/* Interrupt routine for evt2 (NMI).<br /> * We don't actually use this, so just return.<br /> * For inner circle type details, please see:<br /> * http://docs.blackfin.uclinux.org/doku.php?id=linux:nmi<br /> */<br />ENTRY(_evt_nmi)<br />.weak _evt_nmi<br /> rtn;<br />ENDPROC(_evt_nmi)<br /><br />/* interrupt routine for core timer - 6 */<br />ENTRY(_evt_timer)<br /> TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P)<br /><br />/* interrupt routine for evt7 - 7 */<br />ENTRY(_evt_evt7)<br /> INTERRUPT_ENTRY(EVT_IVG7_P)<br />ENTRY(_evt_evt8)<br /> INTERRUPT_ENTRY(EVT_IVG8_P)<br />ENTRY(_evt_evt9)<br /> INTERRUPT_ENTRY(EVT_IVG9_P)<br />ENTRY(_evt_evt10)<br /> INTERRUPT_ENTRY(EVT_IVG10_P)<br />ENTRY(_evt_evt11)<br /> INTERRUPT_ENTRY(EVT_IVG11_P)<br />ENTRY(_evt_evt12)<br /> INTERRUPT_ENTRY(EVT_IVG12_P)<br />ENTRY(_evt_evt13)<br /> INTERRUPT_ENTRY(EVT_IVG13_P)<br /><br /><br />include/asm-blackfin/entry.h:<br />----------------------------------------------------------------------------<br />/*<br /> * NOTE! The single-stepping code assumes that all interrupt handlers<br /> * start by saving SYSCFG on the stack with their first instruction.<br /> */<br /><br />/* This one is used for exceptions, emulation, and NMI. It doesn't push<br /> RETI and doesn't do cli. */<br />#define SAVE_ALL_SYS save_context_no_interrupts<br />/* This is used for all normal interrupts. It saves a minimum of registers<br /> to the stack, loads the IRQ number, and jumps to common code. */<br />#define INTERRUPT_ENTRY(N) \<br /> [--sp] = SYSCFG; \<br /> \<br /> [--sp] = P0; /*orig_p0*/ \<br /> [--sp] = R0; /*orig_r0*/ \<br /> [--sp] = (R7:0,P5:0); \<br /> R0 = (N); \<br /> jump __common_int_entry;<br /><br />/* For timer interrupts, we need to save IPEND, since the user_mode<br /> macro accesses it to determine where to account time. */<br />#define TIMER_INTERRUPT_ENTRY(N) \<br /> [--sp] = SYSCFG; \<br /> \<br /> [--sp] = P0; /*orig_p0*/ \<br /> [--sp] = R0; /*orig_r0*/ \<br /> [--sp] = (R7:0,P5:0); \<br /> p0.l = lo(IPEND); \<br /> p0.h = hi(IPEND); \<br /> r1 = [p0]; \<br /> R0 = (N); \<br /> jump __common_int_entry;<br /><br /><br /><br />mach-common/interrupt.S<br />--------------------------------------------------------------------------------<br />/* Common interrupt entry code. First we do CLI, then push<br /> * RETI, to keep interrupts disabled, but to allow this state to be changed<br /> * by local_bh_enable.<br /> * R0 contains the interrupt number, while R1 may contain the value of IPEND,<br /> * or garbage if IPEND won't be needed by the ISR. */<br />__common_int_entry:<br /> [--sp] = fp;<br /> [--sp] = usp;<br /><br /> [--sp] = i0;<br /> [--sp] = i1;<br /> [--sp] = i2;<br /> [--sp] = i3;<br /><br /> [--sp] = m0;<br /> [--sp] = m1;<br /> [--sp] = m2;<br /> [--sp] = m3;<br /><br /> [--sp] = l0;<br /> [--sp] = l1;<br /> [--sp] = l2;<br /> [--sp] = l3;<br /><br /> [--sp] = b0;<br /> [--sp] = b1;<br /> [--sp] = b2;<br /> [--sp] = b3;<br /> [--sp] = a0.x;<br /> [--sp] = a0.w;<br /> [--sp] = a1.x;<br /> [--sp] = a1.w;<br /><br /> [--sp] = LC0;<br /> [--sp] = LC1;<br /> [--sp] = LT0;<br /> [--sp] = LT1;<br /> [--sp] = LB0;<br /> [--sp] = LB1;<br /><br /> [--sp] = ASTAT;<br /><br /> [--sp] = r0; /* Skip reserved */<br /> [--sp] = RETS;<br /> r2 = RETI;<br /> [--sp] = r2;<br /> [--sp] = RETX;<br /> [--sp] = RETN;<br /> [--sp] = RETE;<br /> [--sp] = SEQSTAT;<br /> [--sp] = r1; /* IPEND - R1 may or may not be set up before jumping here. */<br /><br /> /* Switch to other method of keeping interrupts disabled. */<br />#ifdef CONFIG_DEBUG_HWERR<br /> r1 = 0x3f;<br /> sti r1;<br />#else<br /> cli r1;<br />#endif<br /> [--sp] = RETI; /* orig_pc */<br /> /* Clear all L registers. */<br /> r1 = 0 (x);<br /> l0 = r1;<br /> l1 = r1;<br /> l2 = r1;<br /> l3 = r1;<br />#ifdef CONFIG_FRAME_POINTER<br /> fp = 0;<br />#endif<br /><br />#if ANOMALY_05000283 || ANOMALY_05000315<br /> cc = r7 == r7;<br /> p5.h = HI(CHIPID);<br /> p5.l = LO(CHIPID);<br /> if cc jump 1f;<br /> r7.l = W[p5];<br />1:<br />#endif<br /> r1 = sp;<br /> SP += -12;<br /> call _do_irq;<br /> SP += 12;<br /> call _return_from_int;<br />.Lcommon_restore_context:<br /> RESTORE_CONTEXT<br /> rti;<br /><br />/* Adam: ====================== do_irq() =========================*/<br />mach-common/ints-priority.c<br />----------------------------------------------------------------------<br />#ifdef CONFIG_DO_IRQ_L1<br />__attribute__((l1_text))<br />#endif<br />void do_irq(int vec, struct pt_regs *fp)<br />{<br /> if (vec == EVT_IVTMR_P) {<br /> vec = IRQ_CORETMR;<br /> } else {<br /> struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;<br /> struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;<br />#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)<br /> unsigned long sic_status[3];<br /><br /> sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();<br /> sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();<br />#ifdef CONFIG_BF54x<br /> sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();<br />#endif<br /> for (;; ivg++) {<br /> if (ivg >= ivg_stop) {<br /> atomic_inc(&num_spurious);<br /> return;<br /> }<br /> if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)<br /> break;<br /> }<br />#else<br /> unsigned long sic_status;<br /><br /> sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();<br /><br /> for (;; ivg++) {<br /> if (ivg >= ivg_stop) {<br /> atomic_inc(&num_spurious);<br /> return;<br /> } else if (sic_status & ivg->isrflag)<br /> break;<br /> }<br />#endif<br /> vec = ivg->irqno;<br /> }<br /> asm_do_IRQ(vec, fp);<br /><br />#ifdef CONFIG_KGDB<br /> kgdb_process_breakpoint();<br />#endif<br />}<br /><br />asm/kernel/irqchip.c<br />-----------------------------------------------------------------------------------<br />#ifdef CONFIG_DO_IRQ_L1<br />__attribute__((l1_text))<br />#endif<br />asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)<br />{<br /> struct pt_regs *old_regs;<br /> struct irq_desc *desc = irq_desc + irq;<br /> unsigned short pending, other_ints;<br /><br /> old_regs = set_irq_regs(regs);<br /><br /> /*<br /> * Some hardware gives randomly wrong interrupts. Rather<br /> * than crashing, do something sensible.<br /> */<br /> if (irq >= NR_IRQS)<br /> desc = &bad_irq_desc;<br /><br /> irq_enter();<br /><br /> generic_handle_irq(irq);<br /><br /> /* If we're the only interrupt running (ignoring IRQ15 which is for<br /> syscalls), lower our priority to IRQ14 so that softirqs run at<br /> that level. If there's another, lower-level interrupt, irq_exit<br /> will defer softirqs to that. */<br /> CSYNC();<br /> pending = bfin_read_IPEND() & ~0x8000;<br /> other_ints = pending & (pending - 1);<br /> if (other_ints == 0)<br /> lower_to_irq14();<br /> irq_exit();<br /><br /> set_irq_regs(old_regs);<br />}<br /><br />include/linux/irq.h:<br />----------------------------------------------------------------------------------------<br />/*<br /> * Architectures call this to let the generic IRQ layer<br /> * handle an interrupt. If the descriptor is attached to an<br /> * irqchip-style controller then we call the ->handle_irq() handler,<br /> * and it calls __do_IRQ() if it's attached to an irqtype-style controller.<br /> */<br />static inline void generic_handle_irq(unsigned int irq)<br />{<br /> struct irq_desc *desc = irq_desc + irq;<br /><br />#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ<br /> desc->handle_irq(irq, desc);<br />#else<br /> if (likely(desc->handle_irq))<br /> desc->handle_irq(irq, desc);<br /> else<br /> __do_IRQ(irq);<br />#endif<br />}<br /><br />/* Adam: =============== Global struct irq_desc irq_desc[NR_IRQS], struct irqchip ======== */<br /><br />kernel/irq/handle.c<br />-----------------------------------------------------------------------<br />/*<br /> * Linux has a controller-independent interrupt architecture.<br /> * Every controller has a 'controller-template', that is used<br /> * by the main code to do the right thing. Each driver-visible<br /> * interrupt source is transparently wired to the appropriate<br /> * controller. Thus drivers need not be aware of the<br /> * interrupt-controller.<br /> *<br /> * The code is designed to be easily extended with new/different<br /> * interrupt controllers, without having to do assembly magic or<br /> * having to touch the generic code.<br /> *<br /> * Controller mappings for all interrupt sources:<br /> */<br />struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {<br /> [0 ... NR_IRQS-1] = {<br /> .status = IRQ_DISABLED,<br /> .chip = &no_irq_chip,<br /> .handle_irq = handle_bad_irq,<br /> .depth = 1,<br /> .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),<br />#ifdef CONFIG_SMP<br /> .affinity = CPU_MASK_ALL<br />#endif<br /> }<br />};<br /><br />/**<br /> * struct irq_desc - interrupt descriptor<br /> *<br /> * @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()]<br /> * @chip: low level interrupt hardware access<br /> * @msi_desc: MSI descriptor<br /> * @handler_data: per-IRQ data for the irq_chip methods<br /> * @chip_data: platform-specific per-chip private data for the chip<br /> * methods, to allow shared chip implementations<br /> * @action: the irq action chain<br /> * @status: status information<br /> * @depth: disable-depth, for nested irq_disable() calls<br /> * @wake_depth: enable depth, for multiple set_irq_wake() callers<br /> * @irq_count: stats field to detect stalled irqs<br /> * @irqs_unhandled: stats field for spurious unhandled interrupts<br /> * @last_unhandled: aging timer for unhandled count<br /> * @lock: locking for SMP<br /> * @affinity: IRQ affinity on SMP<br /> * @cpu: cpu index useful for balancing<br /> * @pending_mask: pending rebalanced interrupts<br /> * @dir: /proc/irq/ procfs entry<br /> * @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP<br /> * @name: flow handler name for /proc/interrupts output<br /> */<br />struct irq_desc {<br /> irq_flow_handler_t handle_irq;<br /> struct irq_chip *chip;<br /> struct msi_desc *msi_desc;<br /> void *handler_data;<br /> void *chip_data;<br /> struct irqaction *action; /* IRQ action list */<br /> unsigned int status; /* IRQ status */<br /><br /> unsigned int depth; /* nested irq disables */<br /> unsigned int wake_depth; /* nested wake enables */<br /> unsigned int irq_count; /* For detecting broken IRQs */<br /> unsigned int irqs_unhandled;<br /> unsigned long last_unhandled; /* Aging timer for unhandled count */<br /> spinlock_t lock;<br />#ifdef CONFIG_SMP<br /> cpumask_t affinity;<br /> unsigned int cpu;<br />#endif<br />#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)<br /> cpumask_t pending_mask;<br />#endif<br />#ifdef CONFIG_PROC_FS<br /> struct proc_dir_entry *dir;<br />#endif<br /> const char *name;<br />} ____cacheline_internodealigned_in_smp;<br /><br /><br />arch/blackfin/mach-common/ints-priority.c:<br />------------------------------------------------------------<br />static struct irq_chip bfin_core_irqchip = {<br /> .ack = bfin_ack_noop,<br /> .mask = bfin_core_mask_irq,<br /> .unmask = bfin_core_unmask_irq,<br />};<br /><br />static struct irq_chip bfin_internal_irqchip = {<br /> .ack = bfin_ack_noop,<br /> .mask = bfin_internal_mask_irq,<br /> .unmask = bfin_internal_unmask_irq,<br /> .mask_ack = bfin_internal_mask_irq,<br /> .disable = bfin_internal_mask_irq,<br /> .enable = bfin_internal_unmask_irq,<br />#ifdef CONFIG_PM<br /> .set_wake = bfin_internal_set_wake,<br />#endif<br />};<br /><br />static struct irq_chip bfin_generic_error_irqchip = {<br /> .ack = bfin_ack_noop,<br /> .mask_ack = bfin_generic_error_mask_irq,<br /> .mask = bfin_generic_error_mask_irq,<br /> .unmask = bfin_generic_error_unmask_irq,<br />};<br /><br /><br />static struct irq_chip bfin_gpio_irqchip = {<br /> .ack = bfin_gpio_ack_irq,<br /> .mask = bfin_gpio_mask_irq,<br /> .mask_ack = bfin_gpio_mask_ack_irq,<br /> .unmask = bfin_gpio_unmask_irq,<br /> .set_type = bfin_gpio_irq_type,<br /> .startup = bfin_gpio_irq_startup,<br /> .shutdown = bfin_gpio_irq_shutdown,<br />#ifdef CONFIG_PM<br /> .set_wake = bfin_gpio_set_wake,<br />#endif<br />};<br /><br /><br />/* Adam: =============== How everything get initialized ======== */<br /><br />blackfin/kernel/irqchip.c:<br />-------------------------------------------------------<br />void __init init_IRQ(void)<br />{<br /> struct irq_desc *desc;<br /> int irq;<br /><br /> spin_lock_init(&irq_controller_lock);<br /> for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {<br /> *desc = bad_irq_desc;<br /> }<br /><br /> init_arch_irq();<br /><br />#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND<br /> /* Now that evt_ivhw is set up, turn this on */<br /> trace_buff_offset = 0;<br /> bfin_write_TBUFCTL(BFIN_TRACE_ON);<br /> printk(KERN_INFO "Hardware Trace expanded to %ik\n",<br /> 1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN);<br />#endif<br />}<br /><br />blackfin/mach-common/ints-prioirty.c<br />-------------------------------------------------------------<br />/*<br /> * This function should be called during kernel startup to initialize<br /> * the BFin IRQ handling routines.<br /> */<br />int __init init_arch_irq(void)<br />{<br /> int irq;<br /> unsigned long ilat = 0;<br /> /* Disable all the peripheral intrs - page 4-29 HW Ref manual */<br />#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)<br /> bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);<br /> bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);<br /># ifdef CONFIG_BF54x<br /> bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);<br /># endif<br />#else<br /> bfin_write_SIC_IMASK(SIC_UNMASK_ALL);<br />#endif<br /><br /> local_irq_disable();<br /><br />#ifdef CONFIG_BF54x<br /># ifdef CONFIG_PINTx_REASSIGN<br /> pint[0]->assign = CONFIG_PINT0_ASSIGN;<br /> pint[1]->assign = CONFIG_PINT1_ASSIGN;<br /> pint[2]->assign = CONFIG_PINT2_ASSIGN;<br /> pint[3]->assign = CONFIG_PINT3_ASSIGN;<br /># endif<br /> /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */<br /> init_pint_lut();<br />#endif<br /><br /> for (irq = 0; irq <= SYS_IRQS; irq++) {<br /> if (irq <= IRQ_CORETMR)<br /> set_irq_chip(irq, &bfin_core_irqchip);<br /> else<br /> set_irq_chip(irq, &bfin_internal_irqchip);<br /><br /> switch (irq) {<br />#if defined(CONFIG_BF53x)<br /> case IRQ_PROG_INTA:<br /># if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))<br /> case IRQ_MAC_RX:<br /># endif<br />#elif defined(CONFIG_BF54x)<br /> case IRQ_PINT0:<br /> case IRQ_PINT1:<br /> case IRQ_PINT2:<br /> case IRQ_PINT3:<br />#elif defined(CONFIG_BF52x)<br /> case IRQ_PORTF_INTA:<br /> case IRQ_PORTG_INTA:<br /> case IRQ_PORTH_INTA:<br />#elif defined(CONFIG_BF561)<br /> case IRQ_PROG0_INTA:<br /> case IRQ_PROG1_INTA:<br /> case IRQ_PROG2_INTA:<br />#endif<br /> set_irq_chained_handler(irq,<br /> bfin_demux_gpio_irq);<br /> break;<br />#ifdef BF537_GENERIC_ERROR_INT_DEMUX<br /> case IRQ_GENERIC_ERROR:<br /> set_irq_handler(irq, bfin_demux_error_irq);<br /><br /> break;<br />#endif<br /> default:<br /> set_irq_handler(irq, handle_simple_irq);<br /> break;<br /> }<br /> }<br /><br />#ifdef BF537_GENERIC_ERROR_INT_DEMUX<br /> for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)<br /> set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,<br /> handle_level_irq);<br />#endif<br /><br /> /* if configured as edge, then will be changed to do_edge_IRQ */<br /> for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++)<br /> set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,<br /> handle_level_irq);<br /><br /><br /> bfin_write_IMASK(0);<br /> CSYNC();<br /> ilat = bfin_read_ILAT();<br /> CSYNC();<br /> bfin_write_ILAT(ilat);<br /> CSYNC();<br /><br /> printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");<br /> /* IMASK=xxx is equivalent to STI xx or irq_flags=xx,<br /> * local_irq_enable()<br /> */<br /> program_IAR();<br /> /* Therefore it's better to setup IARs before interrupts enabled */<br /> search_IAR();<br /><br /> /* Enable interrupts IVG7-15 */<br /> irq_flags = irq_flags | IMASK_IVG15 |<br /> IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |<br /> IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;<br /><br />#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)<br /> bfin_write_SIC_IWR0(IWR_ENABLE_ALL);<br /> bfin_write_SIC_IWR1(IWR_ENABLE_ALL);<br /># ifdef CONFIG_BF54x<br /> bfin_write_SIC_IWR2(IWR_ENABLE_ALL);<br /># endif<br />#else<br /> bfin_write_SIC_IWR(IWR_ENABLE_ALL);<br />#endif<br /><br /><br /><br /> return 0;<br />}<br /><br />kernel/irq/chip.c:<br />------------------------------------------------------<br />/**<br /> * handle_simple_irq - Simple and software-decoded IRQs.<br /> * @irq: the interrupt number<br /> * @desc: the interrupt description structure for this irq<br /> *<br /> * Simple interrupts are either sent from a demultiplexing interrupt<br /> * handler or come from hardware, where no interrupt hardware control<br /> * is necessary.<br /> *<br /> * Note: The caller is expected to handle the ack, clear, mask and<br /> * unmask issues if necessary.<br /> */<br />void fastcall<br />handle_simple_irq(unsigned int irq, struct irq_desc *desc)<br />{<br /> struct irqaction *action;<br /> irqreturn_t action_ret;<br /> const unsigned int cpu = smp_processor_id();<br /><br /> spin_lock(&desc->lock);<br /><br /> if (unlikely(desc->status & IRQ_INPROGRESS))<br /> goto out_unlock;<br /> desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);<br /> kstat_cpu(cpu).irqs[irq]++;<br /><br /> action = desc->action;<br /> if (unlikely(!action || (desc->status & IRQ_DISABLED)))<br /> goto out_unlock;<br /><br /> desc->status |= IRQ_INPROGRESS;<br /> spin_unlock(&desc->lock);<br /><br /> action_ret = handle_IRQ_event(irq, action);<br /> if (!noirqdebug)<br /> note_interrupt(irq, desc, action_ret);<br /><br /> spin_lock(&desc->lock);<br /> desc->status &= ~IRQ_INPROGRESS;<br />out_unlock:<br /> spin_unlock(&desc->lock);<br />}<br /><br />/**<br /> * handle_level_irq - Level type irq handler<br /> * @irq: the interrupt number<br /> * @desc: the interrupt description structure for this irq<br /> *<br /> * Level type interrupts are active as long as the hardware line has<br /> * the active level. This may require to mask the interrupt and unmask<br /> * it after the associated handler has acknowledged the device, so the<br /> * interrupt line is back to inactive.<br /> */<br />void fastcall<br />handle_level_irq(unsigned int irq, struct irq_desc *desc)<br />{<br /> unsigned int cpu = smp_processor_id();<br /> struct irqaction *action;<br /> irqreturn_t action_ret;<br /><br /> spin_lock(&desc->lock);<br /> mask_ack_irq(desc, irq);<br /><br /> if (unlikely(desc->status & IRQ_INPROGRESS))<br /> goto out_unlock;<br /> desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);<br /> kstat_cpu(cpu).irqs[irq]++;<br /><br /> /*<br /> * If its disabled or no action available<br /> * keep it masked and get out of here<br /> */<br /> action = desc->action;<br /> if (unlikely(!action || (desc->status & IRQ_DISABLED)))<br /> goto out_unlock;<br /><br /> desc->status |= IRQ_INPROGRESS;<br /> spin_unlock(&desc->lock);<br /><br /> action_ret = handle_IRQ_event(irq, action);<br /> if (!noirqdebug)<br /> note_interrupt(irq, desc, action_ret);<br /><br /> spin_lock(&desc->lock);<br /> desc->status &= ~IRQ_INPROGRESS;<br /> if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)<br /> desc->chip->unmask(irq);<br />out_unlock:<br /> spin_unlock(&desc->lock);<br />}<br /><br />kernel/irq/handle.c:<br />------------------------------------------------------<br />/**<br /> * handle_IRQ_event - irq action chain handler<br /> * @irq: the interrupt number<br /> * @action: the interrupt action chain for this irq<br /> *<br /> * Handles the action chain of an irq event<br /> */<br />irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)<br />{<br /> irqreturn_t ret, retval = IRQ_NONE;<br /> unsigned int status = 0;<br /><br /> handle_dynamic_tick(action);<br /><br /> if (!(action->flags & IRQF_DISABLED))<br /> local_irq_enable_in_hardirq();<br /><br /> do {<br /> ret = action->handler(irq, action->dev_id);<br /> if (ret == IRQ_HANDLED)<br /> status |= action->flags;<br /> retval |= ret;<br /> action = action->next;<br /> } while (action);<br /><br /> if (status & IRQF_SAMPLE_RANDOM)<br /> add_interrupt_randomness(irq);<br /> local_irq_disable();<br /><br /> return retval;<br />}<br /><br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-90629039142782431522008-05-29T00:36:00.000-07:002008-05-29T00:37:46.017-07:00<pre><code> <br /><br />/* Interrupt flows: <br />EVT table --> <br /> INTERRUPT_ENTRY(N) --><br /> common_int_entry() --><br /> do_irq() --><br /> asm_do_IRQ() --><br /> generic_handle_irq() --><br /> irq_desc[irq]-> handler() <br /> --> {<br /> handle_simple_irq();<br /> handle_level_irq();<br /> ...<br /> } -> handle_IRQ_event() --><br /> action->handler() (request_irq() registers the real handler)<br /> <br />*/<br /><br />/* ============Adam: init the EVT table ========================*/<br />mach-common/ints-priority.c:<br />-----------------------------<br />void __init init_exception_vectors(void)<br />{<br /> SSYNC();<br /><br /> /* cannot program in software:<br /> * evt0 - emulation (jtag)<br /> * evt1 - reset<br /> */<br /> bfin_write_EVT2(evt_nmi);<br /> bfin_write_EVT3(trap);<br /> bfin_write_EVT5(evt_ivhw);<br /> bfin_write_EVT6(evt_timer);<br /> bfin_write_EVT7(evt_evt7);<br /> bfin_write_EVT8(evt_evt8);<br /> bfin_write_EVT9(evt_evt9);<br /> bfin_write_EVT10(evt_evt10);<br /> bfin_write_EVT11(evt_evt11);<br /> bfin_write_EVT12(evt_evt12);<br /> bfin_write_EVT13(evt_evt13);<br /> bfin_write_EVT14(evt14_softirq);<br /> bfin_write_EVT15(evt_system_call);<br /> CSYNC();<br />}<br /><br />mach-common/interrupt.S<br />--------------------------------------------------------------------------------<br />/* Interrupt routine for evt2 (NMI).<br /> * We don't actually use this, so just return.<br /> * For inner circle type details, please see:<br /> * http://docs.blackfin.uclinux.org/doku.php?id=linux:nmi<br /> */<br />ENTRY(_evt_nmi)<br />.weak _evt_nmi<br /> rtn;<br />ENDPROC(_evt_nmi)<br /><br />/* interrupt routine for core timer - 6 */<br />ENTRY(_evt_timer)<br /> TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P)<br /><br />/* interrupt routine for evt7 - 7 */<br />ENTRY(_evt_evt7)<br /> INTERRUPT_ENTRY(EVT_IVG7_P)<br />ENTRY(_evt_evt8)<br /> INTERRUPT_ENTRY(EVT_IVG8_P)<br />ENTRY(_evt_evt9)<br /> INTERRUPT_ENTRY(EVT_IVG9_P)<br />ENTRY(_evt_evt10)<br /> INTERRUPT_ENTRY(EVT_IVG10_P)<br />ENTRY(_evt_evt11)<br /> INTERRUPT_ENTRY(EVT_IVG11_P)<br />ENTRY(_evt_evt12)<br /> INTERRUPT_ENTRY(EVT_IVG12_P)<br />ENTRY(_evt_evt13)<br /> INTERRUPT_ENTRY(EVT_IVG13_P)<br /><br /><br />include/asm-blackfin/entry.h:<br />----------------------------------------------------------------------------<br />/*<br /> * NOTE! The single-stepping code assumes that all interrupt handlers<br /> * start by saving SYSCFG on the stack with their first instruction.<br /> */<br /><br />/* This one is used for exceptions, emulation, and NMI. It doesn't push<br /> RETI and doesn't do cli. */<br />#define SAVE_ALL_SYS save_context_no_interrupts<br />/* This is used for all normal interrupts. It saves a minimum of registers<br /> to the stack, loads the IRQ number, and jumps to common code. */<br />#define INTERRUPT_ENTRY(N) \<br /> [--sp] = SYSCFG; \<br /> \<br /> [--sp] = P0; /*orig_p0*/ \<br /> [--sp] = R0; /*orig_r0*/ \<br /> [--sp] = (R7:0,P5:0); \<br /> R0 = (N); \<br /> jump __common_int_entry;<br /><br />/* For timer interrupts, we need to save IPEND, since the user_mode<br /> macro accesses it to determine where to account time. */<br />#define TIMER_INTERRUPT_ENTRY(N) \<br /> [--sp] = SYSCFG; \<br /> \<br /> [--sp] = P0; /*orig_p0*/ \<br /> [--sp] = R0; /*orig_r0*/ \<br /> [--sp] = (R7:0,P5:0); \<br /> p0.l = lo(IPEND); \<br /> p0.h = hi(IPEND); \<br /> r1 = [p0]; \<br /> R0 = (N); \<br /> jump __common_int_entry;<br /><br /><br /><br />mach-common/interrupt.S<br />--------------------------------------------------------------------------------<br />/* Common interrupt entry code. First we do CLI, then push<br /> * RETI, to keep interrupts disabled, but to allow this state to be changed<br /> * by local_bh_enable.<br /> * R0 contains the interrupt number, while R1 may contain the value of IPEND,<br /> * or garbage if IPEND won't be needed by the ISR. */<br />__common_int_entry:<br /> [--sp] = fp;<br /> [--sp] = usp;<br /><br /> [--sp] = i0;<br /> [--sp] = i1;<br /> [--sp] = i2;<br /> [--sp] = i3;<br /><br /> [--sp] = m0;<br /> [--sp] = m1;<br /> [--sp] = m2;<br /> [--sp] = m3;<br /><br /> [--sp] = l0;<br /> [--sp] = l1;<br /> [--sp] = l2;<br /> [--sp] = l3;<br /><br /> [--sp] = b0;<br /> [--sp] = b1;<br /> [--sp] = b2;<br /> [--sp] = b3;<br /> [--sp] = a0.x;<br /> [--sp] = a0.w;<br /> [--sp] = a1.x;<br /> [--sp] = a1.w;<br /><br /> [--sp] = LC0;<br /> [--sp] = LC1;<br /> [--sp] = LT0;<br /> [--sp] = LT1;<br /> [--sp] = LB0;<br /> [--sp] = LB1;<br /><br /> [--sp] = ASTAT;<br /><br /> [--sp] = r0; /* Skip reserved */<br /> [--sp] = RETS;<br /> r2 = RETI;<br /> [--sp] = r2;<br /> [--sp] = RETX;<br /> [--sp] = RETN;<br /> [--sp] = RETE;<br /> [--sp] = SEQSTAT;<br /> [--sp] = r1; /* IPEND - R1 may or may not be set up before jumping here. */<br /><br /> /* Switch to other method of keeping interrupts disabled. */<br />#ifdef CONFIG_DEBUG_HWERR<br /> r1 = 0x3f;<br /> sti r1;<br />#else<br /> cli r1;<br />#endif<br /> [--sp] = RETI; /* orig_pc */<br /> /* Clear all L registers. */<br /> r1 = 0 (x);<br /> l0 = r1;<br /> l1 = r1;<br /> l2 = r1;<br /> l3 = r1;<br />#ifdef CONFIG_FRAME_POINTER<br /> fp = 0;<br />#endif<br /><br />#if ANOMALY_05000283 || ANOMALY_05000315<br /> cc = r7 == r7;<br /> p5.h = HI(CHIPID);<br /> p5.l = LO(CHIPID);<br /> if cc jump 1f;<br /> r7.l = W[p5];<br />1:<br />#endif<br /> r1 = sp;<br /> SP += -12;<br /> call _do_irq;<br /> SP += 12;<br /> call _return_from_int;<br />.Lcommon_restore_context:<br /> RESTORE_CONTEXT<br /> rti;<br /><br />/* Adam: ====================== do_irq() =========================*/<br />mach-common/ints-priority.c<br />----------------------------------------------------------------------<br />#ifdef CONFIG_DO_IRQ_L1<br />__attribute__((l1_text))<br />#endif<br />void do_irq(int vec, struct pt_regs *fp)<br />{<br /> if (vec == EVT_IVTMR_P) {<br /> vec = IRQ_CORETMR;<br /> } else {<br /> struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;<br /> struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;<br />#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)<br /> unsigned long sic_status[3];<br /><br /> sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();<br /> sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();<br />#ifdef CONFIG_BF54x<br /> sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();<br />#endif<br /> for (;; ivg++) {<br /> if (ivg >= ivg_stop) {<br /> atomic_inc(&num_spurious);<br /> return;<br /> }<br /> if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)<br /> break;<br /> }<br />#else<br /> unsigned long sic_status;<br /><br /> sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();<br /><br /> for (;; ivg++) {<br /> if (ivg >= ivg_stop) {<br /> atomic_inc(&num_spurious);<br /> return;<br /> } else if (sic_status & ivg->isrflag)<br /> break;<br /> }<br />#endif<br /> vec = ivg->irqno;<br /> }<br /> asm_do_IRQ(vec, fp);<br /><br />#ifdef CONFIG_KGDB<br /> kgdb_process_breakpoint();<br />#endif<br />}<br /><br />asm/kernel/irqchip.c<br />-----------------------------------------------------------------------------------<br />#ifdef CONFIG_DO_IRQ_L1<br />__attribute__((l1_text))<br />#endif<br />asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)<br />{<br /> struct pt_regs *old_regs;<br /> struct irq_desc *desc = irq_desc + irq;<br /> unsigned short pending, other_ints;<br /><br /> old_regs = set_irq_regs(regs);<br /><br /> /*<br /> * Some hardware gives randomly wrong interrupts. Rather<br /> * than crashing, do something sensible.<br /> */<br /> if (irq >= NR_IRQS)<br /> desc = &bad_irq_desc;<br /><br /> irq_enter();<br /><br /> generic_handle_irq(irq);<br /><br /> /* If we're the only interrupt running (ignoring IRQ15 which is for<br /> syscalls), lower our priority to IRQ14 so that softirqs run at<br /> that level. If there's another, lower-level interrupt, irq_exit<br /> will defer softirqs to that. */<br /> CSYNC();<br /> pending = bfin_read_IPEND() & ~0x8000;<br /> other_ints = pending & (pending - 1);<br /> if (other_ints == 0)<br /> lower_to_irq14();<br /> irq_exit();<br /><br /> set_irq_regs(old_regs);<br />}<br /><br />include/linux/irq.h:<br />----------------------------------------------------------------------------------------<br />/*<br /> * Architectures call this to let the generic IRQ layer<br /> * handle an interrupt. If the descriptor is attached to an<br /> * irqchip-style controller then we call the ->handle_irq() handler,<br /> * and it calls __do_IRQ() if it's attached to an irqtype-style controller.<br /> */<br />static inline void generic_handle_irq(unsigned int irq)<br />{<br /> struct irq_desc *desc = irq_desc + irq;<br /><br />#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ<br /> desc->handle_irq(irq, desc);<br />#else<br /> if (likely(desc->handle_irq))<br /> desc->handle_irq(irq, desc);<br /> else<br /> __do_IRQ(irq);<br />#endif<br />}<br /><br />/* Adam: =============== Global struct irq_desc irq_desc[NR_IRQS], struct irqchip ======== */<br /><br />kernel/irq/handle.c<br />-----------------------------------------------------------------------<br />/*<br /> * Linux has a controller-independent interrupt architecture.<br /> * Every controller has a 'controller-template', that is used<br /> * by the main code to do the right thing. Each driver-visible<br /> * interrupt source is transparently wired to the appropriate<br /> * controller. Thus drivers need not be aware of the<br /> * interrupt-controller.<br /> *<br /> * The code is designed to be easily extended with new/different<br /> * interrupt controllers, without having to do assembly magic or<br /> * having to touch the generic code.<br /> *<br /> * Controller mappings for all interrupt sources:<br /> */<br />struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {<br /> [0 ... NR_IRQS-1] = {<br /> .status = IRQ_DISABLED,<br /> .chip = &no_irq_chip,<br /> .handle_irq = handle_bad_irq,<br /> .depth = 1,<br /> .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),<br />#ifdef CONFIG_SMP<br /> .affinity = CPU_MASK_ALL<br />#endif<br /> }<br />};<br /><br />/**<br /> * struct irq_desc - interrupt descriptor<br /> *<br /> * @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()]<br /> * @chip: low level interrupt hardware access<br /> * @msi_desc: MSI descriptor<br /> * @handler_data: per-IRQ data for the irq_chip methods<br /> * @chip_data: platform-specific per-chip private data for the chip<br /> * methods, to allow shared chip implementations<br /> * @action: the irq action chain<br /> * @status: status information<br /> * @depth: disable-depth, for nested irq_disable() calls<br /> * @wake_depth: enable depth, for multiple set_irq_wake() callers<br /> * @irq_count: stats field to detect stalled irqs<br /> * @irqs_unhandled: stats field for spurious unhandled interrupts<br /> * @last_unhandled: aging timer for unhandled count<br /> * @lock: locking for SMP<br /> * @affinity: IRQ affinity on SMP<br /> * @cpu: cpu index useful for balancing<br /> * @pending_mask: pending rebalanced interrupts<br /> * @dir: /proc/irq/ procfs entry<br /> * @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP<br /> * @name: flow handler name for /proc/interrupts output<br /> */<br />struct irq_desc {<br /> irq_flow_handler_t handle_irq;<br /> struct irq_chip *chip;<br /> struct msi_desc *msi_desc;<br /> void *handler_data;<br /> void *chip_data;<br /> struct irqaction *action; /* IRQ action list */<br /> unsigned int status; /* IRQ status */<br /><br /> unsigned int depth; /* nested irq disables */<br /> unsigned int wake_depth; /* nested wake enables */<br /> unsigned int irq_count; /* For detecting broken IRQs */<br /> unsigned int irqs_unhandled;<br /> unsigned long last_unhandled; /* Aging timer for unhandled count */<br /> spinlock_t lock;<br />#ifdef CONFIG_SMP<br /> cpumask_t affinity;<br /> unsigned int cpu;<br />#endif<br />#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)<br /> cpumask_t pending_mask;<br />#endif<br />#ifdef CONFIG_PROC_FS<br /> struct proc_dir_entry *dir;<br />#endif<br /> const char *name;<br />} ____cacheline_internodealigned_in_smp;<br /><br /><br />arch/blackfin/mach-common/ints-priority.c:<br />------------------------------------------------------------<br />static struct irq_chip bfin_core_irqchip = {<br /> .ack = bfin_ack_noop,<br /> .mask = bfin_core_mask_irq,<br /> .unmask = bfin_core_unmask_irq,<br />};<br /><br />static struct irq_chip bfin_internal_irqchip = {<br /> .ack = bfin_ack_noop,<br /> .mask = bfin_internal_mask_irq,<br /> .unmask = bfin_internal_unmask_irq,<br /> .mask_ack = bfin_internal_mask_irq,<br /> .disable = bfin_internal_mask_irq,<br /> .enable = bfin_internal_unmask_irq,<br />#ifdef CONFIG_PM<br /> .set_wake = bfin_internal_set_wake,<br />#endif<br />};<br /><br />static struct irq_chip bfin_generic_error_irqchip = {<br /> .ack = bfin_ack_noop,<br /> .mask_ack = bfin_generic_error_mask_irq,<br /> .mask = bfin_generic_error_mask_irq,<br /> .unmask = bfin_generic_error_unmask_irq,<br />};<br /><br /><br />static struct irq_chip bfin_gpio_irqchip = {<br /> .ack = bfin_gpio_ack_irq,<br /> .mask = bfin_gpio_mask_irq,<br /> .mask_ack = bfin_gpio_mask_ack_irq,<br /> .unmask = bfin_gpio_unmask_irq,<br /> .set_type = bfin_gpio_irq_type,<br /> .startup = bfin_gpio_irq_startup,<br /> .shutdown = bfin_gpio_irq_shutdown,<br />#ifdef CONFIG_PM<br /> .set_wake = bfin_gpio_set_wake,<br />#endif<br />};<br /><br /><br />/* Adam: =============== How everything get initialized ======== */<br /><br />blackfin/kernel/irqchip.c:<br />-------------------------------------------------------<br />void __init init_IRQ(void)<br />{<br /> struct irq_desc *desc;<br /> int irq;<br /><br /> spin_lock_init(&irq_controller_lock);<br /> for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {<br /> *desc = bad_irq_desc;<br /> }<br /><br /> init_arch_irq();<br /><br />#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND<br /> /* Now that evt_ivhw is set up, turn this on */<br /> trace_buff_offset = 0;<br /> bfin_write_TBUFCTL(BFIN_TRACE_ON);<br /> printk(KERN_INFO "Hardware Trace expanded to %ik\n",<br /> 1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN);<br />#endif<br />}<br /><br />blackfin/mach-common/ints-prioirty.c<br />-------------------------------------------------------------<br />/*<br /> * This function should be called during kernel startup to initialize<br /> * the BFin IRQ handling routines.<br /> */<br />int __init init_arch_irq(void)<br />{<br /> int irq;<br /> unsigned long ilat = 0;<br /> /* Disable all the peripheral intrs - page 4-29 HW Ref manual */<br />#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)<br /> bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);<br /> bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);<br /># ifdef CONFIG_BF54x<br /> bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);<br /># endif<br />#else<br /> bfin_write_SIC_IMASK(SIC_UNMASK_ALL);<br />#endif<br /><br /> local_irq_disable();<br /><br />#ifdef CONFIG_BF54x<br /># ifdef CONFIG_PINTx_REASSIGN<br /> pint[0]->assign = CONFIG_PINT0_ASSIGN;<br /> pint[1]->assign = CONFIG_PINT1_ASSIGN;<br /> pint[2]->assign = CONFIG_PINT2_ASSIGN;<br /> pint[3]->assign = CONFIG_PINT3_ASSIGN;<br /># endif<br /> /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */<br /> init_pint_lut();<br />#endif<br /><br /> for (irq = 0; irq <= SYS_IRQS; irq++) {<br /> if (irq <= IRQ_CORETMR)<br /> set_irq_chip(irq, &bfin_core_irqchip);<br /> else<br /> set_irq_chip(irq, &bfin_internal_irqchip);<br /><br /> switch (irq) {<br />#if defined(CONFIG_BF53x)<br /> case IRQ_PROG_INTA:<br /># if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))<br /> case IRQ_MAC_RX:<br /># endif<br />#elif defined(CONFIG_BF54x)<br /> case IRQ_PINT0:<br /> case IRQ_PINT1:<br /> case IRQ_PINT2:<br /> case IRQ_PINT3:<br />#elif defined(CONFIG_BF52x)<br /> case IRQ_PORTF_INTA:<br /> case IRQ_PORTG_INTA:<br /> case IRQ_PORTH_INTA:<br />#elif defined(CONFIG_BF561)<br /> case IRQ_PROG0_INTA:<br /> case IRQ_PROG1_INTA:<br /> case IRQ_PROG2_INTA:<br />#endif<br /> set_irq_chained_handler(irq,<br /> bfin_demux_gpio_irq);<br /> break;<br />#ifdef BF537_GENERIC_ERROR_INT_DEMUX<br /> case IRQ_GENERIC_ERROR:<br /> set_irq_handler(irq, bfin_demux_error_irq);<br /><br /> break;<br />#endif<br /> default:<br /> set_irq_handler(irq, handle_simple_irq);<br /> break;<br /> }<br /> }<br /><br />#ifdef BF537_GENERIC_ERROR_INT_DEMUX<br /> for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)<br /> set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,<br /> handle_level_irq);<br />#endif<br /><br /> /* if configured as edge, then will be changed to do_edge_IRQ */<br /> for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++)<br /> set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,<br /> handle_level_irq);<br /><br /><br /> bfin_write_IMASK(0);<br /> CSYNC();<br /> ilat = bfin_read_ILAT();<br /> CSYNC();<br /> bfin_write_ILAT(ilat);<br /> CSYNC();<br /><br /> printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");<br /> /* IMASK=xxx is equivalent to STI xx or irq_flags=xx,<br /> * local_irq_enable()<br /> */<br /> program_IAR();<br /> /* Therefore it's better to setup IARs before interrupts enabled */<br /> search_IAR();<br /><br /> /* Enable interrupts IVG7-15 */<br /> irq_flags = irq_flags | IMASK_IVG15 |<br /> IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |<br /> IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;<br /><br />#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)<br /> bfin_write_SIC_IWR0(IWR_ENABLE_ALL);<br /> bfin_write_SIC_IWR1(IWR_ENABLE_ALL);<br /># ifdef CONFIG_BF54x<br /> bfin_write_SIC_IWR2(IWR_ENABLE_ALL);<br /># endif<br />#else<br /> bfin_write_SIC_IWR(IWR_ENABLE_ALL);<br />#endif<br /><br /> return 0;<br />}<br /><br />kernel/irq/chip.c:<br />------------------------------------------------------<br />/**<br /> * handle_simple_irq - Simple and software-decoded IRQs.<br /> * @irq: the interrupt number<br /> * @desc: the interrupt description structure for this irq<br /> *<br /> * Simple interrupts are either sent from a demultiplexing interrupt<br /> * handler or come from hardware, where no interrupt hardware control<br /> * is necessary.<br /> *<br /> * Note: The caller is expected to handle the ack, clear, mask and<br /> * unmask issues if necessary.<br /> */<br />void fastcall<br />handle_simple_irq(unsigned int irq, struct irq_desc *desc)<br />{<br /> struct irqaction *action;<br /> irqreturn_t action_ret;<br /> const unsigned int cpu = smp_processor_id();<br /><br /> spin_lock(&desc->lock);<br /><br /> if (unlikely(desc->status & IRQ_INPROGRESS))<br /> goto out_unlock;<br /> desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);<br /> kstat_cpu(cpu).irqs[irq]++;<br /><br /> action = desc->action;<br /> if (unlikely(!action || (desc->status & IRQ_DISABLED)))<br /> goto out_unlock;<br /><br /> desc->status |= IRQ_INPROGRESS;<br /> spin_unlock(&desc->lock);<br /><br /> action_ret = handle_IRQ_event(irq, action);<br /> if (!noirqdebug)<br /> note_interrupt(irq, desc, action_ret);<br /><br /> spin_lock(&desc->lock);<br /> desc->status &= ~IRQ_INPROGRESS;<br />out_unlock:<br /> spin_unlock(&desc->lock);<br />}<br /><br />/**<br /> * handle_level_irq - Level type irq handler<br /> * @irq: the interrupt number<br /> * @desc: the interrupt description structure for this irq<br /> *<br /> * Level type interrupts are active as long as the hardware line has<br /> * the active level. This may require to mask the interrupt and unmask<br /> * it after the associated handler has acknowledged the device, so the<br /> * interrupt line is back to inactive.<br /> */<br />void fastcall<br />handle_level_irq(unsigned int irq, struct irq_desc *desc)<br />{<br /> unsigned int cpu = smp_processor_id();<br /> struct irqaction *action;<br /> irqreturn_t action_ret;<br /><br /> spin_lock(&desc->lock);<br /> mask_ack_irq(desc, irq);<br /><br /> if (unlikely(desc->status & IRQ_INPROGRESS))<br /> goto out_unlock;<br /> desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);<br /> kstat_cpu(cpu).irqs[irq]++;<br /><br /> /*<br /> * If its disabled or no action available<br /> * keep it masked and get out of here<br /> */<br /> action = desc->action;<br /> if (unlikely(!action || (desc->status & IRQ_DISABLED)))<br /> goto out_unlock;<br /><br /> desc->status |= IRQ_INPROGRESS;<br /> spin_unlock(&desc->lock);<br /><br /> action_ret = handle_IRQ_event(irq, action);<br /> if (!noirqdebug)<br /> note_interrupt(irq, desc, action_ret);<br /><br /> spin_lock(&desc->lock);<br /> desc->status &= ~IRQ_INPROGRESS;<br /> if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)<br /> desc->chip->unmask(irq);<br />out_unlock:<br /> spin_unlock(&desc->lock);<br />}<br /><br />kernel/irq/handle.c:<br />------------------------------------------------------<br />/**<br /> * handle_IRQ_event - irq action chain handler<br /> * @irq: the interrupt number<br /> * @action: the interrupt action chain for this irq<br /> *<br /> * Handles the action chain of an irq event<br /> */<br />irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)<br />{<br /> irqreturn_t ret, retval = IRQ_NONE;<br /> unsigned int status = 0;<br /><br /> handle_dynamic_tick(action);<br /><br /> if (!(action->flags & IRQF_DISABLED))<br /> local_irq_enable_in_hardirq();<br /><br /> do {<br /> ret = action->handler(irq, action->dev_id);<br /> if (ret == IRQ_HANDLED)<br /> status |= action->flags;<br /> retval |= ret;<br /> action = action->next;<br /> } while (action);<br /><br /> if (status & IRQF_SAMPLE_RANDOM)<br /> add_interrupt_randomness(irq);<br /> local_irq_disable();<br /><br /> return retval;<br />}<br /><br /></code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-24072336160124457882008-05-08T21:09:00.000-07:002008-05-08T21:17:25.113-07:00Using expr<p><b>http://www.faqs.org/docs/abs/HTML/moreadv.html<br /></b></p><p><b>Example 12-6. Using <b class="COMMAND">expr</b></b></p><table bgcolor="#e0e0e0" border="0" width="90%"><tbody><tr><td><pre class="PROGRAMLISTING"> 1 #!/bin/bash<br /> 2<br /> 3 # Demonstrating some of the uses of 'expr'<br /> 4 # =======================================<br /> 5<br /> 6 echo<br /> 7<br /> 8 # Arithmetic Operators<br /> 9 # ---------- ---------<br /> 10<br /> 11 echo "Arithmetic Operators"<br /> 12 echo<br /> 13 a=`expr 5 + 3`<br /> 14 echo "5 + 3 = $a"<br /> 15<br /> 16 a=`expr $a + 1`<br /> 17 echo<br /> 18 echo "a + 1 = $a"<br /> 19 echo "(incrementing a variable)"<br /> 20<br /> 21 a=`expr 5 % 3`<br /> 22 # modulo<br /> 23 echo<br /> 24 echo "5 mod 3 = $a"<br /> 25<br /> 26 echo<br /> 27 echo<br /> 28<br /> 29 # Logical Operators<br /> 30 # ------- ---------<br /> 31<br /> 32 # Returns 1 if true, 0 if false,<br /> 33 #+ opposite of normal Bash convention.<br /> 34<br /> 35 echo "Logical Operators"<br /> 36 echo<br /> 37<br /> 38 x=24<br /> 39 y=25<br /> 40 b=`expr $x = $y` # Test equality.<br /> 41 echo "b = $b" # 0 ( $x -ne $y )<br /> 42 echo<br /> 43<br /> 44 a=3<br /> 45 b=`expr $a \> 10`<br /> 46 echo 'b=`expr $a \> 10`, therefore...'<br /> 47 echo "If a > 10, b = 0 (false)"<br /> 48 echo "b = $b" # 0 ( 3 ! -gt 10 )<br /> 49 echo<br /> 50<br /> 51 b=`expr $a \< 10`<br /> 52 echo "If a < 10, b = 1 (true)"<br /> 53 echo "b = $b" # 1 ( 3 -lt 10 )<br /> 54 echo<br /> 55 # Note escaping of operators.<br /> 56<br /> 57 b=`expr $a \<= 3`<br /> 58 echo "If a <= 3, b = 1 (true)"<br /> 59 echo "b = $b" # 1 ( 3 -le 3 )<br /> 60 # There is also a "\>=" operator (greater than or equal to).<br /> 61<br /> 62<br /> 63 echo<br /> 64 echo<br /> 65<br /> 66 # Comparison Operators<br /> 67 # ---------- ---------<br /> 68<br /> 69 echo "Comparison Operators"<br /> 70 echo<br /> 71 a=zipper<br /> 72 echo "a is $a"<br /> 73 if [ `expr $a = snap` ]<br /> 74 # Force re-evaluation of variable 'a'<br /> 75 then<br /> 76 echo "a is not zipper"<br /> 77 fi <br /> 78<br /> 79 echo<br /> 80 echo<br /> 81<br /> 82<br /> 83<br /> 84 # String Operators<br /> 85 # ------ ---------<br /> 86<br /> 87 echo "String Operators"<br /> 88 echo<br /> 89<br /> 90 a=1234zipper43231<br /> 91 echo "The string being operated upon is \"$a\"."<br /> 92<br /> 93 # length: length of string<br /> 94 b=`expr length $a`<br /> 95 echo "Length of \"$a\" is $b."<br /> 96<br /> 97 # index: position of first character in substring<br /> 98 # that matches a character in string<br /> 99 b=`expr index $a 23`<br />100 echo "Numerical position of first \"2\" in \"$a\" is \"$b\"."<br />101<br />102 # substr: extract substring, starting position & length specified<br />103 b=`expr substr $a 2 6`<br />104 echo "Substring of \"$a\", starting at position 2,\<br />105 and 6 chars long is \"$b\"."<br />106<br />107<br />108 # The default behavior of the 'match' operations is to<br />109 #+ search for the specified match at the ***beginning*** of the string.<br />110 #<br />111 # uses Regular Expressions<br />112 b=`expr match "$a" '[0-9]*'` # Numerical count.<br />113 echo Number of digits at the beginning of \"$a\" is $b.<br />114 b=`expr match "$a" '\([0-9]*\)'` # Note that escaped parentheses<br />115 # == == + trigger substring match.<br />116 echo "The digits at the beginning of \"$a\" are \"$b\"."<br />117<br />118 echo<br />119<br />120 exit 0</pre></td></tr></tbody></table><hr /><table class="IMPORTANT" border="0" width="90%"><tbody><tr><td align="center" valign="top" width="25"><img src="http://www.faqs.org/docs/abs/HTML/common/important.png" alt="Important" hspace="5" /></td><td align="left" valign="top"><p>The <a href="http://www.faqs.org/docs/abs/HTML/special-chars.html#NULLREF">:</a> operator can substitute for <b class="COMMAND">match</b>. For example, <tt class="USERINPUT"><b>b=`expr $a : [0-9]*`</b></tt> is the exact equivalent of <tt class="USERINPUT"><b>b=`expr match $a [0-9]*`</b></tt> in the above listing.</p><p><table bgcolor="#e0e0e0" border="0" width="90%"><tbody><tr><td><pre class="PROGRAMLISTING"> 1 #!/bin/bash<br /> 2<br /> 3 echo<br /> 4 echo "String operations using \"expr \$string : \" construct"<br /> 5 echo "==================================================="<br /> 6 echo<br /> 7<br /> 8 a=1234zipper5FLIPPER43231<br /> 9<br /> 10 echo "The string being operated upon is \"`expr "$a" : '\(.*\)'`\"."<br /> 11 # Escaped parentheses grouping operator. == ==<br /> 12<br /> 13 # ***************************<br /> 14 #+ Escaped parentheses<br /> 15 #+ match a substring<br /> 16 # ***************************<br /> 17<br /> 18<br /> 19 # If no escaped parentheses...<br /> 20 #+ then 'expr' converts the string operand to an integer.<br /> 21<br /> 22 echo "Length of \"$a\" is `expr "$a" : '.*'`." # Length of string<br /> 23<br /> 24 echo "Number of digits at the beginning of \"$a\" is `expr "$a" : '[0-9]*'`."<br /> 25<br /> 26 # ------------------------------------------------------------------------- #<br /> 27<br /> 28 echo<br /> 29<br /> 30 echo "The digits at the beginning of \"$a\" are `expr "$a" : '\([0-9]*\)'`."<br /> 31 # == ==<br /> 32 echo "The first 7 characters of \"$a\" are `expr "$a" : '\(.......\)'`."<br /> 33 # ===== == ==<br /> 34 # Again, escaped parentheses force a substring match.<br /> 35 #<br /> 36 echo "The last 7 characters of \"$a\" are `expr "$a" : '.*\(.......\)'`."<br /> 37 # ==== end of string operator ^^<br /> 38 # (actually means skip over one or more of any characters until specified<br /> 39 #+ substring)<br /> 40<br /> 41 echo<br /> 42<br /> 43 exit 0</pre></td></tr></tbody></table></p></td></tr></tbody></table>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-58329711734639391982008-05-08T20:59:00.000-07:002008-05-08T21:18:18.863-07:00regular expression<p>An expression is a string of characters. Those characters that have an interpretation above and beyond their literal meaning are called <span class="emphasis"><i class="EMPHASIS">metacharacters</i></span>. A quote symbol, for example, may denote speech by a person, <span class="emphasis"><i class="EMPHASIS">ditto</i></span>, or a meta-meaning for the symbols that follow. Regular Expressions are sets of characters and/or metacharacters that UNIX endows with special features. <a name="AEN12124" href="http://www.faqs.org/docs/abs/HTML/regexp.html#FTN.AEN12124">[1]</a> </p><p>The main uses for Regular Expressions (REs) are text searches and string manipulation. An RE <i class="FIRSTTERM">matches</i> a single character or a set of characters (a substring or an entire string).</p><ul><li><p>The asterisk -- <span class="TOKEN">*</span> -- matches any number of repeats of the character string or RE preceding it, <span class="emphasis"><i class="EMPHASIS">including zero</i></span>.</p><p><span class="QUOTE">"1133*"</span> matches <tt class="REPLACEABLE"><i>11 + one or more 3's + possibly other characters</i></tt>: <tt class="REPLACEABLE"><i>113</i></tt>, <tt class="REPLACEABLE"><i>1133</i></tt>, <tt class="REPLACEABLE"><i>111312</i></tt>, and so forth.</p></li><li><p><a name="REGEXDOT"></a>The dot -- <span class="TOKEN">.</span> -- matches any one character, except a newline. <a name="AEN12153" href="http://www.faqs.org/docs/abs/HTML/regexp.html#FTN.AEN12153">[2]</a> </p><p><span class="QUOTE">"13."</span> matches <tt class="REPLACEABLE"><i>13 + at least one of any character (including a space)</i></tt>: <tt class="REPLACEABLE"><i>1133</i></tt>, <tt class="REPLACEABLE"><i>11333</i></tt>, but not <tt class="REPLACEABLE"><i>13</i></tt> (additional character missing).</p></li><li><p>The caret -- <span class="TOKEN">^</span> -- matches the beginning of a line, but sometimes, depending on context, negates the meaning of a set of characters in an RE. </p></li><li><p><a name="DOLLARSIGNREF"></a></p><p>The dollar sign -- <span class="TOKEN">$</span> -- at the end of an RE matches the end of a line.</p><p><span class="QUOTE">"^$"</span> matches blank lines.</p><div class="NOTE"><table class="NOTE" border="0" width="90%"><tbody><tr><td align="center" valign="top" width="25"><img src="http://www.faqs.org/docs/abs/HTML/common/note.png" alt="Note" hspace="5" /></td><td align="left" valign="top"><p>The <span class="TOKEN">^</span> and <span class="TOKEN">$</span> are known as <span class="emphasis"><i class="EMPHASIS">anchors</i></span>, since they indicate or anchor a position within an RE.</p></td></tr></tbody></table></div></li><li><p><a name="BRACKETSREF"></a></p><p>Brackets -- <span class="TOKEN">[...]</span> -- enclose a set of characters to match in a single RE.</p><p><span class="QUOTE">"[xyz]"</span> matches the characters <tt class="REPLACEABLE"><i>x</i></tt>, <tt class="REPLACEABLE"><i>y</i></tt>, or <tt class="REPLACEABLE"><i>z</i></tt>.</p><p><span class="QUOTE">"[c-n]"</span> matches any of the characters in the range <tt class="REPLACEABLE"><i>c</i></tt> to <tt class="REPLACEABLE"><i>n</i></tt>.</p><p><span class="QUOTE">"[B-Pk-y]"</span> matches any of the characters in the ranges <tt class="REPLACEABLE"><i>B</i></tt> to <tt class="REPLACEABLE"><i>P</i></tt> and <tt class="REPLACEABLE"><i>k</i></tt> to <tt class="REPLACEABLE"><i>y</i></tt>.</p><p><span class="QUOTE">"[a-z0-9]"</span> matches any lowercase letter or any digit.</p><p><span class="QUOTE">"[^b-d]"</span> matches all characters <span class="emphasis"><i class="EMPHASIS">except</i></span> those in the range <tt class="REPLACEABLE"><i>b</i></tt> to <tt class="REPLACEABLE"><i>d</i></tt>. This is an instance of <span class="TOKEN">^</span> negating or inverting the meaning of the following RE (taking on a role similar to <span class="TOKEN">!</span> in a different context).</p><p>Combined sequences of bracketed characters match common word patterns. <span class="QUOTE">"[Yy][Ee][Ss]"</span> matches <tt class="REPLACEABLE"><i>yes</i></tt>, <tt class="REPLACEABLE"><i>Yes</i></tt>, <tt class="REPLACEABLE"><i>YES</i></tt>, <tt class="REPLACEABLE"><i>yEs</i></tt>, and so forth. <span class="QUOTE">"[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]"</span> matches any Social Security number.</p></li><li><p>The backslash -- <span class="TOKEN">\</span> -- <a href="http://www.faqs.org/docs/abs/HTML/quoting.html#ESCP">escapes</a> a special character, which means that character gets interpreted literally.</p><p>A <span class="QUOTE">"\$"</span> reverts back to its literal meaning of <span class="QUOTE">"$"</span>, rather than its RE meaning of end-of-line. Likewise a <span class="QUOTE">"\\"</span> has the literal meaning of <span class="QUOTE">"\"</span>.</p></li><li><p><a name="ANGLEBRAC"></a></p><p><a href="http://www.faqs.org/docs/abs/HTML/quoting.html#ESCP">Escaped</a> <span class="QUOTE">"angle brackets"</span> -- <span class="TOKEN">\<...\></span> -- mark word boundaries.</p><p>The angle brackets must be escaped, since otherwise they have only their literal character meaning.</p><p><span class="QUOTE">"\<the\>"</span> matches the word <span class="QUOTE">"the"</span>, but not the words <span class="QUOTE">"them"</span>, <span class="QUOTE">"there"</span>, <span class="QUOTE">"other"</span>, etc.</p><p> <table bgcolor="#e0e0e0" border="0" width="90%"><tbody><tr><td><pre class="SCREEN"> <tt class="PROMPT">bash$ </tt><tt class="USERINPUT"><b>cat textfile</b></tt><br /><tt class="COMPUTEROUTPUT">This is line 1, of which there is only one instance.<br />This is the only instance of line 2.<br />This is line 3, another line.<br />This is line 4.</tt><br /><br /><br /><tt class="PROMPT">bash$ </tt><tt class="USERINPUT"><b>grep 'the' textfile</b></tt><br /><tt class="COMPUTEROUTPUT">This is line 1, of which there is only one instance.<br />This is the only instance of line 2.<br />This is line 3, another line.</tt><br /><br /><br /><tt class="PROMPT">bash$ </tt><tt class="USERINPUT"><b>grep '\<the\>' textfile</b></tt><br /><tt class="COMPUTEROUTPUT">This is the only instance of line 2.</tt><br /> </pre></td></tr></tbody></table> </p></li></ul><ul><li style="list-style-type: square;"><div class="FORMALPARA"><p><b><a name="EXTREGEX"></a>Extended REs. </b>Used in <a href="http://www.faqs.org/docs/abs/HTML/textproc.html#EGREPREF">egrep</a>, <a href="http://www.faqs.org/docs/abs/HTML/awk.html#AWKREF">awk</a>, and <a href="http://www.faqs.org/docs/abs/HTML/wrapper.html#PERLREF">Perl</a></p></div></li><li><p><a name="QUEXREGEX"></a></p><p>The question mark -- <span class="TOKEN">?</span> -- matches zero or one of the previous RE. It is generally used for matching single characters.</p></li><li><p><a name="PLUSREF"></a></p><p>The plus -- <span class="TOKEN">+</span> -- matches one or more of the previous RE. It serves a role similar to the <span class="TOKEN">*</span>, but does <span class="emphasis"><i class="EMPHASIS">not</i></span> match zero occurrences.</p><p><table bgcolor="#e0e0e0" border="0" width="90%"><tbody><tr><td><pre class="PROGRAMLISTING"> 1 # GNU versions of sed and awk can use "+",<br /> 2 # but it needs to be escaped.<br /> 3<br /> 4 echo a111b | sed -ne '/a1\+b/p'<br /> 5 echo a111b | grep 'a1\+b'<br /> 6 echo a111b | gawk '/a1+b/'<br /> 7 # All of above are equivalent.<br /> 8<br /> 9 # Thanks, S.C.</pre></td></tr></tbody></table></p></li><li><p><a href="http://www.faqs.org/docs/abs/HTML/quoting.html#ESCP">Escaped</a> <span class="QUOTE">"curly brackets"</span> -- <span class="TOKEN">\{ \}</span> -- indicate the number of occurrences of a preceding RE to match.</p><p>It is necessary to escape the curly brackets since they have only their literal character meaning otherwise. This usage is technically not part of the basic RE set.</p><p><span class="QUOTE">"[0-9]\{5\}"</span> matches exactly five digits (characters in the range of 0 to 9).</p><div class="NOTE"><table class="NOTE" border="0" width="90%"><tbody><tr><td align="center" valign="top" width="25"><img src="http://www.faqs.org/docs/abs/HTML/common/note.png" alt="Note" hspace="5" /></td><td align="left" valign="top"><p>Curly brackets are not available as an RE in the <span class="QUOTE">"classic"</span> (non-POSIX compliant) version of <a href="http://www.faqs.org/docs/abs/HTML/awk.html#AWKREF">awk</a>. However, <b class="COMMAND">gawk</b> has the <tt class="OPTION">--re-interval</tt> option that permits them (without being escaped).</p><p> <table bgcolor="#e0e0e0" border="0" width="90%"><tbody><tr><td><pre class="SCREEN"> <tt class="PROMPT">bash$ </tt><tt class="USERINPUT"><b>echo 2222 | gawk --re-interval '/2{3}/'</b></tt><br /><tt class="COMPUTEROUTPUT">2222</tt><br /> </pre></td></tr></tbody></table> </p><p><b class="COMMAND">Perl</b> and some <b class="COMMAND">egrep</b> versions do not require escaping the curly brackets.</p></td></tr></tbody></table></div></li><li><p>Parentheses -- <b class="COMMAND">( )</b> -- enclose groups of REs. They are useful with the following <span class="QUOTE">"<span class="TOKEN">|</span>"</span> operator and in <a href="http://www.faqs.org/docs/abs/HTML/string-manipulation.html#EXPRPAREN">substring extraction</a> using <a href="http://www.faqs.org/docs/abs/HTML/moreadv.html#EXPRREF">expr</a>.</p></li><li><p>The -- <b class="COMMAND">|</b> -- <span class="QUOTE">"or"</span> RE operator matches any of a set of alternate characters.</p><p> <table bgcolor="#e0e0e0" border="0" width="90%"><tbody><tr><td><pre class="SCREEN"> <tt class="PROMPT">bash$ </tt><tt class="USERINPUT"><b>egrep 're(a|e)d' misc.txt</b></tt><br /><tt class="COMPUTEROUTPUT">People who read seem to be better informed than those who do not.<br />The clarinet produces sound by the vibration of its reed.</tt><br /> </pre></td></tr></tbody></table></p></li></ul>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-89409162946176315392008-05-07T20:54:00.000-07:002008-05-08T21:19:48.512-07:00find & xargshttp://www.kalamazoolinux.org/tech/find.html<br /><br /><center> <h1>find & xargs</h1> <h3>Part of the reason why the Linux command line is so POWERFUL!</h3> </center> <p> Finding files can be a daunting task, given the vast number of files on your average Linux filesystem. The number of system files in an average Linux install is well into the tens of thousands, or even hundreds of thousands of files. That's not counting user files! </p><p> The command `find` is, as it's name implies, used to aid you in finding files you are looking for, anywhere in your filesystems. Plus much more (see below). </p><p> </p><h3>find can use a large number of other criteria to find a file.</h3> <p> </p><ul><li>The first argument to "find" is the directory (or directories) to perform the search. <ul><li>Example: find (and display) every file in your home directory: <ul><li><b>find $HOME</b></li></ul></li></ul> <p> </p></li><li>"-name" the name of a file, or a partial name (basic regex). <ul><li>Example: find the file named "bookmarks.html" in your home directory: <ul><li><b>find $HOME -name bookmarks.html</b></li></ul></li></ul> <ul><li>Example: find all files starting with the name "bookmarks" in your home directory: <ul><li><b>find $HOME -name bookmarks\*</b> <ul><li>Characters that mean something special to the shell, like the asterisk must<br /> be escaped with a backslash or put in single quotes, to avoid problems.</li></ul></li></ul></li></ul> <p> </p></li><li>"-atime/-ctime/-mtime" the last time a files's "access time", "file status" and "modification time",<br />measured in days or minutes. The time can be compared to another file with "-newer/-anewer/-cnewer". <ul><li>Example: find everything in your home directory modified in the last 24 hours: <ul><li><b>find $HOME -mtime 0 </b></li></ul></li></ul> <ul><li>Example: find everything in your home directory modified in the last 7 days: <ul><li><b>find $HOME -mtime -7 </b></li></ul></li></ul> <ul><li>Example: find everything in your home directory that have NOT been modified in the last year: <ul><li><b>find $HOME -mtime +365 </b></li></ul></li></ul> <ul><li>Example: find everything in your home that has been modified more recently than "abc.txt": <ul><li><b>find $HOME -newer klug/find.html </b></li></ul></li></ul> <p> </p></li><li>"-type x" files of a certain type (file, directory, symlink, socket, pipe, block, character) (fdlspbc) <ul><li>Example: find all directories under /tmp <ul><li><b>find /tmp -type d</b></li></ul></li></ul> <p> </p></li><li>"-user" files owned by a certain user. <ul><li>Example: find all files owned by user "bruce" under /var <ul><li><b>find /var -user bruce</b></li></ul></li></ul> <p> </p></li><li>"-group" files which are a member of a certain group. <ul><li>Example: find all files in group "users" under /var <ul><li><b>find /var -group users</b></li></ul></li></ul> <p> </p></li><li>"-size" files of a certain size. <ul><li>Size can be specified in blocks, bytes, works, Kilobytes, Megabytes or Gigabytes (bcwkMG). </li><li>Example: find all files in your home directory exactly 100 bytes long: <ul><li><b>find $HOME -size 100c</b></li></ul> </li><li>Example: find all files in your home directory smaller than 100 bytes: <ul><li><b>find $HOME -size -100c</b></li></ul> </li><li>Example: find all files in your home directory larger than 100MB: <ul><li><b>find $HOME -size +100M</b></li></ul> </li></ul> <p> </p></li><li>"-perm" files that has certain permissions, or has individual bits set or not set. <ul><li>Example: find all files in your root directory that are SUID. <ul><li><b>find / -xdev -type f -perm +4000</b></li></ul> </li><li>Example: find all files in your root directory that are SUID-root. <ul><li><b>find / -xdev -type f -user root -perm +4000</b></li></ul></li></ul> <p> </p><p> </p></li><li>"-links" files that has a certain number of hard links. <ul><li>Example: find all <i>files</i> in your home directory with a hard link count of two: <ul><li><b>find $HOME -type f -links 2</b></li></ul></li></ul> <ul><li>Example: find all <i>files</i> in your home directory with more than one hard link: <ul><li><b>find $HOME -type f -links +1</b></li></ul></li></ul> <p> </p></li><li>"-inum" a file with a certain `inum`, useful in filesystem debugging and locating identical hard linked files. <ul><li>Example: find file with inum=114300 in the /home partition: <ul><li><b>find /home -inum 114300</b></li></ul></li></ul> </li></ul> <p> </p><h3>find can perform a number of actions on the file(s) it finds.</h3> <ul><li>"-print" prints the names of the files it finds. This is the default if no other actions are specified.<br /> These two commands are identical on recent Linux systems: <ul><li><b>find $HOME -name bookmarks.html</b><br /> <b>find $HOME -name bookmarks.html -print</b></li></ul> <ul><li>Variations include:<ul><li>"-ls" to display detailed output instead of just filename ("ls -dils" format). </li><li>"-fprint" to send the output to a file instead of stdout.<br /> </li><li>"-printf" to format the output in a specific way.<br /> </li><li>"-fprintf" a combination of the above two.</li></ul></li></ul> <p> </p></li><li>"-print0" Same as -print, except it separates files by a null character (ascii 0) instead of a newline.<br /> Although the usefulness of this may not be immediately obvious, it is extremely useful!<br /> See examples below. (the argument ends in the number ZERO, not the letter O) <ul><li>Variations include: <ul><li>"-fprint0" to send output to a file instead of stdout.</li></ul></li></ul> <p> </p></li><li>"-delete" will delete all files it finds. Use with care! :-) <ul><li>Example: delete all files named "core" in the /tmp directory: <ul><li><b>find /tmp -type f -name core -delete</b></li></ul></li></ul> <p> </p></li><li>"-exec" will execute any command on the files found. <ul><li>Use "{}" to specify the filename found in the command. </li><li>End the command with a ";" (escape it!) to execute the command every time a file is found. </li><li>End the command with a "+" to pass multiple files to the command (like xargs). </li></ul> <ul><li>Variations include: <ul><li>"-execdir" to execute the command in it's directory (instead of the current directory) </li><li>"-ok" to ask the user for each file found if the command should be executed. </li><li>"-okdir" ask the user and execute in the file's directory. </li></ul> </li></ul> </li></ul> <p> </p><h3>Other useful find parameters:</h3> <ul><p> </p><li>"-xdev" Don't descend directories on other filesystems. <ul><li>Useful for searching a single hard drive partition and omitting other HDD partitions, /proc,<br /> CDROM's, network mounts, etc. (network drives and CD's can be really slow to search)</li></ul> <p> </p></li><li>"-maxdepth <i>n</i>" Descend at most <i>n</i> directory levels. (cannot be negative) <p> </p></li><li>"-mindepth <i>n</i>" Do not apply tests or actions at levels less than <i>n</i> (non-negative). <p> </p></li><li>"-daystart" perform time tests from beginning of today, instead of current date/time. <p> </p></li><li>"-L" follow symbolic links (does not follow symlinks by default). <p> </p></li><li>"-fstype <i>x</i>" only find files a filesystems of type <i>x</i>. <ul><li>Useful for searching hard drive partitions and omitting CDROM's, network mounts, etc.</li></ul> <p> </p></li><li>"-regex <i>pattern</i>" use full regular expressions. <ul><li>Variations include: <ul><li>"-iregex" case insensitive regex.</li></ul></li></ul> <p> </p></li><li>"-depth" Process each directory's contents before the directory itself <ul><li>Useful for removing, since the directory has to be empty before it can be removed</li></ul> <p> </p></li><li>"-noleaf" Do not optimize by assuming that directories contain 2 fewer subdirectories than their hard link count. <ul><li>The default optimization improves speed significantly on Unix filesystems.<br /> However it doesn't work so well on other filesystems (DOS, CDROM, etc.), hence this option.</li></ul> </li></ul> <p> </p><h3>OPERATORS</h3> <ul><li>"! <i>expr</i>" True if <i>expr</i> is false. (logical NOT) <p> </p></li><li>"( <i>expr</i> )" Force precedence. <p> </p></li><li>"<i>expr1</i> -a <i>expr2</i>" Logical AND (default operation, not necessary) <p> </p></li><li>"<i>expr1</i> -o <i>expr2</i>" Logical OR. <p> </p></li><li>"<i>expr1</i> , <i>expr2</i>" For different searches while traversing the filesystem hierarchy only once.<br /> Must be used with parenthesis and -fprint to save separate outputs. </li></ul> <p> </p><h2>Examples:</h2> <ul><li>Display all jpg files in the top two levels of your home directory: <ul><li><b>find $HOME -maxdepth 2 -name \*jpg -print -exec xv {} \;</b></li></ul> <ul><li><b>find $HOME -maxdepth 2 -name '*jpg' -print -exec xv {} +</b></li></ul> <ul><li><b>find $HOME -maxdepth 2 -name '*jpg' -print0 | xargs -0 xv</b></li></ul> <p> </p></li><li>cron job to make all files & directories world readable/writable in common area: <ul><li><b>find /somedir/common -type f -exec chmod a+wr {} \;<br /> find /somedir/common -type d -exec chmod 777 {} \;</b></li></ul> <p> </p></li><li>cron job to force correct owner/group/permissions on certain files: <ul><li><b>find $BSE/lib/user \( -name '[p,u]*' -a -type f -a ! -perm 664 \) -exec chmod 664 {} \;<br /> find $BSE/lib/user \( -name 'd*' -a -type f -a ! -perm 666 \) -exec chmod 666 {} \;<br /> find $BSE/lib/user \( -type f -a ! -user bsp \) -exec chown bsp {} \;<br /> find $BSE/lib/user \( -type f -a ! -group programs \) -exec chgrp programs {} \;</b></li></ul> <p> </p></li><li>cron job to delete some old log files and keep record of files removed: <ul><li><b>find /var/opt/hparray/log -mtime +30 -print -exec rm -f {} \; >> $logf 2> /dev/null</b></li></ul> <p> </p></li><li>cron job to delete some old temp files and keep record of files removed: <ul><li><b>find / -name core -type f -fstype xfs -print -exec rm -f {} \; >> $logf 2> /dev/null<br /> find /var/tmp -mtime +1 -name '*aaa*' -print -exec rm -f {} \; >> $logf 2> /dev/null<br /> find /var/tmp -mtime +1 -name 'srt*' -print -exec rm -f {} \; >> $logf 2> /dev/null<br /> find /var/tmp -mtime +7 -print -exec rm -f {} \; >> $logf 2> /dev/null</b></li></ul> <p> </p></li><li>Traverse /var only once, listing setuid files and directories into /root/suid.txt<br /> and large files into /root/big/txt. (example taken from the find man page): <ul><li><b>find /var \( -perm +4000 -fprintf /root/suid.txt '%#m %u %p\n' \) , \<br /> \( -size +100M -fprintf /root/big.txt '%-10s %p\n' \)</b></li></ul> </li></ul> <p> </p><h2>xargs</h2> <ul><p> </p><li>Why do we need this "xargs" thing? It's in the presentation title! :-)<br /> Answer: Speed and efficiency. <ul><li>The second line runs much faster than the first for a large number of files: <ul><li><b>find / -name core -exec rm -f {} \;</b> </li><li><b>rm -f $(find / -name core -print)</b><br /> </li></ul> In other words, running "rm" once, with all the filenames on the command line<br /> is much faster than running "rm" multiple times, once for each file. </li><li>However, the second line could fail if the number of files is very large and<br /> exceeds the maximum number of characters allowed in a single command. </li><li>"xargs" will combine the single line output of find and run commands with multiple<br /> arguments, multiple times if necessary to avoid the max chars per line limit. <ul><li><b>find / -name core -print | xargs rm -f</b></li></ul> </li><li>The simplest way to see what xargs does, is to run some simple commands: <ul><li><b>find $HOME -maxdepth 2 -name \*.jpg -exec echo {} \; </b></li><li><b>find $HOME -maxdepth 2 -name \*.jpg | xargs echo</b> </li></ul> </li></ul> <p> </p></li><li><b>Enter the power of ZERO!</b> <ul><li>The 2nd command will fail if any of the files contain a space or other special character: <ul><li><b>find $HOME -maxdepth 2 -name \*.jpg -exec ls {} \; </b></li><li><b>find $HOME -maxdepth 2 -name \*.jpg | xargs ls</b> </li></ul> </li><li>Delimiting the file names with NULL fixes the problem: <ul><li><b>find $HOME -maxdepth 2 -name \*.jpg -print0 | xargs -0 ls</b></li></ul> </li></ul> <p> </p></li><li><b>Real world example of a very useful set of commands:</b> (This happens to me all the time) <ul><li>Our "webmaster" comes to me and asks if I can "find" all the web pages<br /> that contain the graphic file "ArmstrongISS.jpg" so they can edit those pages. <ul><li><b>find /home/httpd \( -name \*.html -o -name \*.php -o -name \*.php3 \) -print0 \<br /> | xargs -0 grep -l "ArmstrongISS.jpg"</b></li></ul> Note: add a "-i" parameter to "grep" for a case insensitive search on the string. </li><li>The above example alone is worth more than double the price of admission! :-)<br /> Not only does it find files by name, it only displays file names containing a certain string!<br /> When combining "find" with other Linux commands (like grep) and it's potential use in shell<br /> scripts, the power is only limited by your imagination! (and your command line skills). :-)<br /> </li><li>Similar examples to demo on my local system: <ul><li><b>find $HOME \( -name \*txt -o -name \*html \) -print0 | xargs -0 grep -li vpn</b> </li><li><b>find $HOME \( -name \*txt -o -name \*html \) -exec grep -li vpn {} +</b></li></ul> </li></ul> </li></ul> <p> </p><h3>Miscellaneous</h3> <p> </p><ul><li>Always read the man page for "find" & "xargs" on the system where you plan on using it.<br /> "find" has been around for a long time, but is still evolving at a rapid rate. <ul><li>Some arguments are fairly new, and may not exist on some older systems,<br /> and some commercial Unix systems. <ul><li>Some parameters, like "-delete" and -exec followed by a plus sign ("+"),<br /> are REALLY NEW. (Neither existed in the SuSE 9.2 "find"!) </li><li>Other parameters may be named something completely different on<br /> commerical Unix systems (i.e. "-fstype" == "-fsonly" on HPUX) </li><li>Older versions of "find" did NOT have "-print" as the default action.<br /> In fact there was no default, so running find without any action did<br /> nothing noticeable (except use CPU time and grind the hard drive)! </li></ul></li></ul> <p> </p></li><li>Always test your commands using "-exec echo" before invoking real commands,<br /> especially destructive commands like removing files! :-) <p> </p></li><li>Honorable mention: "locate". <ul><li>The "locate" package comes with most distributions. <ul><li>Installs by default on Redhat/Fedora systems. </li><li>Comes with SuSE, but does not install by default.</li></ul> </li><li>"Locate" consists of a cron job that runs nightly (by default),<br /> and stores all filenames on your system in a searchable database. </li><li>Simply type "locate <i>filename</i>" to find the location (directory) of a file. </li><li>Is MUCH faster than using "find" on your entire directory structure, but only<br /> tells you where files live. It has none of the extra functionality of "find". </li><li>Using the right tool for the job, "locate" is faster than "find" when you are<br /> only looking for the locations of files (or where they lived as of yesterday). </li></ul> <p> </p></li><li>Any [more] questions? <ul><li>Note to self: if this went too quickly, read the "find" man page out-loud very slowly! :-)</li></ul> <p> </p></li><li>Fin. </li></ul>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-12225353382466754522008-05-05T23:59:00.000-07:002008-05-08T21:39:01.331-07:00blackfin system call<pre><code> /* Adam:<br /><br />uclibc: syscall()<br /> ---> excpt 0;<br /><br />HW: EVT3 --> trap()<br /> jump _ex_table()->_ex_syscall;<br /> --> raise 15;<br /><br />HW: EVT15 --> evt_system_call()<br /> call (real system call)<br />*/<br /><br />uClibc/libc/sysdeps/linux/bfin/syscall.c:<br />------------------------------------------<br />long syscall(long sysnum, long a, long b, long c, long d, long e, long f)<br />{<br /> int _r0 = 0;<br /><br /> __asm__ __volatile__ (<br /> "R5 = %7;"<br /> "R4 = %6;"<br /> "R3 = %5;"<br /> "R2 = %4;"<br /> "R1 = %3;"<br /> "R0 = %2;"<br /> "P0 = %1;"<br /> "excpt 0;"<br /> "%0 = R0;"<br /> : "=r" (_r0)<br /> : "rm" (sysnum),<br /> "rm" (a),<br /> "rm" (b),<br /> "rm" (c),<br /> "rm" (d),<br /> "rm" (e),<br /> "rm" (f)<br /> : "memory","CC","R0","R1","R2","R3","R4","R5","P0");<br /><br /> if (_r0 >= (unsigned long) -4095) {<br /> (*__errno_location()) = (-_r0);<br /> _r0 = (unsigned long) -1;<br /> }<br /><br /> return (long)_r0;<br />}<br /><br />/* Adam:<br />excpt 0;<br /><br />The Force Exception instruction forces an exception with code uimm4.<br />When the EXCPT instruction is issued, the sequencer vectors to the excep-<br />tion handler that the user provides.<br /><br />start_kernel()<br /> ---> trap_init()<br /><br />setup_arch()<br /> --> init_exception_vectors()<br />*/<br /><br /><br />mach-common/ints-priority.c:<br />-----------------------------<br />void __init init_exception_vectors(void)<br />{<br /> SSYNC();<br /><br /> /* cannot program in software:<br /> * evt0 - emulation (jtag)<br /> * evt1 - reset<br /> */<br /> bfin_write_EVT2(evt_nmi);<br /> bfin_write_EVT3(trap);<br /> bfin_write_EVT5(evt_ivhw);<br /> bfin_write_EVT6(evt_timer);<br /> bfin_write_EVT7(evt_evt7);<br /> bfin_write_EVT8(evt_evt8);<br /> bfin_write_EVT9(evt_evt9);<br /> bfin_write_EVT10(evt_evt10);<br /> bfin_write_EVT11(evt_evt11);<br /> bfin_write_EVT12(evt_evt12);<br /> bfin_write_EVT13(evt_evt13);<br /> bfin_write_EVT14(evt14_softirq);<br /> bfin_write_EVT15(evt_system_call);<br /> CSYNC();<br />}<br /><br />arch/blackfin/kernel/traps.c:<br />-----------------------------<br /><br />/* Initiate the event table handler */<br />void __init trap_init(void)<br />{<br /> CSYNC();<br /> bfin_write_EVT3(trap);<br /> CSYNC();<br />}<br /><br />/* Adam:<br />EVT3: The 4th entry of event table is for exception.<br /><br />"excpt 0;" will finally jump here:<br />*/<br />arch/blackfin/mach-common/entry.S:<br />------------------------------------<br /><br />ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/<br /> /* Since the kernel stack can be anywhere, it's not guaranteed to be<br /> * covered by a CPLB. Switch to an exception stack; use RETN as a<br /> * scratch register (for want of a better option).<br /> */<br /> EX_SCRATCH_REG = sp;<br /> sp.l = _exception_stack_top;<br /> sp.h = _exception_stack_top;<br /> /* Try to deal with syscalls quickly. */<br /> [--sp] = ASTAT;<br /> [--sp] = (R7:6,P5:4);<br /> r7 = SEQSTAT; /* reason code is in bit 5:0 */<br /> r6.l = lo(SEQSTAT_EXCAUSE);<br /> r6.h = hi(SEQSTAT_EXCAUSE);<br /> r7 = r7 & r6;<br /> p5.h = _ex_table;<br /> p5.l = _ex_table;<br /> p4 = r7;<br /> p5 = p5 + (p4 << p4 =" [p5];" r7 =" -ENOSYS;" astat =" [sp++];" sp =" EX_SCRATCH_REG;" fp =" 0;" l =" lo(IPEND);" h =" hi(IPEND);" r0 =" [p2];" r0 =" rets;" r7 =" sp;" l =" lo(ALIGN_PAGE_MASK);" h =" hi(ALIGN_PAGE_MASK);" r7 =" r7" p2 =" r7;" p2 =" [p2];" r7 =" __NR_syscall;" r6 =" p0;" cc =" r6" r7 =" sp;" l =" lo(ALIGN_PAGE_MASK);" h =" hi(ALIGN_PAGE_MASK);" r7 =" r7" p2 =" r7;" r7 =" [p2+TI_FLAGS];" cc =" BITTST(r7,TIF_SYSCALL_TRACE);" p4 =" p0;" l =" _sys_call_table;" h =" _sys_call_table;" p5 =" p5" r0 =" [sp" r1 =" [sp" r2 =" [sp" p5 =" [p5];" r7 =" sp;" l =" lo(ALIGN_PAGE_MASK);" h =" hi(ALIGN_PAGE_MASK);" r7 =" r7">flags */<br /> p5 = r7;<br />.Lresume_userspace_1:<br /> /* Disable interrupts. */<br /> [--sp] = reti;<br /> reti = [sp++];<br /><br /> r7 = [p5 + TI_FLAGS];<br /> r4.l = lo(_TIF_WORK_MASK);<br /> r4.h = hi(_TIF_WORK_MASK);<br /> r7 = r7 & r4;<br /><br />.Lsyscall_resched:<br /> cc = BITTST(r7, TIF_NEED_RESCHED);<br /> if !cc jump .Lsyscall_sigpending;<br /><br /> /* Reenable interrupts. */<br /> [--sp] = reti;<br /> r0 = [sp++];<br /><br /> SP += -12;<br /> call _schedule;<br /> SP += 12;<br /><br /> jump .Lresume_userspace_1;<br /><br />.Lsyscall_sigpending:<br /> cc = BITTST(r7, TIF_RESTORE_SIGMASK);<br /> if cc jump .Lsyscall_do_signals;<br /> cc = BITTST(r7, TIF_SIGPENDING);<br /> if !cc jump .Lsyscall_really_exit;<br />.Lsyscall_do_signals:<br /> /* Reenable interrupts. */<br /> [--sp] = reti;<br /> r0 = [sp++];<br /><br /> r0 = sp;<br /> SP += -12;<br /> call _do_signal;<br /> SP += 12;<br /><br />.Lsyscall_really_exit:<br /> r5 = [sp + PT_RESERVED];<br /> rets = r5;<br /> rts;<br />ENDPROC(_system_call)</code></pre>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-20798729147776391722008-04-20T20:49:00.001-07:002008-05-08T21:14:41.848-07:00mdev primerThe following is the doc related to mdev which i get from busybox 1.6.1<br />distribution :<p>————-<br />MDEV Primer<br />————-</p><p>For those of us who know how to use mdev, a primer might seem lame. For<br />everyone else, mdev is a weird black box that they hear is awesome, but<br />can't<br />seem to get their head around how it works. Thus, a primer.</p><p>———–<br />Basic Use<br />———–</p><p>Mdev has two primary uses: initial population and dynamic updates. Both<br />require sysfs support in the kernel and have it mounted at /sys. For<br />dynamic<br />updates, you also need to have hotplugging enabled in your kernel.</p><p>Here's a typical code snippet from the init script:<br />[1] mount -t sysfs sysfs /sys<br />[2] echo /bin/mdev > /proc/sys/kernel/hotplug<br />[3] mdev -s</p><p>Of course, a more "full" setup would entail executing this before the<br />previous<br />code snippet:<br />[4] mount -t tmpfs mdev /dev<br />[5] mkdir /dev/pts<br />[6] mount -t devpts devpts /dev/pts</p><p>The simple explanation here is that [1] you need to have /sys mounted<br />before<br />executing mdev. Then you [2] instruct the kernel to execute /bin/mdev<br />whenever<br />a device is added or removed so that the device node can be created or<br />destroyed. Then you [3] seed /dev with all the device nodes that were<br />created<br />while the system was booting.</p><p>For the "full" setup, you want to [4] make sure /dev is a tmpfs<br />filesystem<br />(assuming you're running out of flash). Then you want to [5] create the<br />/dev/pts mount point and finally [6] mount the devpts filesystem on it.</p><p>————-<br />MDEV Config (/etc/mdev.conf)<br />————-</p><p>Mdev has an optional config file for controlling ownership/permissions<br />of<br />device nodes if your system needs something more than the default<br />root/root<br />660 permissions.</p><p>The file has the format:<br /><device regex> <uid>:<gid> <octal permissions><br />For example:<br />hd[a-z][0-9]* 0:3 660</p><p>The config file parsing stops at the first matching line. If no line is<br />matched, then the default of 0:0 660 is used. To set your own default,<br />simply<br />create your own total match like so:<br />.* 1:1 777</p><p>If you also enable support for executing your own commands, then the<br />file has<br />the format:<br /><device regex> <uid>:<gid> <octal permissions> [<@|$|*> <command>]<br />The special characters have the meaning:<br />@ Run after creating the device.<br />$ Run before removing the device.<br />* Run both after creating and before removing the device.</p><p>The command is executed via the system() function (which means you're<br />giving a<br />command to the shell), so make sure you have a shell installed<br />at /bin/sh.</p><p>For your convenience, the shell env var $MDEV is set to the device name.<br />So if<br />the device 'hdc' was matched, MDEV would be set to "hdc</p>liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-57739037425770523462008-01-10T00:01:00.000-08:002008-01-09T23:53:32.035-08:00/proc/meminfo/proc/meminfo annotated:<p>fs/proc/proc_misc.c: meminfo_read_proc() <p>MemTotal: Total usable ram (i.e. physical ram minus a few reserved<br> bits and the kernel binary code)<p>MemFree: The sum of LowFree+HighFree<p>Buffers: Relatively temporary storage for raw disk blocks<br> shouldn't get tremendously large (20MB or so)<p>Cached: in-memory cache for files read from the disk (the<br> pagecache). Doesn't include SwapCached<br> <br>SwapCached: Memory that once was swapped out, is swapped back in but<br> still also is in the swapfile (if memory is needed it<br> doesn't need to be swapped out AGAIN because it is already<br> in the swapfile. This saves I/O)<p>(All page frames are linked in inactive or active list)<br>Active: Memory that has been used more recently and usually not<br> reclaimed unless absolutely necessary.<br>Inactive: Memory which has been less recently used. It is more<br> eligible to be reclaimed for other purposes<br> <br>HighTotal:<br> HighFree: Highmem is all memory above ~860MB of physical memory<br> Highmem areas are for use by userspace programs, or<br> for the pagecache. The kernel must use tricks to access<br> this memory, making it slower to access than lowmem.<br> LowTotal:<br> LowFree: Lowmem is memory which can be used for everything that<br> highmem can be used for, but it is also available for the<br> kernel's use for its own data structures. Among many<br> other things, it is where everything from the Slab is<br> allocated. Bad things happen when you're out of lowmem.<p>SwapTotal: total amount of swap space available<br> SwapFree: Memory which has been evicted from RAM, and is temporarily<br> on the disk<br> Dirty: Memory which is waiting to get written back to the disk<br> Writeback: Memory which is actively being written back to the disk<br> Mapped: files which have been mmaped, such as libraries<br> Slab: in-kernel data structures cache<br> CommitLimit: Based on the overcommit ratio ('vm.overcommit_ratio'),<br> this is the total amount of memory currently available to<br> be allocated on the system. This limit is only adhered to<br> if strict overcommit accounting is enabled (mode 2 in<br> 'vm.overcommit_memory').<br> The CommitLimit is calculated with the following formula:<br> CommitLimit = ('vm.overcommit_ratio' * Physical RAM) +<br>Swap<br> For example, on a system with 1G of physical RAM and 7G<br> of swap with a `vm.overcommit_ratio` of 30 it would<br> yield a CommitLimit of 7.3G.<br> For more details, see the memory overcommit documentation<br> in vm/overcommit-accounting.<br>Committed_AS: The amount of memory presently allocated on the system.<br> The committed memory is a sum of all of the memory which<br> has been allocated by processes, even if it has not been<br> "used" by them as of yet. A process which malloc()'s 1G<br> of memory, but only touches 300M of it will only show up<br> as using 300M of memory even if it has the address space<br> allocated for the entire 1G. This 1G is memory which has<br> been "committed" to by the VM and can be used at any time<br> by the allocating application. With strict overcommit<br> enabled on the system (mode 2 in 'vm.overcommit_memory'),<br> allocations which would exceed the CommitLimit (detailed<br> above) will not be permitted. This is useful if one needs<br> to guarantee that processes will not fail due to lack of<br> memory once that memory has been successfully allocated.<br> PageTables: amount of memory dedicated to the lowest level of page<br> tables.<br>VmallocTotal: total size of vmalloc memory area<br> VmallocUsed: amount of vmalloc area which is used<br>VmallocChunk: largest contigious block of vmalloc area which is freeliyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-29968871776400907282007-12-25T22:51:00.000-08:002007-12-25T22:45:11.962-08:00What Is Bit-Banging?What Is Bit-Banging?<br> Bit-banging is a method of using general-purpose I/O lines to<br> emulate a serial port. Microcontrollers that include serial-port<br> modules like SPI[tm] and I2C[tm] manage all synchronization and<br> timing signals, and this activity is transparent to the user.<br> With bit-banging, however, each write to the port causes a<br> single transition at the port pin. And it's up to the user,<br> first, to provide the correct number of transitions to obtain<br> the desired waveform and, second, to ensure that the timing<br> requirements (particularly setup and hold times for reading and<br> writing data) are met. Due to the overhead associated with the<br> number of writes to the port, though the actual port speed might<br> be quite high the actual bit-bang throughput rate is usually<br> very slow. This technique is very inefficient from a software<br> perspective, but it may be acceptable in some applications where<br> the communication overhead is acceptable (for example for doing<br> occasional controlling communication).liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-86878327883115003942007-12-13T01:56:00.000-08:002007-12-13T01:50:13.637-08:00Mixed-Language Programming and External Linkage<a href="http://developers.sun.com/solaris/articles/external_linkage.html">http://developers.sun.com/solaris/articles/external_linkage.html</a><br>Dec 13, 2007<br> <br>Article<br>Mixed-Language Programming and External Linkage<p> <p><br> <br> <p><br>By Giri<br>Mandalika,<br>March 2005,<br>Updated<br>March 2006<br> <p><p>Abstract: This article introduces<br>the concept of linkage and shows how<br>a simple C++ program fails without<br>language linkage, but can succeed<br>with proper linkage.<p>Contents:<p> * Introduction<br> * The Problem<br> * The Reason<br> * The Solution<br> * Resources<p>It is a common practice to call<br>functions of a C library from a C++<br>program. This works out well as long<br>as developers restrict themselves to<br>the standard headers and libraries<br>that were supplied with the<br>operating system. But novice<br>programmers may stumble with some<br>link-time errors, as soon as they<br>try to call methods of their own C<br>library from a C++ program.<br>Potential reasons for the failure<br>could include unfamiliarity with<br>linkage specifications and how C/C++<br>compilers handle symbols during the<br>compilation.<p>This article briefly introduces the<br>concept of linkage and shows how a<br>simple C++ program fails without<br>language linkage, and succeeds with<br>proper linkage. Mixing code written<br>in C++ with code written in C is<br>relatively straightforward, as C++<br>is mostly a superset of C. Although<br>mixing C++ objects with objects in<br>languages other than C is allowed,<br>it is a bit more complicated, hence<br>this article restricts the<br>discussion to C and C++ objects.<p>Introduction<p>The C++ standard provides a<br>mechanism called linkage<br>specification for mixing code that<br>was written in different programming<br>languages and was compiled by the<br>respective compilers, in the same<br>program. Linkage specification<br>refers to the protocol for linking<br>functions or procedures written in<br>different languages. Linkage is the<br>term used by the C++ standard to<br>describe the accessibility of<br>objects from one file to another or<br>even within the same file. Three<br>types of linkage exist:<p> * No linkage<br> * Internal linkage<br> * External linkage<p>Something internal to a function, in<br>regard to its arguments, variables,<br>and so on, always has no linkage and<br>hence can be accessed only within<br>the function.<p>Sometimes it is necessary to declare<br>functions and other objects within a<br>single file in a way that allows<br>them to reference each other, but<br>not to be accessible from outside<br>that file. This can be done through<br>internal linkage. Symbols with<br>internal linkage only refer to the<br>same object within a single source<br>file. Prefixing the declarations<br>with the keyword static changes the<br>linkage of external objects from<br>external linkage to internal<br>linkage.<p>Objects that have external linkage<br>are all considered to be located at<br>the outermost level of the program.<br>This is the default linkage for<br>functions and anything declared<br>outside of a function. All instances<br>of a particular name with external<br>linkage refer to the same object in<br>the program. If two or more<br>declarations of the same symbol have<br>external linkage but with<br>incompatible types (for example,<br>mismatch of declaration and<br>definition), then the program may<br>either crash or show abnormal<br>behavior. The rest of the article<br>discusses one of the issues with<br>mixed code and provides a<br>recommended solution with external<br>linkage.<p>The Problem<p>In the real world, it is very common<br>to use the functionality of code<br>written in one programming language<br>from code written in another. A<br>trivial example is a C++ programmer<br>relying on a standard C library<br>(libc) for sorting a series of<br>integers with the "quick sort"<br>technique. It works because the C<br>implementation takes care of the<br>language linkage for us. But we need<br>to take additional care if we use<br>our own libraries written in C, from<br>a C++ program. Otherwise the<br>compilation may fail with link<br>errors caused by unresolved symbols.<br>Consider the following example:<p>Assume that we're writing C++ code<br>and wish to call a C function from C<br>++ code. Here's the code for the<br>callee, for example, C routine:<p>%cat greet.h<br>extern char *greet();<p>%cat greet.c<br>#include "greet.h"<p>char *greet() {<br> return ((char *) "Hello!");<br>}<p>%cc -G -o libgreet.so greet.c<br> <p><br>Note: The extern keyword declares a<br>variable or function and specifies<br>that it has external linkage, i.e.,<br>its name is visible from files other<br>than the one in which it's defined.<p>Let's try to call the C function<br>greet() from a C++ program.<p>%cat mixedcode.cpp<br>#include <iostream.h><br>#include "greet.h"<p>int main() {<br> char *greeting = greet();<br> cout << greeting << "\n";<br> return (0);<br>}<br> <br>%CC -lgreet mixedcode.cpp<br>Undefined first referenced<br> symbol in file<br>char*greet() mixedcode.o<br>ld: fatal: Symbol referencing errors. No output written to a.out<br> <p><br>Though the C++ code is linked with<br>the dynamic library that holds the<br>implementation for greet(),<br>libgreet.so, the linking failed with<br>undefined symbol error. What went<br>wrong?<p>The Reason<p>The reason for the link error is<br>that a typical C++ compiler mangles<br>(encodes) function names to support<br>function overloading. So, the symbol<br>greet is changed to something else<br>depending on the algorithm<br>implemented in the compiler during<br>the name mangling process. Hence the<br>object file does not have the symbol<br>greet anywhere in the symbol table.<br>The symbol table of mixedcode.o<br>confirms this. Let's have a look at<br>the symbol tables of both<br>libgreet.so and mixedcode.o:<p>%elfdump1 -s libgreet.so<p>Symbol Table Section: .symtab<br>index value size type bind oth ver shndx name<br>...<br>[1] 0x00000000 0x00000000 FILE LOCL D 0 ABS libgreet.so<br>...<br>[37] 0x00000268 0x00000004 OBJT GLOB D 0 .rodata _lib_version<br>[38] 0x000102f3 0x00000000 OBJT GLOB D 0 .data1 _edata<br>[39] 0x00000228 0x00000028 FUNC GLOB D 0 .text greet<br>[40] 0x0001026c 0x00000000 OBJT GLOB D 0 .dynamic _DYNAMIC<p>%elfdump -s mixedcode.o<p>Symbol Table Section: .symtab<br>index value size type bind oth ver shndx name<br>[0] 0x00000000 0x00000000 NOTY LOCL D 0 UNDEF<br>[1] 0x00000000 0x00000000 FILE LOCL D 0 ABS mixedcode.cpp<br>[2] 0x00000000 0x00000000 SECT LOCL D 0 .rodata<br>[3] 0x00000000 0x00000000 FUNC GLOB D 0 UNDEF <br> __1cDstd2l6Frn0ANbasic_ostream4Ccn0ALchar_traits4Cc____pkc_2_<br>[4] 0x00000000 0x00000000 FUNC GLOB D 0 UNDEF __1cFgreet6F_pc_<br>[5] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF __1cDstdEcout_<br>[6] 0x00000010 0x00000050 FUNC GLOB D 0 .text main<br>[7] 0x00000000 0x00000000 NOTY GLOB D 0 ABS __fsr_init_value<p>%dem2 __1cFgreet6F_pc_<p>__1cFgreet6F_pc_ == char*greet()<br> <p><br>char*greet() has been mangled to<br>__1cFgreet6F_pc_ by the Sun Studio 9<br>C++ compiler. That's the reason why<br>the static linker (ld) couldn't<br>match the symbol in the object file.<p>Note that a C compiler that complies<br>with the C99 standard may mangle<br>some names. For example, on systems<br>in which linkers cannot accept<br>extended characters, a C compiler<br>may encode the universal character<br>name in forming valid external<br>identifiers.<p>The Solution<p>The C++ standard provides a<br>mechanism called linkage<br>specification to enables smooth<br>compilation of mixed code. Linkage<br>between C++ and non-C++ code<br>fragments is called language<br>linkage. All function types,<br>function names, and variable names<br>have a default C++ language linkage.<br>Language linkage can be achieved<br>using the following linkage<br>specification.<p>Linkage specification:<p>extern string-literal { <br> function-declaration<br> function-declaration<br>}<br>extern string-literal function-declaration;<br> <p><br>The string-literal specifies the<br>linkage associated with a particular<br>function, for example, C and C++.<br>Every C++ implementation provides<br>for linkage to functions written in<br>C language ("C") and linkage to C++<br>("C++").<p>The solution to the problem under<br>discussion is to ask the C++<br>compiler to use C mangling for the<br>external functions to be called, so<br>we can use the functionality of<br>external C functions from C++ code,<br>without any issues. We can<br>accomplish this using the linkage to<br>C. The following declaration of<br>greet() in greet.h should resolve<br>the problem:<p>extern "C" char *greet();<br> <p><br>Because we were calling C code from<br>a C++ program, C linkage was used<br>for the routine greet(). The linkage<br>directive extern "C" tells the<br>compiler to change from C++ mangling<br>to C mangling for the function, and<br>to use C calling conventions while<br>sending external information to the<br>linker. In other words, the C<br>linkage specification forces the C++<br>compiler to adopt C conventions,<br>which are not the same as C++<br>conventions.<p>So, let's modify the header greet.h,<br>and recompile:<p>%cat greet.h<br>#if defined __cplusplus<br> extern "C" {<br>#liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0tag:blogger.com,1999:blog-30314596.post-56566713595910804202007-11-22T02:00:00.000-08:002007-11-22T01:59:29.182-08:00Multi-file projects and the GNU Make utility==============================================================================<br>C-Scene Issue #2<br>Multi-file projects and the GNU Make utility<br>Author: George Foot<br>Email: george.foot@merton.ox.ac.uk<br>Occupation: Student at Merton College, Oxford University, England<br>IRC nick: gfoot<br>==============================================================================<p>Disclaimer: The author accepts no liability whatsoever for any<br> damage this may cause to anything, real, abstract or <br> virtual, that you may or may not own. Any damage <br> caused is your responsibility, not mine.<p> Ownership: The section `Multi-file projects' remains the<br> property of the author, and is copyright (c) George<br> Foot May-July 1997. The remaining sections are the<br> property of CScene and are copyright (c) 1997 by<br> CScene, all rights reserved. Distribution of this<br> article, in whole or in part, is subject to the same<br> conditions as any other CScene article.<p><br>0) Introduction<br>~~~~~~~~~~~~~~~<p>This article will explain firstly why, when and how to split<br>your C source code between several files sensibly, and it will<br>then go on to show you how the GNU Make utility can handle all<br>your compilation and linking automatically. Users of other make<br>utilities may still find the information useful, but it may<br>require some adaptation to work on other utilities. If in doubt,<br>try it out, but check the manual first.<p><br>1) Multi-file projects<br>~~~~~~~~~~~~~~~~~~~~~~<p> 1.1 Why use them?<br> -----------------<br> <br> Firstly, then, why are multi-file projects a good thing?<br> They appear to complicate things no end, requiring header<br> files, extern declarations, and meaning you need to search<br> through more files to find the function you're looking<br> for.<p> In fact, though, there are strong reasons to split up<br> projects. When you modify a line of your code, the<br> compiler has to recompile everything to create a new<br> executable. However, if your project is in several files<br> and you modify one of them, the object files for the other<br> source files are already on disk, so there's no point in<br> recompiling them. All you need to do is recompile the file<br> that was changed, and relink the object files. In a large<br> project this can mean the difference between a lengthy<br> (several minutes to several hours) rebuild and a ten or<br> twenty second adjustment.<p> With a little organisation, splitting a project between<br> files can make it much easier to find the piece of code<br> you are looking for. It's simple - you split the code<br> between the files based upon what the code does. Then if<br> you're looking for a routine you know exactly where to<br> find it.<p> It is much better to create a library from many object<br> files than from a single object file. Whether or not this<br> is a real advantage depends what system you're using, but<br> when gcc/ld links a library into a program at link time it<br> tries not to link in unused code. It can only exclude<br> entire object files from the library at a time, though, so<br> if you reference any symbols from a particular object file<br> of a library the whole object file must be linked in. If<br> the library is very segmented, the resulting executables<br> can be much smaller than they would be if the library<br> consisted of a single object file.<p> Also, since your program is very modular with the minimum<br> amount of sharing between files there are many other<br> benefits -- bugs are easier to track down, modules can<br> often be reused in another project, and last but not<br> least, other people will find it much easier to understand<br> what your code is doing.<p><br> 1.2 When to split up your projects<br> ----------------------------------<p> It is obvisouly not sensible to split up *everything*;<br> small programs like `Hello World' can't really be split<br> anyway since there's nothing to split. Splitting up small<br> throwaway test programs is pretty pointless too. In<br> general, though, I split things whenever doing so seems to<br> improve the layout, development and readability of the<br> program. This is in fact true most of the time.<p> The decision about what to split and how is of course<br> yours; I can only make general suggestions here, which you<br> may or may not choose to follow.<p> If you are developing a fairly large project, you should<br> think before you start how you are going to implement it,<br> and create several (appropriately named) files initially<br> to hold your code. Of course, don't hesitate to create new<br> files later in development, but if you do then you are<br> changing your mind and should perhaps think about whether<br> some other structural changes would be appropriate.<p> For medium-sized projects, you can use the above technique<br> of course, or you might be able to just start typing, and<br> split the file up later when it is getting hard to manage.<br> In my experience, though, it is a great deal simpler to<br> start off with a scheme in mind and stick to it or adapt<br> it as the program's needs change during development.<p><br> 1.3 How to split up projects<br> ----------------------------<p> Again, this is strictly my opinion; you may (probably<br> will?) prefer to lay things out differently. This is<br> touching on the controversial topic of coding style; what<br> I present here is simply my personal preference (along<br> with reasons for each of these guidelines):<br> <br> i) Don't make header files which span several source<br> files (exception: library header files). It's much<br> easier to track and usually more efficient if each<br> header file only declares symbols from one source<br> file. Otherwise, changing the structure of one<br> source file (and its header file) may cause more<br> files to be rebuilt that is really necessary.<p> ii) Where appropriate, do use more than one header file<br> for a source file. It is often useful to seperate<br> function prototypes, type definitions, etc, from the<br> C source file into a header file even when they are<br> not publicly available. Making one header file for<br> public symbols and one for private symbols means<br> that if you change the internals of the file you can<br> recompile it without having to recompile other files<br> that use the public header file.<p> iii) Don't duplicate information in several header files.<br> If you need to, #include one in the other, but don't<br> write out the same header information twice. The<br> reason for this is that if you change the<br> information in the future you will only need to<br> change it once, rather than hunting for duplicates<br> which would also need modifying.<p> iv) Make each source file #include all the header files<br> which declare information in the source file. Doing<br> this means that the compiler is more likely to pick<br> out mistakes, where you have declared something<br> differently in the header file to what it is in the<br> source file.<p><br> 1.4 Notes on common errors<br> --------------------------<p> a) Identifier clashes between source files: In C,<br> variables and functions are by default public, so that<br> any C source file may refer to global variables and<br> functions from another C source file. This is true even<br> if the file in question does not have a declaration or<br> prototype for the variable or function. You must,<br> therefore, ensure that the same symbol name is not used<br> in two different files. If you don't do this you will<br> get linker errors and possibly warnings during<br> compilation.<p> One way of doing this is to prefix public symbols with<br> some string which depends on the source file they appear<br> in. For example, all the routines in gfx.c might begin<br> with the prefix `gfx_'. If you are careful with the way<br> you split up your program, use sensible function names,<br> and don't go overboard with global variables, this<br> shouldn't be a problem anyway.<p> To prevent a symbol from being visible from outside the<br> source file it is defined in, prefix its definition<br> with the keyword `static'. This is useful for small<br> functions which are used internally by a file, and<br> won't be needed by any other file.<p> b) Multiply defined symbols (again): A header file is<br> literally substituted into your C code in place of the<br> #include statement. Consequently, if the header file is<br> #included in more than one source file all the<br> definitions in the header file will occur in both<br> source files. This causes them to be defined more than<br> once, which gives a linker error (see above).<p> Solution: don't define variables in header files. You<br> only want to declare them in the header file, and<br> define them (once only) in the appropriate C source<br> file, which should #include the header file of course<br> for type checking. The distinction between a<br> declaration and a definition is easy to miss for<br> beginners; a declaration tells the compiler that the<br> named symbol should exist and should have the specified<br> type, but it does not cause the compiler to allocate<br> storage space for it, while a definition does allocate<br> the space. To make a declaration rather than a<br> definition, put the keyword `extern' before the<br> definition.<p> So, if we have an integer called `counter' which we<br> want to be publicly available, we would define it in a<br> source file (one only) as `int counter;' at top level,<br> and declare it in a header file as `extern int<br> counter;'.<p> Function prototypes are implicitly extern, so they do<br> not create this problem.<p> c) Redefinitions, redeclarations, conflicting types:<br> Consider what happens if a C source file #includes both<br> a.h and b.h, and also a.h #includes b.h (which is<br> perfectly sensible; b.h might define some types that<br> a.h needs). Now, the C source file #includes b.h twice.<br> So every #define in b.h occurs twice, every declaration<br> occurs twice (not actually a problem), every typedef<br> occurs twice, etc. In theory, since they are exact<br> duplicates it shouldn't matter, but in practice it is<br> not valid C and you will probably get compiler errors<br> or at least warnings.<p> The solution to this problem is to ensure that the body<br> of each header file is included only once per source<br> file. This is generally achieved using preprocessor<br> directives. We will #define a macro for each header<br> file, as we enter the header file, and only use the<br> body of the file if the macro is not already defined.<br> In practice it is as simple as putting this at the<br> start of each header file:<p> #ifndef FILENAME_H<br> #define FILENAME_H<p> and then putting this at the end of it:liyihttp://www.blogger.com/profile/15974027724810590935noreply@blogger.com0