/* set GPIO5_IO03 as GPIO */ staticvolatileunsignedint *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1; /* set GPIO4_IO14 as GPIO */ staticvolatileunsignedint *IOMUXC_SW_MUX_CTL_PAD_NAND_CE1_B;
[root@xxx]~# mount /dev/root on / type squashfs (ro,relatime) devtmpfs on /dev type devtmpfs (rw,relatime,size=1381884k,nr_inodes=345471,mode=755) proc on /proc type proc (rw,relatime) #procfs sysfs on /sys type sysfs (rw,relatime) #sysfs nodev on /sys/kernel/debug type debugfs (rw,relatime) #debugfs /dev/mmcblk0p6 on /mnt/cfg type ext4 (rw,sync,relatime) /dev/mmcblk0p7 on /mnt/data type ext4 (rw,sync,relatime) /dev/mmcblk0p7 on /var/log type ext4 (rw,sync,relatime)
fail_printk: printk("unable to get major %d for misc devices\n", MISC_MAJOR); class_destroy(misc_class); fail_remove: remove_proc_entry("misc", NULL); return err; }
num = sscanf(input, "%s %d %d %d", str, &a, &v, &v2); if (num > 4) { dbg_print_usage(link->dev); return -EINVAL; }
dev_info(link->dev, "input = %s %d\n", str, num); /* convert to lower case for following type compare */ p = str; for (; *p; ++p) *p = tolower(*p); n = ARRAY_SIZE(dbg_type); for (i = 0; i < n; i++) { if (!strcmp(str, dbg_type[i])) { t = i; break; } } if (i == n) { dev_info(link->dev, "unknown type(%s)!\n", str); dbg_print_usage(link->dev); return -EINVAL; } switch (t) { case0: /* reset */ if (a > MAX_LINK_NUM) return -EINVAL;
seq_printf(m, "\nModule: [MIPI_RX], Build Time[%s]\n", UTS_VERSION); seq_puts(m, "\n------------Combo DEV ATTR--------------\n"); for (i = 0; i < MAX_LINK_NUM; i++) if (dev->link[i].is_on) cif_show_dev_attr(m, &dev->link[i].attr);
/** * cma_release() - release allocated pages * @cma: Contiguous memory region for which the allocation is performed. * @pages: Allocated pages. * @count: Number of allocated pages. * * This function releases memory allocated by cma_alloc(). * It returns false when provided pages do not belong to contiguous area and * true otherwise. */ boolcma_release(struct cma *cma, conststruct page *pages, unsignedint count);
对于自旋锁而言,如果自旋锁 正在被线程 A 持有,线程 B 想要获取自旋锁,那么线程 B 就会处于忙循环-旋转-等待状态,线 程 B 不会进入休眠状态或者说去做其他的处理,而是会一直傻傻的在那里“转圈圈”的等待锁 可用。比如现在有个公用电话亭,一次肯定只能进去一个人打电话,现在电话亭里面有人正在 打电话,相当于获得了自旋锁。此时你到了电话亭门口,因为里面有人,所以你不能进去打电 话,相当于没有获取自旋锁,这个时候你肯定是站在原地等待,你可能因为无聊的等待而转圈 圈消遣时光,反正就是哪里也不能去,要一直等到里面的人打完电话出来。终于,里面的人打 完电话出来了,相当于释放了自旋锁,这个时候你就可以使用电话亭打电话了,相当于获取到 了自旋锁。
自旋锁的“自旋”也就是“原地打转”的意思,“原地打转”的目的是为了等待自旋锁可以 用,可以访问共享资源。把自旋锁比作一个变量 a,变量 a=1 的时候表示共享资源可用,当 a=0 的时候表示共享资源不可用。现在线程 A 要访问共享资源,发现 a=0(自旋锁被其他线程持有), 那么线程 A 就会不断的查询 a 的值,直到 a=1。可
void spin_lock_irqsave(spinlock_t *lock,unsigned long flags)
保存中断状态,禁止本地中断,并获取自旋锁。
void spin_unlock_irqrestore(spinlock_t*lock, unsigned long flags)
将中断状态恢复到以前的状态,并且激活本地中断,释放自旋锁
如下图就是没有禁止本地中断导致死锁的例子:
线程 A 先运行,并且获取到了 lock 这个锁,当线程 A 运行 functionA 函 数的时候中断发生了,中断抢走了 CPU 使用权。右边的中断服务函数也要获取 lock 这个锁, 但是这个锁被线程 A 占有着,中断就会一直自旋,等待锁有效。但是在中断服务函数执行完之前,线程 A 是不可能执行的,线程 A 说“你先放手”,中断说“你先放手”,场面就这么僵持着, 死锁发生!
相比于自旋锁,信号量可以使线程进入休眠状态,比如 A 与 B、C 合租了一套房子,这个 房子只有一个厕所,一次只能一个人使用。某一天早上 A 去上厕所了,过了一会 B 也想用厕 所,因为 A 在厕所里面,所以 B 只能等到 A 用来了才能进去。B 要么就一直在厕所门口等着, 等 A 出来,这个时候就相当于自旋锁。B 也可以告诉 A,让 A 出来以后通知他一下,然后 B 继 续回房间睡觉,这个时候相当于信号量。可以看出,使用信号量会提高处理器的使用效率,毕 竟不用一直傻乎乎的在那里“自旋”等待。但是,信号量的开销要比自旋锁大,因为信号量使 线程进入休眠状态以后会切换线程,切换线程就会有开销。
在 SMP 架构中,每个 CPU 都拥有自己的高速缓存,通常,L1 cache 是 CPU 独占的,每个 CPU 都有一份,它的速度自然是最快的,而 L2 cache 通常是所有 CPU 共享的高速缓存,当 CPU 载入一个全局数据时,会逐级地查看高速缓存,如果没有在缓存中命中,就从内存中载入,并加入到各级 cache 中,当下次需要读取这个值时,直接读取 cache 。
// 获取当前CPU的percpu变量的值 int value = per_cpu(val, smp_processor_id()); // 遍历所有CPU,并打印percpu变量的值 for_each_possible_cpu(cpu) { value = per_cpu(val, cpu); printk(KERN_INFO "my_percpu_var on CPU%d is %d\n", cpu, value); }
/*put_cpu_var 和 get_cpu_var 是成对出现的,因为这段期间内静止内核抢占, *它们之间的代码不宜执行太长时间。 */ int *pint = &get_cpu_var(val);//获取当前 CPU 的 percpu 变量的地址进行操作 *pint++; put_cpu_var(val);
<id>:<runlevels>:<action>:<process> <id>:每个指令的标识符,不能重复。但是对于 busybox 的 init 来说,<id>有着特殊意义。对于 busybox 而言<id>用来指定启动进程的控制 tty,一般我们将串口或者 LCD 屏幕设置为控制 tty。 <runlevels>:对 busybox 来说此项完全没用,所以空着。 <action>:动作,用于指定<process>可能用到的动作: busybox 支持的动作如下: sysinit: 在系统初始化的时候 process 才会执行一次。 respawn: 当 process 终止以后马上启动一个新的。 askfirst:和 respawn 类似,在运行 process 之前在控制台上显示“Please press Enter to activate this console.”。只要用户按下“Enter”键以后才会执行 process。 wait: 告诉 init,要等待相应的进程执行完以后才能继续执行。 once: 仅执行一次,而且不会等待 process 执行完成。 restart: 当 init 重启的时候才会执行 procee。 ctrlaltdel: 当按下 ctrl+alt+del 组合键才会执行 process。 shutdown: 关机的时候执行 process。 <process>:具体的动作,比如程序、脚本或命令等
我们的/etc/inittab内容设置如下:
1 2 3 4 5 6 7
#etc/inittab ::sysinit:/etc/init.d/rcS console::askfirst:-/bin/sh ::restart:/sbin/init ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r ::shutdown:/sbin/swapoff -a
# Generated by NetworkManager nameserver 192.168.248.2
一般将nameserver设置成网关地址,再加入8.8.8.8和114.114.114.114
ping blog.csdn.com:
1 2 3 4
[root@node2 ~]# ping blog.csdn.com PING blog.csdn.com.com (45.11.57.36) 56(84) bytes of data. 64 bytes from comcomproxy1.com.com (45.11.57.36): icmp_seq=1 ttl=44 time=291 ms 64 bytes from comcomproxy1.com.com (45.11.57.36): icmp_seq=2 ttl=44 time=270 ms
ping blog,发现不通,需要设置domain域:
1 2
[root@node2 ~]# ping blog ping: blog: 未知的名称或服务
调整/etc/resolv.conf配置文件,添加domain
1 2 3 4
[root@node2 ~]# vi /etc/resolv.conf # Generated by NetworkManager nameserver 192.168.248.2 domain csdn.net
再次ping blog, ping不完整域名会自动补全
1 2 3
[root@node2 ~]# ping blog PING blog.csdn.net (182.92.187.217) 56(84) bytes of data. 64 bytes from 182.92.187.217 (182.92.187.217): icmp_seq=1 ttl=89 time=20.4 ms
调整/etc/resolv.conf配置文件,添加search
1 2 3 4
[root@node2 ~]# vi /etc/resolv.conf # Generated by NetworkManager nameserver 192.168.248.2 search abc.com csdn.net
492 OUTPUT_ARCH(arm) 493 ENTRY(stext) 494 jiffies = jiffies_64; 495 SECTIONS 496 { 497/* 498 * XXX: The linker does not define how output sections are 499 * assigned to input sections when there are multiple statements 500 * matching the same input section name. There is no documented 501 * order of matching. 502 * 503 * unwind exit sections must be discarded before the rest of the 504 * unwind sections get included. 505 */ 506 /DISCARD/ : { 507 *(.ARM.exidx.exit.text) 508 *(.ARM.extab.exit.text) 509 ...... 645 }
/* * Need to run as early as possible, to initialize the * lockdep hash: */ lockdep_init(); set_task_stack_end_magic(&init_task); smp_setup_processor_id(); debug_objects_early_init();
/* * Set up the the initial canary ASAP: */ boot_init_stack_canary();
/* * These use large bootmem allocations and must precede * kmem_cache_init() */ setup_log_buf(0); pidhash_init(); vfs_caches_init_early(); sort_main_extable(); trap_init(); mm_init();
/* * Set up the scheduler prior starting any interrupts (such as the * timer interrupt). Full topology setup happens at smp_init() * time - but meanwhile we still have a functioning scheduler. */ sched_init(); /* * Disable preemption - early bootup scheduling is extremely * fragile until we cpu_idle() for the first time. */ preempt_disable(); if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n")) local_irq_disable(); idr_init_cache(); rcu_init();
/* trace_printk() and trace points may be used after this */ trace_init();
/* * HACK ALERT! This is early. We're enabling the console before * we've done PCI setups etc, and console_init() must be aware of * this. But we do want output early, in case something goes wrong. */ console_init(); if (panic_later) panic("Too many boot %s vars at `%s'", panic_later, panic_param);
lockdep_info();
/* * Need to run this when irqs are enabled, because it wants * to self-test [hard/soft]-irqs on/off lock inversion bugs * too: */ locking_selftest();
#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok && page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) { pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n", page_to_pfn(virt_to_page((void *)initrd_start)), min_low_pfn); initrd_start = 0; } #endif page_ext_init(); debug_objects_mem_init(); kmemleak_init(); setup_per_cpu_pageset(); numa_policy_init(); if (late_time_init) late_time_init(); sched_clock_init(); calibrate_delay(); pidmap_init(); anon_vma_init(); acpi_early_init(); #ifdef CONFIG_X86 if (efi_enabled(EFI_RUNTIME_SERVICES)) efi_enter_virtual_mode(); #endif #ifdef CONFIG_X86_ESPFIX64 /* Should be run before the first non-init thread is created */ init_espfix_bsp(); #endif thread_info_cache_init(); cred_init(); fork_init(); proc_caches_init(); buffer_init(); key_init(); security_init(); dbg_late_init(); vfs_caches_init(totalram_pages); signals_init(); /* rootfs populating might need page-writeback */ page_writeback_init(); proc_root_init(); nsfs_init(); cpuset_init(); cgroup_init(); taskstats_init_early(); delayacct_init();
check_bugs();
acpi_subsystem_init(); sfi_init_late();
if (efi_enabled(EFI_RUNTIME_SERVICES)) { efi_late_init(); efi_free_boot_services(); }
ftrace_init();
/* Do the rest non-__init'ed, we're now alive */ rest_init(); }
static noinline void __init_refok rest_init(void) { int pid;
rcu_scheduler_starting(); smpboot_thread_init(); /* * We need to spawn init first so that it obtains pid 1, however * the init task will end up wanting to create kthreads, which, if * we schedule it before we create kthreadd, will OOPS. */ kernel_thread(kernel_init, NULL, CLONE_FS); numa_default_policy(); pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); rcu_read_lock(); kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns); rcu_read_unlock(); complete(&kthreadd_done);
/* * The boot idle thread must execute schedule() * at least once to get things moving: */ init_idle_bootup_task(current); schedule_preempt_disabled(); /* Call into cpu_idle with preempt disabled */ cpu_startup_entry(CPUHP_ONLINE); }
staticint __ref kernel_init(void *unused) { int ret; kernel_init_freeable(); /* init 进程的一些其他初始化工作 */ /* need to finish all async __init code before freeing the memory */ async_synchronize_full(); /* 等待所有的异步调用执行完成 */ free_initmem(); /* 释放 init 段内存 */ mark_rodata_ro(); system_state = SYSTEM_RUNNING; /* 标记系统正在运行 */ numa_default_policy();
flush_delayed_fput();
if (ramdisk_execute_command) { ret = run_init_process(ramdisk_execute_command); if (!ret) return0; pr_err("Failed to execute %s (error %d)\n", ramdisk_execute_command, ret); }
/* * We try each of these until one succeeds. * * The Bourne shell can be used instead of init if we are * trying to recover a really broken machine. */ if (execute_command) { ret = run_init_process(execute_command); if (!ret) return0; panic("Requested init %s failed (error %d).", execute_command, ret); } if (!try_to_run_init_process("/sbin/init") || !try_to_run_init_process("/etc/init") || !try_to_run_init_process("/bin/init") || !try_to_run_init_process("/bin/sh")) return0;
panic("No working init found. Try passing init= option to kernel. " "See Linux Documentation/init.txt for guidance."); }
static noinline void __init kernel_init_freeable(void) { /* * Wait until kthreadd is all set-up. */ wait_for_completion(&kthreadd_done);/* 等待 kthreadd 进程准备就绪 */ smp_init(); /* SMP 初始化 */ sched_init_smp(); /* 多核(SMP)调度初始化 */ do_basic_setup(); /* 设备初始化都在此函数中完成 */ /* Open the /dev/console on the rootfs, this should never fail */ if (sys_open((constchar __user *) "/dev/console", O_RDWR, 0) < 0) pr_err("Warning: unable to open an initial console.\n"); (void) sys_dup(0); (void) sys_dup(0); /* * check if there is an early userspace init. If yes, let it do * all the work */ if (!ramdisk_execute_command) ramdisk_execute_command = "/init"; if (sys_access((constchar __user *) ramdisk_execute_command, 0) != 0) { ramdisk_execute_command = NULL; prepare_namespace(); } /* * Ok, we have completed the initial bootup, and * we're essentially up and running. Get rid of the * initmem segments and start the user-mode stuff.. * * rootfs is available now, try loading the public keys * and default modules */ integrity_load_keys(); load_default_modules(); }