Home PC Games Linux Windows Database Network Programming Server Mobile  
           
  Home \ Linux \ To see the Linux device tree     - MySQL stored procedures and triggers (Database)

- Ubuntu 14.04 solved using MyEclipse 10.7 flash back (Linux)

- Examples of Exploration Class File (Programming)

- Android Application Development: an argument between Activity (Programming)

- Oracle to create an external table (Database)

- Oracle GoldenGate Installation and Configuration Tutorial Introduction (Database)

- Example of use WebSocket (Programming)

- C # compiler to achieve functional use in the runtime (Programming)

- Boot-Repair Tool - repair of frequent start-up problems (Linux)

- configuration ssh without password under Linux (Linux)

- How to use the DM-Crypt encryption Linux File System (Linux)

- Copy files between two Linux hosts (Linux)

- CentOS6.7 text installation system (Linux)

- Ubuntu and Derivative Edition users install LMMS 0.4.15 (Linux)

- Graphing tool: Gnuplot (Linux)

- Linux Security (Linux)

- MySQL binlog automatic cleanup script (Database)

- NGINX Plus now fully supports HTTP / 2 (Server)

- How to use Monit to deploy a server to monitor the system (Server)

- Java static internal class (Programming)

 
         
  To see the Linux device tree
     
  Add Date : 2018-11-21      
         
         
         
  Outline

Device Tree (Device tree) is used to describe a set of hardware Zodiac rules. ARM Linux devices using tree Mechanism from March 2011 Linux founder Linus Torvalds sent an email, in this message, he advocated ARM platform should refer to other platforms such as the description of the device tree mechanism PowerPC hardware. Because before, ARM platform still uses the old mechanisms in kernel / arch / arm / plat-xxx directory and kernel / arch / arm / mach-xxx directory code description of the hardware, such as registering resource platform equipment, declared equipment Wait. Because these codes are used to describe the chip and board-level platform differences, so the kernel is concerned it is garbage code. Because many of the company's embedded platforms are ARM chip architecture, along with the success of Android, code more and more. It is said that a common platform, such as board-level directory s3c2410 tens of thousands of lines of code below, no wonder Linux Torvalds will say "this whole ARM thing is a fucking pain in the ass".

Documentation for the kernel device tree located at kernel / Documentation / devicetree / directory. The device tree is Power.org organization to define a set of specifications, specifications documents can be found on the official website, the latest version is https://www.power.org/documentation/epapr-version-1-1/. Kernel device tree of related functions are to begin with, I guess because the device tree mechanism is derived from IEEE 1275 Open Firmware standard norms related code is inherited. If you want to quickly learn how to use the device tree below, you can refer http://devicetree.org/Device_Tree_Usage.

The device tree is a description of the hardware from the software used, not from a hardware design standpoint described. We do not need to write device according to hardware logic tree mechanically, do not expect a reading device tree to figure out how to design the hardware. For software can automatically identify hardware such as USB devices, PCI devices, there is no need to adopt the device tree described.

I personally feel that specification content is divided into two levels. The first layer is on the device tree forms of organization, such as the device tree structure, composition and other node name, the first level is the foundation, is to understand the premise of the second level. The second layer is the content on the device tree, such as multi-core CPU how to describe, how to describe a specific device. The second layer may be regarded as a specific application of the first layer. The second layer is relatively more content, more specifically, depending on the description, the definition of standardized way there are differences, such as on CPU, memory, interrupts the basis of content, is described in epapr, but on peripherals specification is described in a special place.

