如下图所示,当我配置外部工具链的时候最上面一行字“Linaro toochains available for Cortex-A + EABIhf”
难道Linaro工具链编译LicheePi Nano的Buildroot真的不可用?我尝试了一把,结果上电后就gg了。。。直接Kernel panic,exitcode是0x0000000b
但是选择让buildroot自己下载使用Sourcery CodeBench ARM 2014.5的话,同样的配置,是可以正常工作的
离线
应该是这个问题了,hf是硬件浮点数,
而arm926-ejs根本没有这玩意。
可是我用的linaro是linux-arm-gnueabi版本的,没带hf,用来编译uboot和kernel都好好的:|
离线
这个问题也浪费了我几个小时,后来拿云盘上给的那个rootfs来对比,才发现:
1. arm-linux-gnueabi 这个工具链用来编译内核没有问题,编译应用则会出现问题;
2. 编译应用的问题,是因为工具链所附加的库,是面向Cortex A7来编译的;因为假如只编译,不链接: arm-linux-gnueabi-gcc -Q -v -c -mcpu=arm926ej-s hello.c ,然后用readelf -A hello.o,会发现:Tag_CPU_name: "ARM926EJ-S";但只要链接了库,就成了:Tag_CPU_name: "7-A"
3. 解决方法,重新编译工具链,使得它附带的库是用于ARM926EJ-S的,方法是:
https://briolidz.wordpress.com/2012/02/07/building-embedded-arm-systems-with-crosstool-ng/
http://unisim-vp.org/site/crosstool-arm-926ejs-linux-gnueabi-how-to.html
4. 之后再使用编译出来的external toolchain,也是完全OK的。
离线
在搞xboot的时候似乎也遇到了需要某个历史版本的toolchain才能用的问题,我估计也是类似的原因,没空验证了。
离线
这个问题也浪费了我几个小时,后来拿云盘上给的那个rootfs来对比,才发现:
1. arm-linux-gnueabi 这个工具链用来编译内核没有问题,编译应用则会出现问题;2. 编译应用的问题,是因为工具链所附加的库,是面向Cortex A7来编译的;因为假如只编译,不链接: arm-linux-gnueabi-gcc -Q -v -c -mcpu=arm926ej-s hello.c ,然后用readelf -A hello.o,会发现:Tag_CPU_name: "ARM926EJ-S";但只要链接了库,就成了:Tag_CPU_name: "7-A"
3. 解决方法,重新编译工具链,使得它附带的库是用于ARM926EJ-S的,方法是:
https://briolidz.wordpress.com/2012/02/07/building-embedded-arm-systems-with-crosstool-ng/
http://unisim-vp.org/site/crosstool-arm-926ejs-linux-gnueabi-how-to.html4. 之后再使用编译出来的external toolchain,也是完全OK的。
分析的很有道理,又学了一招。
我后来也是用crosstool-ng自己编了一套,还把c库换成了uclibc
离线
感谢@pighead @msr06rr 碰到同样问题,谢谢指路,我试试
离线
@晕哥,现在根文件系统能启动,自己编译的.ko点灯不行
U-Boot SPL 2018.01 (Sep 15 2018 - 16:38:45)
DRAM: 32 MiB
Trying to boot from sunxi SPI
U-Boot 2018.01 (Sep 15 2018 - 16:38:45 +1400) Allwinner Technology
CPU: Allwinner F Series (SUNIV)
Model: Lichee Pi Nano
DRAM: 32 MiB
MMC: SUNXI SD/MMC: 0
SF: Detected w25q128bv with page size 256 Bytes, erase size 4 KiB, total 16 MiB
*** Warning - bad CRC, using default environment
Setting up a 800x480 lcd console (overscan 0x0)
In: serial
Out: vga
Err: vga
Net: No ethernet found.
starting USB...
No controllers found
Hit any key to stop autoboot: 0
SF: Detected w25q128bv with page size 256 Bytes, erase size 4 KiB, total 16 MiB
device 0 offset 0x100000, size 0x4000
SF: 16384 bytes @ 0x100000 Read: OK
device 0 offset 0x110000, size 0x400000
SF: 4194304 bytes @ 0x110000 Read: OK
## Flattened Device Tree blob at 80c00000
Booting using the fdt blob at 0x80c00000
Loading Device Tree to 80e60000, end 80e64da2 ... OK
Cannot setup simplefb: node not found
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 4.15.0-rc8-licheepi-nano+ (root@gx) (gcc version 7.2.1 20171011 (Linaro GCC 7.2-2017.11)) #41 Sat Sep 15 22:18:28 LINT 2018
[ 0.000000] CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=0005317f
[ 0.000000] CPU: VIVT data cache, VIVT instruction cache
[ 0.000000] OF: fdt: Machine model: Lichee Pi Nano
[ 0.000000] Memory policy: Data cache writeback
[ 0.000000] random: fast init done
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 8128
[ 0.000000] Kernel command line: console=ttyS0,115200 earlyprintk panic=5 rootwait mtdparts=spi0.0:1M(uboot)ro,64k(dtb)ro,4M(kernel)ro,-(rootfs) root=31:03 rw rootfstype=jffs2
[ 0.000000] Dentry cache hash table entries: 4096 (order: 2, 16384 bytes)
[ 0.000000] Inode-cache hash table entries: 2048 (order: 1, 8192 bytes)
[ 0.000000] Memory: 24808K/32768K available (4096K kernel code, 189K rwdata, 1052K rodata, 1024K init, 216K bss, 7960K reserved, 0K cma-reserved, 0K highmem)
[ 0.000000] Virtual kernel memory layout:
[ 0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB)
[ 0.000000] fixmap : 0xffc00000 - 0xfff00000 (3072 kB)
[ 0.000000] vmalloc : 0xc2800000 - 0xff800000 ( 976 MB)
[ 0.000000] lowmem : 0xc0000000 - 0xc2000000 ( 32 MB)
[ 0.000000] pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
[ 0.000000] modules : 0xbf000000 - 0xbfe00000 ( 14 MB)
[ 0.000000] .text : 0x(ptrval) - 0x(ptrval) (5088 kB)
[ 0.000000] .init : 0x(ptrval) - 0x(ptrval) (1024 kB)
[ 0.000000] .data : 0x(ptrval) - 0x(ptrval) ( 190 kB)
[ 0.000000] .bss : 0x(ptrval) - 0x(ptrval) ( 217 kB)
[ 0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[ 0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[ 0.000053] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 89478484971ns
[ 0.000123] clocksource: timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
[ 0.000735] Console: colour dummy device 80x30
[ 0.000832] Calibrating delay loop... 203.16 BogoMIPS (lpj=1015808)
[ 0.070246] pid_max: default: 32768 minimum: 301
[ 0.070572] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.070622] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.072229] CPU: Testing write buffer coherency: ok
[ 0.074108] Setting up static identity map for 0x80100000 - 0x80100058
[ 0.076751] devtmpfs: initialized
[ 0.083143] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[ 0.083213] futex hash table entries: 256 (order: -1, 3072 bytes)
[ 0.083500] pinctrl core: initialized pinctrl subsystem
[ 0.085455] NET: Registered protocol family 16
[ 0.087352] DMA: preallocated 256 KiB pool for atomic coherent allocations
[ 0.089301] cpuidle: using governor menu
[ 0.108346] SCSI subsystem initialized
[ 0.108623] pps_core: LinuxPPS API ver. 1 registered
[ 0.108651] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 0.110497] clocksource: Switched to clocksource timer
[ 0.139542] NetWinder Floating Point Emulator V0.97 (double precision)
[ 0.141705] Initialise system trusted keyrings
[ 0.142293] workingset: timestamp_bits=30 max_order=13 bucket_order=0
[ 0.156798] jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
[ 0.172139] Key type asymmetric registered
[ 0.172184] Asymmetric key parser 'x509' registered
[ 0.172408] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 252)
[ 0.172443] io scheduler noop registered
[ 0.172460] io scheduler deadline registered
[ 0.172968] io scheduler cfq registered (default)
[ 0.173002] io scheduler mq-deadline registered
[ 0.173022] io scheduler kyber registered
[ 0.183285] suniv-pinctrl 1c20800.pinctrl: initialized sunXi PIO driver
[ 0.371289] Serial: 8250/16550 driver, 8 ports, IRQ sharing disabled
[ 0.378461] console [ttyS0] disabled
[ 0.398744] 1c25000.serial: ttyS0 at MMIO 0x1c25000 (irq = 23, base_baud = 6250000) is a 16550A
[ 0.770996] console [ttyS0] enabled
[ 0.781733] panel-simple panel: panel supply power not found, using dummy regulator
[ 0.791335] SCSI Media Changer driver v0.25
[ 0.799229] m25p80 spi0.0: w25q128 (16384 Kbytes)
[ 0.804124] 4 cmdlinepart partitions found on MTD device spi0.0
[ 0.810042] Creating 4 MTD partitions on "spi0.0":
[ 0.814931] 0x000000000000-0x000000100000 : "uboot"
[ 0.821233] 0x000000100000-0x000000110000 : "dtb"
[ 0.826946] 0x000000110000-0x000000510000 : "kernel"
[ 0.833082] 0x000000510000-0x000001000000 : "rootfs"
[ 0.839624] i2c /dev entries driver
[ 0.848205] Loading compiled-in X.509 certificates
[ 0.862394] sun4i-drm display-engine: bound 1e60000.display-backend (ops 0xc0535f98)
[ 0.871266] sun4i-drm display-engine: bound 1c0c000.lcd-controller (ops 0xc053527c)
[ 0.878932] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[ 0.885624] [drm] No driver support for vblank timestamp query.
[ 0.939417] Console: switching to colour frame buffer device 60x34
[ 0.962795] sun4i-drm display-engine: fb0: frame buffer device
[ 0.969884] [drm] Initialized sun4i-drm 1.0.0 20150629 for display-engine on minor 0
[ 0.978392] vcc3v3: disabling
[ 1.079639] random: crng init done
[ 2.312327] VFS: Mounted root (jffs2 filesystem) on device 31:3.
[ 2.320393] devtmpfs: mounted
[ 2.328151] Freeing unused kernel memory: 1024K
Starting logging: OK
Initializing random number generator... done.
Starting network: ip: can't find device 'lo'
ip: socket: Address family not supported by protocol
FAIL
Welcome to Buildroot for gx
gx login: root
Password:
login[181]: root login on 'console'
# cd /
# cd /lib/modules/4.15.0-rc8-licheepi-nano\+/kernel/drivers/led/
# ls
app misc_led.ko
# insmod misc_led.ko
[ 40.341249] misc_led: loading out-of-tree module taints kernel.
[ 40.348276] ---led init---
# lsmod
Module Size Used by Tainted: G
misc_led 16384 0
# ls /dev/misc*
ls: /dev/misc*: No such file or directory
# ls /dev/led*
/dev/led_misc
# ./app /dev/led_misc led_on
Segmentation fault
# ./app /dev/led_misc led_off
Segmentation fault
# ./app /dev/led_misc
Segmentation fault
我的.ko文件工程[url=https://whycan.cn/files/members/1063/f1c100s_leds_tar.gz]f1c100s_leds_tar.gz[/url]
ko文件信息
modinfo /git/apps/f1c100s_leds/misc_led.ko
filename: /git/apps/f1c100s_leds/misc_led.ko
alias: platform:f1c100s_led
license: GPL
description: led driver
author: gx
srcversion: 4E214EA6B0221E22AFA4DB2
depends:
name: misc_led
vermagic: 4.15.0-rc8-licheepi-nano+ mod_unload ARMv5 p2v8
insmod时会提示loading out-of-tree module taints kernel.
运行时提示Segmentation fault
我编译app .ko 和内核 用的是 arm-linux-gnueabi-gcc,编译根文件系统用的是 Sourcery CodeBench ARM 2014.05
这样有问题吗?还是其他问题。
最近编辑记录 include_h (2018-09-15 16:56:30)
离线
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/uaccess.h>
// Prototypes
static int leds_probe(struct platform_device *pdev);
static int leds_remove(struct platform_device *pdev);
static ssize_t leds_read(struct file *file, char *buffer, size_t len, loff_t *offset);
static ssize_t leds_write(struct file *file, const char *buffer, size_t len, loff_t *offset);
// An instance of this structure will be created for every custom_led IP in the system
struct custom_leds_dev {
struct miscdevice miscdev;
void __iomem *regs;
u8 leds_value;
};
// Specify which device tree devices this driver supports
static struct of_device_id custom_leds_dt_ids[] = {
{
.compatible = "dev,custom-leds"
},
{ /* end of table */ }
};
// Inform the kernel about the devices this driver supports
MODULE_DEVICE_TABLE(of, custom_leds_dt_ids);
// Data structure that links the probe and remove functions with our driver
static struct platform_driver leds_platform = {
.probe = leds_probe,
.remove = leds_remove,
.driver = {
.name = "Custom LEDs Driver",
.owner = THIS_MODULE,
.of_match_table = custom_leds_dt_ids
}
};
// The file operations that can be performed on the custom_leds character file
static const struct file_operations custom_leds_fops = {
.owner = THIS_MODULE,
.read = leds_read,
.write = leds_write
};
// Called when the driver is installed
static int leds_init(void)
{
int ret_val = 0;
pr_info("Initializing the Custom LEDs module\n");
// Register our driver with the "Platform Driver" bus
ret_val = platform_driver_register(&leds_platform);
if(ret_val != 0) {
pr_err("platform_driver_register returned %d\n", ret_val);
return ret_val;
}
pr_info("Custom LEDs module successfully initialized!\n");
return 0;
}
// Called whenever the kernel finds a new device that our driver can handle
// (In our case, this should only get called for the one instantiation of the Custom LEDs module)
static int leds_probe(struct platform_device *pdev)
{
int ret_val = -EBUSY;
struct custom_leds_dev *dev;
struct resource *r = 0;
pr_info("leds_probe enter\n");
// Get the memory resources for this LED device
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if(r == NULL) {
pr_err("IORESOURCE_MEM (register space) does not exist\n");
goto bad_exit_return;
}
// Create structure to hold device-specific information (like the registers)
dev = devm_kzalloc(&pdev->dev, sizeof(struct custom_leds_dev), GFP_KERNEL);
// Both request and ioremap a memory region
// This makes sure nobody else can grab this memory region
// as well as moving it into our address space so we can actually use it
dev->regs = devm_ioremap_resource(&pdev->dev, r);
if(IS_ERR(dev->regs))
goto bad_ioremap;
// Turn the LEDs on (access the 0th register in the custom LEDs module)
dev->leds_value = 0xFF;
iowrite32(dev->leds_value, dev->regs);
// Initialize the misc device (this is used to create a character file in userspace)
dev->miscdev.minor = MISC_DYNAMIC_MINOR; // Dynamically choose a minor number
dev->miscdev.name = "custom_leds";
dev->miscdev.fops = &custom_leds_fops;
ret_val = misc_register(&dev->miscdev);
if(ret_val != 0) {
pr_info("Couldn't register misc device :(");
goto bad_exit_return;
}
// Give a pointer to the instance-specific data to the generic platform_device structure
// so we can access this data later on (for instance, in the read and write functions)
platform_set_drvdata(pdev, (void*)dev);
pr_info("leds_probe exit\n");
return 0;
bad_ioremap:
ret_val = PTR_ERR(dev->regs);
bad_exit_return:
pr_info("leds_probe bad exit :(\n");
return ret_val;
}
// This function gets called whenever a read operation occurs on one of the character files
static ssize_t leds_read(struct file *file, char *buffer, size_t len, loff_t *offset)
{
int success = 0;
/*
* Get the custom_leds_dev structure out of the miscdevice structure.
*
* Remember, the Misc subsystem has a default "open" function that will set
* "file"s private data to the appropriate miscdevice structure. We then use the
* container_of macro to get the structure that miscdevice is stored inside of (which
* is our custom_leds_dev structure that has the current led value).
*
* For more info on how container_of works, check out:
* http://linuxwell.com/2012/11/10/magical-container_of-macro/
*/
struct custom_leds_dev *dev = container_of(file->private_data, struct custom_leds_dev, miscdev);
// Give the user the current led value
success = copy_to_user(buffer, &dev->leds_value, sizeof(dev->leds_value));
// If we failed to copy the value to userspace, display an error message
if(success != 0) {
pr_info("Failed to return current led value to userspace\n");
return -EFAULT; // Bad address error value. It's likely that "buffer" doesn't point to a good address
}
return 0; // "0" indicates End of File, aka, it tells the user process to stop reading
}
// This function gets called whenever a write operation occurs on one of the character files
static ssize_t leds_write(struct file *file, const char *buffer, size_t len, loff_t *offset)
{
int success = 0;
/*
* Get the custom_leds_dev structure out of the miscdevice structure.
*
* Remember, the Misc subsystem has a default "open" function that will set
* "file"s private data to the appropriate miscdevice structure. We then use the
* container_of macro to get the structure that miscdevice is stored inside of (which
* is our custom_leds_dev structure that has the current led value).
*
* For more info on how container_of works, check out:
* http://linuxwell.com/2012/11/10/magical-container_of-macro/
*/
struct custom_leds_dev *dev = container_of(file->private_data, struct custom_leds_dev, miscdev);
// Get the new led value (this is just the first byte of the given data)
success = copy_from_user(&dev->leds_value, buffer, sizeof(dev->leds_value));
// If we failed to copy the value from userspace, display an error message
if(success != 0) {
pr_info("Failed to read led value from userspace\n");
return -EFAULT; // Bad address error value. It's likely that "buffer" doesn't point to a good address
} else {
// We read the data correctly, so update the LEDs
iowrite32(dev->leds_value, dev->regs);
}
// Tell the user process that we wrote every byte they sent
// (even if we only wrote the first value, this will ensure they don't try to re-write their data)
return len;
}
// Gets called whenever a device this driver handles is removed.
// This will also get called for each device being handled when
// our driver gets removed from the system (using the rmmod command).
static int leds_remove(struct platform_device *pdev)
{
// Grab the instance-specific information out of the platform device
struct custom_leds_dev *dev = (struct custom_leds_dev*)platform_get_drvdata(pdev);
pr_info("leds_remove enter\n");
// Turn the LEDs off
iowrite32(0x00, dev->regs);
// Unregister the character file (remove it from /dev)
misc_deregister(&dev->miscdev);
pr_info("leds_remove exit\n");
return 0;
}
// Called when the driver is removed
static void leds_exit(void)
{
pr_info("Custom LEDs module exit\n");
// Unregister our driver from the "Platform Driver" bus
// This will cause "leds_remove" to be called for each connected device
platform_driver_unregister(&leds_platform);
pr_info("Custom LEDs module successfully unregistered\n");
}
// Tell the kernel which functions are the initialization and exit functions
module_init(leds_init);
module_exit(leds_exit);
// Define information about this kernel module
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Devon Andrade <devon.andrade@oit.edu>");
MODULE_DESCRIPTION("Exposes a character device to user space that lets users turn LEDs on and off");
MODULE_VERSION("1.0");
insmod custom_leds.ko
[ 7.800332] custom_leds: loading out-of-tree module taints kernel.
[ 7.806958] Initializing the Custom LEDs module
[ 7.811590] leds_probe enter
[ 7.814676] leds_probe exit
[ 7.817628] Custom LEDs module successfully initialized!
echo -n -e '\x55' > /dev/custom_leds
echo -n -e '\x0' > /dev/custom_leds
echo -n -e '\xFF' > /dev/custom_leds
试一试这个.
在线
@晕哥,试了下你的代码, 在我的上面出现 gpio: can't request region for resource [mem 0x01c208a0-0x01c208a3]报错,可以正常卸载,dts可能有问题。
login[181]: root login on 'console'
# cd /lib/modules/4.15.0-rc8-licheepi-nano\+/kernel/drivers/led/
# ls
app misc_led.ko
# insmod misc_led.ko
[ 36.286371] misc_led: loading out-of-tree module taints kernel.
[ 36.293438] Initializing the Custom LEDs module
[ 36.298300] leds_probe enter
[ 36.301399] Custom LEDs Driver 1c208a0.gpio: can't request region for resource [mem 0x01c208a0-0x01c208a3]
[ 36.311033] leds_probe bad exit :(
[ 36.314544] Custom LEDs Driver: probe of 1c208a0.gpio failed with error -16
[ 36.321733] Custom LEDs module successfully initialized!
# lsmod
Module Size Used by Tainted: G
misc_led 16384 0
# rmmod misc_led.ko
[ 204.783776] Custom LEDs module exit
[ 204.787448] Custom LEDs module successfully unregistered
#
我使用的dts
led: gpio@0x01c208A0{
compatible = "dev,custom-leds";
label = "gxled";
reg = <0x01c208A0 0x04>;
clocks = <&ccu CLK_BUS_PIO>;
gpio-controller;
};
离线
参考这个: https://github.com/Lichee-Pi/linux/tree/zero-4.13.y/arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts
如果你只想把IO驱动成为LED, 可以这么写:
leds {
compatible = "gpio-leds";blue_led {
label = "licheepi:blue:usr";
gpios = <&pio 6 1 GPIO_ACTIVE_LOW>; /* PG1 */
};green_led {
label = "licheepi:green:usr";
gpios = <&pio 6 0 GPIO_ACTIVE_LOW>; /* PG0 */
default-state = "on";
};red_led {
label = "licheepi:red:usr";
gpios = <&pio 6 2 GPIO_ACTIVE_LOW>; /* PG2 */
};
};
添加底板上的 RGB LED 节点配置: http://nano.lichee.pro/build_sys/devicetree.html#id10
在线