DTS (Device tree syntax, another way of saying Device tree source) device tree is the source file for easy reading and modify text format. DTC (Device tree compiler) is a small utility, responsible for DTS convert DTB (Device tree blob). DTB is DTS binary form for machine use. In use, we first modified according to the hardware DTS file, then DTC tool converts at compile time DTS file into DTB file, and then programmed into the DTB file (such as emmc, disks and other storage media) machine. When the system starts, fastboot (or a similar program started, such as Uboot) before starting the kernel DTB file into memory, the jump to the kernel execution while DTB starting address to the kernel. The kernel start address can resolve the entire device tree structure according to DTB. Said device specification tree can be divided into two levels, the DTS is on a structure for the DTB is not within this range. DTB is for convenience only use the machine only for DTS conversion (DTS can also be said for convenience only human use and a description of the DTB's).

First, the device tree is a tree structure, and a tree. In addition to the root node has a child node can have other child nodes and attributes (child nodes can be seen as branches, leaves property can be seen as) a sole parent node, node. By the name attribute and a value (the name is a must, but the value is not necessary, as long as if according to the presence or absence of this attribute can express our desired function, you can do not need to have a value).

Below is a fragment of our DTS taken from the kernel code. "/" Indicates the root node. "Model =" Newflow AM335x NanoBone "" is the root below the property. "Cpus" is a child of the root node. "Cpu0-supply = < & dcdc2_reg>" is an attribute "cpu @ 0" child node. Attribute node under the node used to represent the characteristics of the child and parent nodes have some affiliation. Real hardware can not be a tree such rules, so the device tree only software developer to describe the hardware and do an approximate representation of it, are not really even abstract.

/ {
    model = "Newflow AM335x NanoBone";
    compatible = "ti, am33xx";

    cpus {
        cpu @ 0 {
            cpu0-supply = <& dcdc2_reg>;
        };
    };

    memory {
        device_type = "memory";
        reg = <0x80000000 0x10000000>; / * 256 MB * /
    };

    leds {
        compatible = "gpio-leds";

        led @ 0 {
            label = "nanobone: green: usr1";
            gpios = < & gpio1 5 0>;
            default-state = "off";
        };
    };
};

Node (node) represents

First, that the method node, except the root node with only a slash "/" means, the representation of the other nodes, such as "node-name @ unit-address". @ In front of the node name, it is behind the node address.
Node name length is 1-31 characters can be used in ePAPR specification has described, comprising:

0-9
lower case letters a-z
Uppercase letters A-Z
, Comma
. Period (English)
_ Underscore
+ Plus
- Dash (English)

Compliant node name should begin with a letter, while allowing the position behind the use of non-alphabetic characters, but the reality is we really do not need to use other characters, in general, all to a letter is enough. In particular specification recommends using a common name in a name rather than a proprietary names, such as the card, using ethernet it would be sufficient, you can distinguish different address card, the card can be the difference between the properties distinguish node. There is basically on the existing equipment already has been widely accepted by the name, we do not need this totally unconventional, such as listed below specification node name (often write driver who basically one can guess which kind of equipment):

atm
cache-controller
compact-flash
can
cpu
crypto
disk
display
dma-controller
ethernet
ethernet-phy
fdc
flash
gpio
i2c
ide
interrupt-controller
isa
keyboard
mdio
memory
memory-controller
mouse
nvram
parallel
pc-card
pci
pcie
rtc
sata
scsi
serial
sound
spi
timer
USB
vme
watchdog

Node address is used to identify the node of the same name, not address the software sense, but in some cases can use the software address as the address. For example, you can name two I2C controllers are i2c, then the controller register first address as the node address. For cpu, because it is not a register address, you can use the core number as an address for the 8-core processor, it can address from 0-7. ePAPR described in the specification is not a good understanding about the node address, the original is "The unit-address component of the name is specific to the bus type on which the node sits". Actually, I think this saying is not very accurate, because not all hardware nodes represent are located on a bus, such as memory, cpu. The device tree is a piece of hardware to software approximate representation, he expressed how software needs, how he expressed. For cpu, software requires the serial number, the address will use the serial number, for i2c controllers, software needs to register first address, then use the address. In addition to specification also requires that if a node has an address, the node below must have a property called reg, and the address must be the first attribute of the same address reg. If the node has no reg property, then the node address, and must be in front of @ can not have. About attributes and values ​​we have not started, but here interject, in fact, reg is the register Abbreviation, this property is primarily used to represent the first address of the controller register. I think this one specification is not very necessary, because some devices as long as there is enough of an address, the address on the node is enough, no need to have full plus a reg property. In the last sentence of this paragraph, standardized to the sentence "The binding for a particular bus may specify additional, more specific requirements for the format of reg and the unit-address.", I think the meaning of this sentence and the "device tree a hardware software approximate representation, he expressed how software needs, how he said, "almost nothing mysterious.

Node path is relatively easy to understand, from the root node to each node and form a path, as in the case of Section / cpus / cpu @ 0, it can be uniquely expressed by cpu @ 0 node. Because cpu @ 0 in cpus Below is unique, but the entire device tree may not be unique, and only with the full path indicates no objection to confirm which nodes. If you omit the node address will not be ambiguous, so can be omitted. Like programming, like parenthesis, personally I feel that the province is not necessary.

In addition to name and address, the node can also have a front label (label), the label is not required, this will be marked with labels nodes in other places generally only need to refer to this node, as if the full path is too cumbersome . Such as "i2c_1: i2c @ 12C70000" in i2c_1 is a label.

Properties (property)

device_type = "memory" is an attribute of the equal sign in front of the property, behind the value. Node is a relatively independent logical entities, attributes are used to describe the characteristics of a node, a node by node a characteristic zero, one or more properties as required. An attribute name and the values ​​of the two parts.

And the name of the node is similar to the name of the attribute specification 1-31 characters. The character's name and type of nodes some differences, does not allow capital letters, adding a question mark and pound two characters. And the node name is not clear why there is no completely consistent pound misleading for beginners, that is a comment.

0-9
lower case letters a-z
, Comma
. Period (English)
_ Underscore
+ Plus
- Dash (English)
? Question mark
# Hashtag

In order to easily distinguish and avoid duplication, the standard does not define the property name should start with a company or organization name, for example:
fsl, channel-fifo-len
ibm, ppc-interrupt-server # s
linux, network-index

Value of the property consists of 0 or more bytes in memory. Basic types of standard definitions include: air, u32, u64, string, , an array of six kinds of characters. Unprecedented edge we have already mentioned, when no value can be a characteristic node, the value of the property can be empty. u32, defined u64, string, character arrays, and c language there is no difference, it noted that the specifications are big-endian representation, but also the end of the string to 0x00. Will explain in detail is an array of structures, the specific elements of the array is determined based on what the definition of property, back when we talked about a specific property. Specification there is a type of property value, called , the attribute type stored in memory essentially u32.

Specification predefined some standard attributes. "Compatible", "model", "device_type" are used to indicate the node basic information.

"Compatible" attribute is used to match the driver, his type is an array of strings, each string represents a type of device, from the specific to the general. For example it is more clear, such as the properties of a serial control node "compatible =" fsl, mpc8641-uart "," ns16550 "". The first string "fsl, mpc8641-uart" front part manufacturers (presumably frescale), after part of the controller specific model, this form is also recommended specification standard wording. Ns16550 second string represents a category in line with the same standard serial controller, a wider range than the first string. Kernel matching driving first to see if there is a match the first string of the drive, and if not then match the second (if there are more, and so on, so the priority matching front).

"Model" attribute is used to indicate the device type, represented by a string, not "compatible" with multiple strings, just one is enough. "Device_type" attribute is used to indicate device type, represented by the string.

"# Address-cells", "# size-cells", "reg", "ranges", "dma-ranges" attribute is relevant and addresses.

Different platforms, different bus, the address bit length may be different, there are 32-bit address, 64-bit address, in order to adapt to this, the specification of a 32-bit length of a cell. "# Address-cells" attribute is used to indicate the address bus a few cell said that the property itself is u32 type. "# Size-cells" attribute is used to indicate the length of the sub-bus address space require several cell, said the type attribute itself is u32. It can be understood that the parent node represents a bus, the address and the length of the address range for each device on the bus is a bus feature, with the "# address-cells", "# size-cells" attribute indicates, for example, is a 32-bit bus, then " # address-cells "is set to 1 on it. These two properties can not inherit, that is to say when the two undefined properties, set a higher level will not inherit the parent node, if not set, the default kernel that the "# address-cells" 2 " # size-cells "1.

"Reg" property is used to indicate the node address of a resource, such as common is the starting address and the size of the register. To represent a contiguous address space must contain the starting address and size of the two parameters If you have multiple addresses, then multiple sets of such values ​​need to represent. Remember front of said property < prop-encoded-array> type of it, is used to do this, he said that an array element according to the specific format of each attribute may be, for 'reg' properties, each element is a tuple containing the start address and size. There is another problem, address and size of a few u32 say then? This would, "# size-cells" attribute is determined by the parent node "# address-cells".

Devices on the bus may be different address bus and the bus itself in, "ranges" attribute is used to indicate how to convert. And 'reg' similar properties, 'ranges' attribute is type of property, the difference is 'ranges' of each element properties are triples, according to the order before and after, respectively (sub bus address, parent bus address, size). Sub bus address needs expressed several u32 '# address-cells' property is determined by the 'ranges' attributes of the node, the parent bus address several needs expressed u32 '# address-cells' property determines the higher level nodes, size required several u32 represents is determined by the current node '# size-cells' property.

Structure and definition of 'dma-ranges' property and 'ranges' properties are identical, the only difference is that the address is the address used dma, 'ranges' address is the address of the cpu use.

Sometimes the need to reference a node to another node, such as interruption of a peripheral in which the interrupt controller is connected. In talking about the section we said node, you can specify the full path through the node which node, but this method is very cumbersome. 'Phandle' property is designed for ease of reference node design, which node you want to add a reference to 'phandle' property in the node below the set value is a u32, such as 'phandle = < 1>', where direct reference use the number 1 can reference the node, such as 'interrupt-parent = < 1>'. These are the methods described in the specification, in fact, this is not easy, I do not see in the actual code so used. Remember that section of said node node name can define a label in front of it, the reality is that with all label references, such as node label intc1, then use the 'interrupt-parent = < & intc1>' can be cited.

'Status' attribute is used to indicate the status of the node, in fact, is the status of the hardware, with a string. 'Okay' showing the hardware is working properly, "disabled" shows the hardware currently available, "fail" indicates unavailable because an error occurred, "fail-sss" indicates an error for some reason unavailable, sss indicates the specific cause of the error. In practice, basically only 'okay' and 'disabled'.

Interrupt

Interrupt generally include interrupt generating device and interrupt processing equipment. Interrupt controller is responsible for handling interrupts, each interrupt has a corresponding interrupt number and trigger conditions. Interrupt generation device may have multiple sources, sometimes multiple interrupt sources corresponding to the interrupt controller, an interrupt, this interrupt source interrupt device called the interrupt controller corresponding to the interrupted sub interrupted. General equipment to produce more than the number of interrupts interrupt controller, a plurality of interrupt device is interrupted by an interrupt controller processes this many to one relationship like a tree, so in the device tree, interrupted has also been described as a tree, the tree is called the interrupt. The following statements in order to clarify when said interrupt tree, the parent and child nodes are in front of us the words "break" the word, is to prevent the device tree and parent node, child node confusion (although in most cases the device tree father and son parent-child relationship is the relationship between the interruption of the tree, but because there are exceptions, so we emphasize parent-child relationship is interrupted).

Interrupt generation equipment interrupts attribute describes the interrupt source (interrupt specifier), because different hardware description data sources require different amounts of interrupts, so interrupts the type attribute is < prop-encoded-array>. To clear an interrupt is represented by several u32, and the introduction of # interrupt-cells property, # interrupt-cells attribute type u32, if an interrupt source requires two u32 represents (a representation interrupt number, and the other represents the type of interrupt ), then # interrupt-cells is set to 2. In some cases, the parent node of the device tree is not interrupted parent (mainly the interrupt controller is generally not the parent node), for the introduction of the interrupt-parent attribute, type the attribute is < phandle>, used to refer to interrupt the parent node (we explained above, usually with the label of the parent node, the parent node of this place said interrupt controller is not interrupted for a reason). If the device is to interrupt the tree's parent parent, you can not set interrupt-parent attribute. interrupts and interrupt-parent attribute properties are properties interrupt device node, but the property is not # interrupt-cells, # interrupt-cells attribute node and the interrupt controller interrupt attribute nexus node, these two types of nodes may be interrupted Father node.

Interrupt controller node with interrupt-controller attribute represents himself as an interrupt controller, the type of this property is empty, do not set the value as long as the existence of this node indicates that the node is the interrupt controller. In addition to this property, the interrupt controller node also # interrupt-cells attribute that represents the interrupt controller interrupt domain under direct management (back we'll talk about the interrupt controller interrupt interrupt nexus node child node has a separate interrupt domain ) with a few u32 represents an interrupt source (interrupt specifier). Interrupt controller including interrupt-controller node # interrupt-cells and two properties on interrupts. Interrupt Controller # address-cells and interrupt attribute mapping relationship, but the property is not designed to interrupt, the interrupt map just uses this property only.

In front of said interrupt controller, an interrupt may correspond to a plurality of interrupt generation device interrupt sources, and that this relationship with what it described? We also said # interrupt-celll property is not only interrupt controller node attributes, or interrupt attribute nexus node, the node is the nexus described interrupt interrupt mapping relationship, the node through interrupt-map, interrupt-map-mask attribute description interrupt mappings. interrupt-map attribute is < prop-encoded-array> type, each element represents a mapping between an interrupt (note is a "break mapping relationship", not "a break" mapping relations), front to back including: child device interrupts address, interrupt sub-device interrupt source (interrupt specifier), the parent device interrupt, the interrupt address of the parent, the parent device interrupts interrupt source (interrupt specifier) ​​five parts. Interrupted by several sub-device address specific u32 composed by the interrupt subroutine where bus devices (not interrupt the parent device) # address-cells attribute decision, this place Why interrupt device addresses without interrupting device phandle, there is a reason because the interrupt the device will use interrupt-parrent parent attribute to the interrupt, so the interrupt sub-device is for sure, no explanation. But also because the interrupt sub-device address can be done with the operation through interrupt-map-mask attribute can be achieved one mapping. Interrupt child device interrupt source (interrupt specifier) ​​is composed of several u32 # interrupt-cell is determined by the interrupt nexus node under. Interrupt parent is a parent to the interrupt device < phandle> Properties, under normal circumstances is an interrupt controller, but according to the interrupt logic tree, it may interrupt nexus node higher level. Interrupt parent device address of a specific composition is made up of several u32 # address-cells attribute interrupt the parent device node under the decision (Note that not interrupt the bus where the parent device # address-cells attribute). Interrupt parent device interrupt source (interrupt specifier) ​​consists of several u32 composition was determined by the interruption of the parent device # interrupt-cells property.

Remember front of said interrupt source devices and interrupt controller interrupt sources may be many to one relationship, if each child interrupts with interrupt-map represents a row, then the interrupt-map attribute will be very large. In order to allow a plurality of sub-interrupt sharing mapping introduced interrupt-map-mask attribute, type the attribute is , contains the interrupt sub-device address and interrupt sub-device interrupts bit mask source, given a child interrupt source, first and interrupt-map-mask to do with the operation, the operation results and then find the corresponding interrupt the parent device interrupt source interrupt-map attribute. That is why we are in front of a line interrupt-map attribute is an "interrupt mapping relationship", and not the cause of the mappings "a break."

Let us review the entire bottom of the tree is interrupted interrupt device (and possibly from interrupt nexus node), an interrupt is generated by the device interrupts to interrupt his property description can produce. Because his parent could interrupt device tree and parent are different, then using interrupt-parent attribute points to interrupt his parent device. His father interrupt device may interrupt controller (interrupt is generated if the device interrupt and the interrupt controller is one to one, or the bottom of the interrupt nexus node), it may interrupt nexus node (if the bottom is interrupted generating device, and needs to be mapped). interrupt nexus node and all his direct child nodes constitute a interrupt domain, in which the interrupt source interrupt domain representation is determined by how # interrupt-cells property, how the child device interrupt interrupt interrupt sources to find the parent device interrupt sources interrupt-map and interrupt-map-mask attribute decision. interrupt nexus parent node may interrupt nexus or a parent, it may be an interrupt controller, up to find when the last interrupt controller, the interrupt controller and interrupt no parent, the entire tree traversal complete interruption . Interrupt controller with interrupt-controller attribute represents himself as an interrupt controller, and use # interrupt-cells attribute represents his direct management interrupt domain with a few u32 represents an interrupt source. According to the characteristics of trees interrupted, a device tree, it is possible to have multiple interrupts tree.

These are the rules interruption in the device tree of how to describe, it sounds very complicated, but as long as it is simple to understand, in order to help understand we give a practical example. To highlight the interrupt part, we have done has been simplified.
/ {
    model = "Marvell Armada 375 family SoC";
    compatible = "marvell, armada375";
    soc {
        # Address-cells = < 2>;
        # Size-cells = < 1>;
        interrupt-parent = < & gic>;

        internal-regs {
            compatible = "simple-bus";
            # Address-cells = < 1>;
            # Size-cells = < 1>;

            timer @ c600 {
                compatible = "arm, cortex-a9-twd-timer";
                reg = < 0xc600 0x20>;
                interrupts = < GIC_PPI 13 (IRQ_TYPE_EDGE_RISING | GIC_CPU_MASK_SIMPLE (2))>;
                clocks = < & coreclk 2>;
            };

            gic: interrupt-controller @ d000 {
                compatible = "arm, cortex-a9-gic";
                # Interrupt-cells = < 3>;
                # Address-cells = < 0>;
                interrupt-controller;
                reg = < 0xd000 0x1000>,
                      < 0xc100 0x100>;
            };
        }

        pcie-controller {
            compatible = "marvell, armada-370-pcie";
            # Address-cells = < 3>;
            # Size-cells = < 2>;

            pcie @ 1,0 {
                # Address-cells = < 3>;
                # Size-cells = < 2>;
                # Interrupt-cells = < 1>;
                interrupt-map-mask = < 0 0 0 0>;
                interrupt-map = < 0 0 0 0 & gic GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
            };
        };
}

First, we see the next timer @ c600 device node defines interrupts property, indicating that the device can generate interrupts, but the attributes described several interrupt we do not see (if any experience, we can only guess a break, and now we follow the rules of confirmation). Because the node does not interrupt-parent attribute, so that the device tree parent internal-regs is interrupted parent node in internal-regs parent did not interrupt-parent attribute, or keep looking tree parent nodes found soc in the node below has interrupt-parent attribute. The property references are tagged gic, search the entire device tree, interrupt-controller @ d000 tagged gic. There are interrupt-controller attributes gic node, that he is an interrupt controller. gic node also attribute # interrupt-cells = < 3>, described in the controller interrupt domain, the interrupt source (interrupt specifier) ​​with three u32 that we look interrupts properties timer @ c600 indeed under the 3 a u32 composition (refer to GIC's specification, the first u32 an interrupt type, the second is the interrupt number, and the third is the interrupt trigger conditions). This example illustrates that an interrupt is generated if the device interrupt sources and interrupt controller interrupt source is one to one, you may not need to interrupt nexus node and related attributes to represent the interrupt map.

Look pcie @ 1,0 this node, there is # interrupt-cells property, but did not interrupt-controller attribute, which shows that he is a interrupt nexus node. # Interrupt-cells property of the node is 1, indicating that the interrupt source of the interrupt nexus node under the jurisdiction with a u32 would be sufficient. In pcie @ 1,0 below the node has no child nodes, and did not interrupt-parent attribute node points pcie @ 1,0 nodes, the interrupt generation device not interrupt domain from the device under the tree, the likely cause is these devices generate interrupts so no software can dynamically identify the device tree description. Because the interrupt-map-mask attribute is generated by the address of the device interrupts and interrupt sources (interrupt specifier) ​​composition, and the interrupt source with a u32 said it can be speculated that an interrupt is generated by the device address 3 u32 composition. It should be noted that the # address-cells attribute pcie @ 1,0 node 3, it is that the bus device address below by 3 u32 said it does not mean the device interrupt device address must also indicate u32 3 here is no coincidence, but we have to clear the interrupt address generating device consists of several u32 composition is determined by the location of the bus devices, for pcie bus indeed is 3, but other buses may be other kinds of cases. Now we analyze interrupt-map attribute, the first three numbers are interrupting device address, and the fourth number is the interrupting device interrupt sources. Because the interrupt-map-mask is all 0s, so no matter what the numbers and do the calculation result is 0, interrupt-map first four numeric attributes are also 0, indicating that all of the interrupt map in pcie @ 1,0 below to interrupt node interrupt is an interrupt parent. It followed gic point of < phandle>, because the next gic node # address-cells property is 0, so need not be described interrupt behind parent device address, and behind three figures are represented interrupt the parent device interrupt sources. Sentence description is pcie @ 1,0 under all interrupts are mapped to gic, GIC_SPI type No. 29 interrupts trigger high level trigger type. This example illustrates the interrupt lowermost tree may interrupt nexus nodes.

Interrupt tree root above example is gic, gic below has two children, one is interrupting device timer @ c600, a node is interrupt nexus pcie @ 1,0. interrupt domain gic directly governed by three u32 an interrupt source, in this interrupt domain timer @ c600. Under pcie @ 1,0 define a new interrupt domain, in this interrupt domain, the interrupt source with a u32 represents, pcie @ 1,0 with interrupt-map and interrupt-map-mask attribute below will be interrupted for all devices mapped to a gic below interrupts.

The root

One of the most simple device must contain the root tree, cpus nodes, memory nodes. And the full path name of the root node is "/", and compatible model must contain at least two properties. We have said attribute model is used to describe the properties of that section of the product model, the type of string, the recommended format for the "manufacturer, model-number" (non-mandatory). Root model attribute describes the type of board or chip platform models, such as:
model = "Atmel AT91SAM9G20 family SoC"
model = "Samsung SMDK5420 board based on EXYNOS5420"

Speaking from the software level model properties represent only a first name only, no more effect. compatible property is different, this property determines how the software to match the hardware for hardware initialization. Properties that section we said compatible attribute type is an array of strings, from small to large order in accordance with the scope of each string represents one match type. Root compatible attribute indicates how to match the platform, such as 'compatible = "samsung, smdk5420", "samsung, exynos5420", "samsung, exynos5"', means that the software should first match 'samsung, smdk5420', this is a development board . If you can not match, and then try to match "samsung, exynos5420", this is a chip platform. If this does not match, you can also try to match "samsung, exynos5", which is a series of chip platform. Here that the match is to find the corresponding software code based on that information, such as the corresponding initialization function.

Root node represents the entire board or chip platform, so relatively early in system initialization when you need to confirm what the platform, how to initialize. For Linux, the function call by start_kernel setup_arch function implementation. Different architectures to realize setup_arch function is different for arm architecture, setup_arch function source code is located in arch / arm / kernel / setup.c in. The following is a part of the function of the source code (the code from the kernel version of the official version of the 4.4-rc7 the holiday edge all the code from that version).

 935 void __init setup_arch (char ** cmdline_p)
 936 {
 937 const struct machine_desc * mdesc;
 938
 939 setup_processor ();
 940 mdesc = setup_machine_fdt (__ atags_pointer);
 941 if (! Mdesc)
 942 mdesc = setup_machine_tags (__ atags_pointer, __machine_arch_type);
 943 machine_desc = mdesc;
 944 machine_name = mdesc-> name;


Enter the first 940 rows setup_machine_fdt function of the device tree (DTB) first address returned mdesc platform is to describe the information structure. Remember we said in the Summary section that start the program as uboot the device tree into the memory, and then start the kernel while the first address to the kernel device tree, __atags_pointer here is to start the program passed to the kernel device tree address (in this case the memory device is already DTB tree form). setup_machine_fdt in fdt flat device tree is an abbreviation, fdt mean that in a device tree is stored in consecutive addresses, fdt and dtb said is the same thing in memory. setup_machine_tags is in the device tree initialization fails when it calls, so do not need him. machine_desc machine_name are static and global variables, used to hold back pointer convenient reference. To better understand what setup_machine_fdt concrete realization function, we first look machine_desc structure. Different architectures to define the difference between a lot of the structure, arm architecture source code is located in arch / arm / include / asm / mach / arch.h, reproduced below:
 
 27 struct machine_desc {
 28 unsigned int nr; / * architecture number * /
 29 const char * name; / * architecture name * /
 30 unsigned long atag_offset; / * tagged list (relative) * /
 31 const char * const * dt_compat; / * array of device tree
 32 * 'compatible' strings * /
 33
 34 unsigned int nr_irqs; / * number of IRQs * /
 35
 36 #ifdef CONFIG_ZONE_DMA
 37 phys_addr_t dma_zone_size; / * size of DMA-able area * /
 38 #endif
 39
 40 unsigned int video_start; / * start of video RAM * /
 41 unsigned int video_end; / * end of video RAM * /
 42
 43 unsigned char reserve_lp0: 1; / * never has lp0 * /
 44 unsigned char reserve_lp1: 1; / * never has lp1 * /
 45 unsigned char reserve_lp2: 1; / * never has lp2 * /
 46 enum reboot_mode reboot_mode; / * default restart mode * /
 47 unsigned l2c_aux_val; / * L2 cache aux value * /
 48 unsigned l2c_aux_mask; / * L2 cache aux mask * /
 49 void (* l2c_write_sec) (unsigned long, unsigned);
 50 const struct smp_operations * smp; / * SMP operations * /
 51 bool (* smp_init) (void);
 52 void (* fixup) (struct tag *, char **);
 53 void (* dt_fixup) (void);
 54 long long (* pv_fixup) (void);
 55 void (* reserve) (void); / * reserve mem blocks * /
 56 void (* map_io) (void); / * IO mapping function * /
 57 void (* init_early) (void);
 58 void (* init_irq) (void);
 59 void (* init_time) (void);
 60 void (* init_machine) (void);
 61 void (* init_late) (void);
 62 #ifdef CONFIG_MULTI_IRQ_HANDLER
 63 void (* handle_irq) (struct pt_regs *);
 64 #endif
 65 void (* restart) (enum reboot_mode, const char *);
 66};
 67

Notes can be seen from the above structure, the structure contains a lot of information. Note dt_compat variable line 31, the variable is used to match compatible device properties of the tree.

Achieve setup_machine_fdt function is related to architecture, arm architecture source code is located in arch / arm / kernel / devtree.c, copy the code below:

203 / **
204 * setup_machine_fdt - Machine setup when an dtb was passed to the kernel
205 * @dt_phys: physical address of dt blob
206 *
207 * If a dtb was passed to the kernel in r2, then use it to choose the
208 * correct machine_desc and to setup the system.
209 * /
210 const struct machine_desc * __init setup_machine_fdt (unsigned int dt_phys)
211 {
212 const struct machine_desc * mdesc, * mdesc_best = NULL;
213
214 #ifdef CONFIG_ARCH_MULTIPLATFORM
215 DT_MACHINE_START (GENERIC_DT, "Generic DT based system")
216 MACHINE_END
217
218 mdesc_best = & __ mach_desc_GENERIC_DT;
219 #endif
220
221 if (! Dt_phys ||! Early_init_dt_verify (phys_to_virt (dt_phys)))
222 return NULL;
223
224 mdesc = of_flat_dt_match_machine (mdesc_best, arch_get_next_mach);
225
226 if (! Mdesc) {
227 const char * prop;
228 int size;
229 unsigned long dt_root;
230
231 early_print ( "\ nError: unrecognized / unsupported"
232 "device tree compatible list: \ n [");
233
234 dt_root = of_get_flat_dt_root ();
235 prop = of_get_flat_dt_prop (dt_root, "compatible", & size);
236 while (size> 0) {
237 early_print ( " '% s'", prop);
238 size - = strlen (prop) + 1;
239 prop + = strlen (prop) + 1;
240}
241 early_print ( "] \ n \ n");
242
243 dump_machine_table (); / * does not return * /
244}
245
246 / * We really do not want to do this, but sometimes firmware provides buggy data * /
247 if (mdesc-> dt_fixup)
248 mdesc-> dt_fixup ();
249
250 early_init_dt_scan_nodes ();
251
252 / * Change machine number to match the mdesc we're using * /
253 __machine_arch_type = mdesc-> nr;
254
255 return mdesc;
256}

The first function 221 checks fdt row pointer is empty and calls early_init_dt_verify function, which code is in drivers / of / fdt.c, regarded as a function of the module (remember? Is open firmware abbreviation), and copy the code as follows:

1060
1061 bool __init early_init_dt_verify (void * params)
1062 {
1063 if (! Params)
1064 return false;
1065
1066 / * check device tree validity * /
1067 if (fdt_check_header (params))
1068 return false;
1069
1070 / * Setup flat device-tree pointer * /
1071 initial_boot_params = params;
1072 of_fdt_crc32 = crc32_be (~ 0, initial_boot_params,
1073 fdt_totalsize (initial_boot_params));
1074 return true;
1075}

early_init_dt_verify First check the legality of fdt head, then set fdt global variables and calculating crc. This variable initial_boot_params behind when accessing the device tree will be used. Continue to look at the front row 224, of_flat_dt_match_machine regarded as the second function of the function block it, prior to analysis this function, we first analyze the second argument arch_get_next_mach functions, which is a function pointer, to achieve architecture arm located in arch / arm / kernel / devtree.c, copy the code below:

190 static const void * __init arch_get_next_mach (const char * const ** match)
191 {
192 static const struct machine_desc * mdesc = __arch_info_begin;
193 const struct machine_desc * m = mdesc;
194
195 if (m> = __arch_info_end)
196 return NULL;
197
198 mdesc ++;
199 * match = m-> dt_compat;
200 return m;
201}

This function is very simple, attention is mdesc static local variables, first call point __arch_info_begin, behind all mdesc ++ each call, if more than __arch_info_end returns NULL. Described in the above code and __arch_info_end __arch_info_begin between two addresses stored plurality machine_desc variables (possibly a), the function traverses these variables, pointer variables return dt_compat all machine_desc structure by match parameters. The problem is __arch_info_begin and __arch_info_end address is how come? Defines .arch.info.init segment arch / arm / kernel / vmlinux.lds.S connection script, __ arch_info_begin and __arch_info_end address are the first and last address of the segment.

188 .init.arch.info: {
189 __arch_info_begin =.;
190 * (. Arch.info.init)
191 __arch_info_end =.;
192}

Then the contents .init.arch.info segment how come? This requires reference DT_MACHINE_START and MACHINE_END macros, arm architecture defined in arch / arm / include / asm / mach / arch.h file as follows:

 94 #define DT_MACHINE_START (_name, _namestr) \
 95 static const struct machine_desc __mach_desc _ ## _ name \
 96 __used \
 97 __attribute __ ((__ section __ ( ". Arch.info.init"))) = {\
 98 .nr = ~ 0, \
 99 .name = _namestr,
100
101 #endif

From the macro code to see his definition of a static local variable machine_desc type, the variable is .arch.info.init section. Reference arch / arm / mach-exynos / exynos.c in the following code, the following code defines a section in .arch.info.init named __mach_desc_EXYNOS_DT, machine_desc type static local variables, and the variable matrix string dt_compat there are "samsung, exynos5420" string.

277 static char const * const exynos_dt_compat [] __initconst = {
278 "samsung, exynos3",
279 "samsung, exynos3250",
280 "samsung, exynos4",
281 "samsung, exynos4210",
282 "samsung, exynos4212",
283 "samsung, exynos4412",
284 "samsung, exynos4415",
285 "samsung, exynos5",
286 "samsung, exynos5250",
287 "samsung, exynos5260",
288 "samsung, exynos5420",
289 "samsung, exynos5440",
290 NULL
291};
 
319 DT_MACHINE_START (EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
320 321 322 .l2c_aux_val = 0x3c400001,
323 .l2c_aux_mask = 0xc20fffff,
324 .smp = smp_ops (exynos_smp_ops),
325 .map_io = exynos_init_io,
326 .init_early = exynos_firmware_init,
327 .init_irq = exynos_init_irq,
328 .init_machine = exynos_dt_machine_init,
329 .init_late = exynos_init_late,
330 .dt_compat = exynos_dt_compat,
331 .reserve = exynos_reserve,
332 .dt_fixup = exynos_dt_fixup,
333 MACHINE_END


We already know get_next_compat pointer concrete realization, and now continue to look of_flat_dt_match_machine. Cycle from the beginning of the line 732 is traversing all segments .arch.info.init dt_compat variables, and then compute a score by of_flat_dt_match, and looking for the smallest fraction.

 713 / **
 714 * of_flat_dt_match_machine - Iterate match tables to find matching machine.
 715 *
 716 * @default_match: A machine specific ptr to return in case of no match.
 717 * @get_next_compat: callback function to return next compatible match table.
 718 *
 719 * Iterate through machine match tables to find the best match for the machine
 720 * compatible string in the FDT.
 721 * /
 722 const void * __init of_flat_dt_match_machine (const void * default_match,
 723 const void * (* get_next_compat) (const char * const **))
 724 {
 725 const void * data = NULL;
 726 const void * best_data = default_match;
 727 const char * const * compat;
 728 unsigned long dt_root;
 729 unsigned int best_score = ~ 1, score = 0;
 730
 731 dt_root = of_get_flat_dt_root ();
 732 while ((data = get_next_compat (& compat))) {
 733 score = of_flat_dt_match (dt_root, compat);
 734 if (score> 0 && score  735 best_data = data;
 736 best_score = score;
 737}
 738}
 ....
 759 return best_data;
 760}
 761

of_flat_dt_match_machine the rest of the code is error handling and printing, and now we see of_flat_dt_match implementation, the function is only called directly of_fdt_match only difference is increased initial_boot_params parameters (remember we said in front of said initialization variable bar in fact, this is the kernel of a simple package only).

 685 / **
 686 * of_flat_dt_match - Return true if node matches a list of compatible values
 687 * /
 688 int __init of_flat_dt_match (unsigned long node, const char * const * compat)
 689 {
 690 return of_fdt_match (initial_boot_params, node, compat);
 691}

of_fdt_match function from the beginning of the line 142 through each compat string array, and then calculate the matching degree by of_fdt_is_compatible function (with a minimum value as the final result). Code into this place has a good understanding, .arch.info.init segment data compat in from the kernel, the kernel segment represents the supported platforms, blob is actually address device tree, the root node by node node compatible properties, then calculate the matching degree. Remember when we said compatible front property contains multiple strings, increasing the range of front to back, priority matching front, this place code calculates the score (score variable) is for this purpose.
 131 / **
 132 * of_fdt_match - Return true if node matches a list of compatible values
 133 * /
 134 int of_fdt_match (const void * blob, unsigned long node,
 135 const char * const * compat)
 136 {
 137 unsigned int tmp, score = 0;
 138
 139 if (! Compat)
 140 return 0;
 141
 142 while (* compat) {
 143 tmp = of_fdt_is_compatible (blob, node, * compat);
 144 if (tmp && (score == 0 || (tmp  145 score = tmp;
 146 compat ++;
 147}
 148
 149 return score;
 150}

Continue to look to achieve of_fdt_is_compatible function, the first 97 rows have been seen to find "compatible" under the property of the node.

  80 / **
  81 * of_fdt_is_compatible - Return true if given node from the given blob has
  82 * compat in its compatible list
  83 * @blob: A device tree blob
  84 * @node: node to test
  85 * @compat: compatible string to compare with compatible list.
  * 86
  87 * On match, returns a non-zero value with smaller values ​​returned for more
  88 * specific compatible values.
  89 * /
  90 int of_fdt_is_compatible (const void * blob,
  91 unsigned long node, const char * compat)
  92 {
  93 const char * cp;
  94 int cplen;
  95 unsigned long l, score = 0;
  96
  97 cp = fdt_getprop (blob, node, "compatible", & cplen);
  98 if (cp == NULL)
  99 return 0;
 100 while (cplen> 0) {
 101 score ++;
 102 if (of_compat_cmp (cp, compat, strlen (compat)) == 0)
 103 return score;
 104 l = strlen (cp) + 1;
 105 cp + = l;
 106 cplen - = l;
 107}
 108
 109 return 0;
 110}

About "compatible" attribute of the root node we spoke of this, stating at the kernel is "compatible" attribute to find the corresponding platform description, in accordance with the range from small to large range of possible matching the smallest, if not match, then that kernel does not support the platform, the system will be initialized when the error occurred.

Properties may also contain the root of # address-cells and # size-cells, described in the specification of these two properties are required, the actual application is optional, remember that section said that the two properties if no property there are default values, # address-cells the default value is 2, # size-cells default is 1. Child nodes under the root node must contain the cpus and memory, the back will explain below there each child node of cpu cpus, memory node is defined below the starting memory address and size, so the root node # address-cells and # size-cells property actually is described from the perspective of cpu system bus address length and size.

Specification also written below the root node must have a epapr-version attributes used to describe the device tree version, in fact, in linux do not have this property.

memory & chosen node

We have said that the root section, the simplest device tree must also contain cpus node and memory nodes. memory node is used to describe the hardware memory layout. If you have multiple memory, either through a plurality of memory nodes that can also be supported by a plurality of elements of a memory node reg property. As an example, if a system has two 64-bit memory, respectively,

• RAM: starting address 0x0, length 0x80000000 (2GB)
• RAM: starting address 0x100000000, length 0x100000000 (4GB)

For 64-bit systems, the root node # address-cells attributes and attribute # size-cells are set to 2. A memory node in the form below (remember the node address mentioned in the previous sections must be the same thing and reg property first address bar):
    memory @ 0 {
        device_type = "memory";
        reg = <0x000000000 0x00000000 0x00000000 0x80000000
              0x000000001 0x00000000 0x00000001 0x00000000>;
    };

In the form of two memory nodes as follows:
    memory @ 0 {
        device_type = "memory";
        reg = <0x000000000 0x00000000 0x00000000 0x80000000>;
    };
    memory @ 100000000 {
        device_type = "memory";
        reg = <0x000000001 0x00000000 0x00000001 0x00000000>;
    };

chosen node is also located under the root node, the node is used to pass arguments to the kernel (do not represent actual hardware). For the Linux kernel, this node is most useful properties bootargs, the type of the property is a string used to pass to the Linux kernel cmdline. Specification also defines stdout-path stdin-path and two optional, string type of property, the purpose of these two properties are used to specify the standard input and output devices in linux, without these two basic attributes .

memory and kernel initialization code chosen nodes are located start_kernel () -> setup_arch () -> setup_machine_fdt () -> early_init_dt_scan_nodes () function (located in drivers / of / fdt.c), copy the code as follows (all the code in this section both from the official kernel 4.4-rc7 version):

1078 void __init early_init_dt_scan_nodes (void)
1079 {
1080 / * Retrieve various information from the / chosen node * /
1081 of_scan_flat_dt (early_init_dt_scan_chosen, boot_command_line);
1082
1083 / * Initialize {size, address} -cells info * /
1084 of_scan_flat_dt (early_init_dt_scan_root, NULL);
1085
1086 / * Setup memory, calling early_init_dt_add_memory_arch * /
1087 of_scan_flat_dt (early_init_dt_scan_memory, NULL);
1088}

of_scan_flat_dt function scans the entire device tree, the actual operation is done in the callback function. 1081 line is chosen node operation, the role of the line of code is a string bootargs attribute node under boot_command_line copied to the memory pointed. boot_command_line is a global variable of the kernel, the kernel of many are used. Line 1084 is based on the root node # address-cells attributes and attribute # size-cells and initialize global variables dt_root_size_cells dt_root_addr_cells, remember the front said that if property is not set, then use the default values, which are implemented in early_init_dt_scan_root function. 1087 line is the memory is initialized, early_init_dt_scan_memory copy part of the code is as follows:

 893 / **
 894 * early_init_dt_scan_memory - Look for an parse memory nodes
 895 * /
 896 int __init early_init_dt_scan_memory (unsigned long node, const char * uname,
 897 int depth, void * data)
 898 {
 899 const char * type = of_get_flat_dt_prop (node, "device_type", NULL);
 900 const __be32 * reg, * endp;
 901 int l;
 902
 903 / * We are scanning "memory" nodes only * /
 904 if (type == NULL) {
 905 / *
 906 * The longtrail does not have a device_type on the
 907 * / memory node, so look for the node called / memory @ 0.
 908 * /
 909 if (! IS_ENABLED (CONFIG_PPC32) || depth! = 1 || strcmp (uname, "memory @ 0")! = 0)
 910 return 0;
 911} else if (strcmp (type, "memory")! = 0)
 912 return 0;
 913
 914 reg = of_get_flat_dt_prop (node, "linux, usable-memory", & l);
 915 if (reg == NULL)
 916 reg = of_get_flat_dt_prop (node, "reg", & l);
 917 if (reg == NULL)
 918 return 0;
 919
 920 endp = reg + (l / sizeof (__ be32));
 921
 922 pr_debug ( "memory scan node% s, reg size% d, \ n", uname, l);
 923
 924 while ((endp - reg)> = (dt_root_addr_cells + dt_root_size_cells)) {
 925 u64 base, size;
 926
 927 base = dt_mem_next_cell (dt_root_addr_cells, & reg);
 928 size = dt_mem_next_cell (dt_root_size_cells, & reg);
 929
 930 if (size == 0)
 931 continue;
 932 pr_debug ( "-% llx,% llx \ n", (unsigned long long) base,
 933 (unsigned long long) size);
 934
 935 early_init_dt_add_memory_arch (base, size);
 936}
 937
 938 return 0;
 939}

914 line can be seen not only linux kernel support reg property, and also supports linux, usable-memory properties. For dt_root_addr_cells and dt_root_size_cells use can also see # address-cells properties and # size-cells are used to describe the properties of the root node of the memory address and size. After get the starting address and the size of each block of memory in the first 935 line call early_init_dt_add_memory_arch function, copy the code below:
 
 983 void __init __weak early_init_dt_add_memory_arch (u64 base, u64 size)
 984 {
 985 const u64 phys_offset = __pa (PAGE_OFFSET);
 986
 987 if (! PAGE_ALIGNED (base)) {
 988 if (size  989 pr_warn ( "Ignoring memory block 0x% llx - 0x% llx \ n",
 990 base, base + size);
 991 return;
 992}
 993 size - = PAGE_SIZE - (base & ~ PAGE_MASK);
 994 base = PAGE_ALIGN (base);
 995}
 996 size & = PAGE_MASK;
 997
 998 if (base> MAX_MEMBLOCK_ADDR) {
 999 pr_warning ( "Ignoring memory block 0x% llx - 0x% llx \ n",
1000 base, base + size);
1001 return;
1002}
1003
1004 if (base + size - 1> MAX_MEMBLOCK_ADDR) {
1005 pr_warning ( "Ignoring memory range 0x% llx - 0x% llx \ n",
1006 ((u64) MAX_MEMBLOCK_ADDR) + 1, base + size);
1007 size = MAX_MEMBLOCK_ADDR - base + 1;
1008}
1009
1010 if (base + size 1011 pr_warning ( "Ignoring memory block 0x% llx - 0x% llx \ n",
1012 base, base + size);
1013 return;
1014}
1015 if (base 1016 pr_warning ( "Ignoring memory range 0x% llx - 0x% llx \ n",
1015 if (base 1016 pr_warning ( "Ignoring memory range 0x% llx - 0x% llx \ n",
1017 base, phys_offset);
1018 size - = phys_offset - base;
1019 base = phys_offset;
1020}
1021 memblock_add (base, size);
1022}

After the code can be seen from the above address and size of the kernel to do a series of judgments, the last call memblock_add block of memory added to the kernel.
     
         
         
         
  More:      
 
- MySQL5.7 implement virtual column expression index (Database)
- Linux server is how to do after the invasion (Linux)
- Oracle 11g statistics collection - collection of multi-column statistics (Database)
- J2EE Example of Filter (Programming)
- Ubuntu the ARP (arptables) (Linux)
- Erase do with HTML5 Canvas and diffusion effect (Programming)
- Hadoop namenode do NFS disaster recovery (Server)
- Build a Linux development environment under STC89C52RC (Linux)
- On Android running ClojureScript (Linux)
- Spring Data JPA @EnableJpaRepositories configuration in detail (Programming)
- Linux installation beautify early experience (Linux)
- Four levels of intrusion on Linux server and counter-measures (Linux)
- Installation under Linux to deploy Java (Linux)
- Installation JDK 1.8 under CentOS7 (Linux)
- Zabbix configure DataGuard monitoring (Database)
- C ++ stderr / stdout redirected to a file (Programming)
- Linux stand-alone OGG synchronous Oracle 11g DB test (Database)
- Understanding Linux firewall Iptables (Linux)
- After SSH change the default port, how to use Git (Linux)
- Database start listening TNS-12537, TNS-12560 error (Database)
     
           
     
  CopyRight 2002-2020 newfreesoft.com, All Rights Reserved.