Linux v1.2成功移植到ARM平台 (linux v1.2 arm)

Linux v1.2 Successfully Ported to ARM Platform

Introduction

Linux has gned worldwide recognition as an open-source, Unix-like operating system. When Linus Torvalds created the first Linux kernel in 1991, he never imagined that it would become one of the most versatile and widely used OS in the world. Linux was originally designed for x86-based personal computers but has over the years found its way into other hardware architectures including the ARM platform. In this article, we will discuss how Linux v1.2 was successfully ported to the ARM platform.

ARM Architecture

ARM (Advanced RISC Machines) is a reduced instruction set computing (RISC) instruction set architecture (ISA) developed by ARM Holdings. ARM processors are known for their energy efficiency, low power consumption, and high performance. The ARM architecture is widely used in embedded systems, artphones, tablets, and IoT devices. Linux, being an open-source OS, can run on a wide range of hardware platforms, including those based on the ARM architecture.

Linux v1.2

Linux 1.2 was released on March 7, 1995, and was the first version of Linux to run on machines with less than 4MB of RAM. At the time of its release, Linux had support for the i386 architecture, and ports to other architectures were actively being developed. The v1.2 release featured significant improvements over previous releases, including support for ELF binaries, shared libraries, and virtual memory management.

Porting Linux v1.2 to ARM

The initial work on porting Linux v1.2 to ARM began in 1995 by British programmer Russell King. Russell was inspired by the work of Dave Hillis, who had ported an earlier version of Linux to ARM. Russell started by modifying the Linux kernel source code to support the ARM platform, which required the development of a new set of drivers for the platform’s hardware devices. Russell also developed a new bootloader program, which is responsible for loading the Linux kernel into memory.

One of the biggest challenges in porting Linux to ARM was the lack of avlable documentation. At the time, ARM processors and their documentation were proprietary, making it difficult to develop open-source software for the platform. Russell had to rely on reverse engineering and trial and error to get the OS to run on ARM.

Another challenge was the limited memory avlable on the ARM-based devices. Linux v1.2 was designed to run on machines with less than 4MB of RAM, but many ARM-based devices had much less memory than that. Russell had to optimize the operating system to work within these limitations, which required significant manual effort.

Despite these challenges, Russell was successful in porting Linux v1.2 to the ARM platform, and the first ARM-based Linux kernel was released in 1996. Since then, Linux has become the dominant OS in the embedded systems market, with ARM processors being one of the most widely used architectures.

Conclusion

In conclusion, the successful porting of Linux v1.2 to ARM was a significant milestone in the history of Linux. It demonstrated the versatility of the OS, and its ability to run on a wide range of hardware architectures. The porting process required significant effort, and the challenges faced by Russell King are a testament to the dedication and tenacity of open-source developers. Today, Linux continues to evolve, and new ports to emerging architectures will undoubtedly be developed.

相关问题拓展阅读:

ARM linux内核启动时几个关键地址

1.内核启动地址

ZTEXTADDR

解压代码运行的开始地址。没有物理地址和虚拟地址之分,因为此时MMU处于关闭轮渗状态。这个地址不一定时RAM的地址,可以是支持读写寻址的flash等存储中介。

Start address of decompressor. here’s no point in talking about virtual or physical addresses here, since the MMU will be off at the time when you call the decompressor code. You normally call the kernel at this address to start it booting. This doesn’t have to be located in RAM, it can be in flash or other read-only or read-write addressable medium.

在arch/arm/搭指boot/compressed/Makefile中说的很明确

#

# We now have a PIC decompressor implementation. Decompressors running

# from RAM should not define ZTEXTADDR. Decompressors running directly

# from ROM or Flash must define ZTEXTADDR (preferably via the config)

# FIXME: Previous assignment to ztextaddr-y is lost here. See SHARK

ifeq ($(CONFIG_ZBOOT_ROM),y)

ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT)

ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS)

else

ZTEXTADDR :=

ZBSSADDR := ALIGN(8)

endif

ZRELADDR

内核启动在RAM中的地址。压缩的内核映像被解压到这个地址,然后执行。

This is the address where the decompressed kernel will be written, and eventually executed. The following constraint must be valid:

__virt_to_phys(TEXTADDR) == ZRELADDR

The initial part of the kernel is carefully coded to be position independent.

一般定义在项目目录下,比如:

arch/arm/mach-at91/Makefile.boot: zreladdr-y+= 0x

arch/arm/mach-at91/Makefile.boot: zreladdr-y+= 0x

arch/arm/mach-cns3/Makefile.boot: zreladdr-y+= 0x

arch/arm/mach-davinci/Makefile.boot: zreladdr-y+= 0xc

arch/arm/mach-davinci/Makefile.boot: zreladdr-y+= 0x

arch/arm/mach-dove/Makefile.boot: zreladdr-y+= 0x

arch/arm/mach-ebsa110/Makefile.boot: zreladdr-y+= 0x

arch/arm/mach-exynos/Makefile.boot: zreladdr-y+= 0x

arch/腊枝脊arm/mach-footbridge/Makefile.boot: zreladdr-y+= 0x

arch/arm/mach-gemini/Makefile.boot: zreladdr-y+= 0x

arch/arm/mach-gemini/Makefile.boot: zreladdr-y+= 0x

arch/arm/mach-integrator/Makefile.boot: zreladdr-y+= 0x

arch/arm/mach-iop13xx/Makefile.boot: zreladdr-y += 0x

在arch/arm/boot/Makefile中被赋值:

ZRELADDR := $(zreladdr-y)

PARAMS_PHYS := $(params_phys-y)

INITRD_PHYS := $(initrd_phys-y)

… …

ifneq ($(LOADADDR),)

UIMAGE_LOADADDR=$(LOADADDR)

else

ifeq ($(CONFIG_ZBOOT_ROM),y)

UIMAGE_LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)

四 . 树莓派A20 GPIO中断程序编写(1基本处理)

关于按键,在DVK521上为:

我又从一份数据手册中看到,PI7,PI8,PI9是没有外部中断功能的。如下图所示:

还好,目前的按键是通过短接帽来连接PI7

PI9的,那么可以将短接帽拿掉,使用杜邦线连接PI10

PI12。

现在我将Key2连接到PI10上。那么KEY2的中断引脚为EINT22。

配置sys_config.fex文件:

现在使用的树莓派A20,是一个双核A7的芯片,而这个属于P架构,中断处理方式也已经和原先的理念大有不同。所以还是要知道关于linux的中断原理,可以从网络中获取相关历史性技术知识。

从A20的数据手册中,可以看到外部中断数到了EINT31。也就是说PIO中断功能有32个。

下面列出的API函数是在 \linux-sunxi\arch\arm\plat-sunxi\Sys_config.c中。

1.gpio_request_ex(),获取sys_config.fex中设置的中断IO口。

2.gpio_set_one_pin_io_status(),设置为输入状态。

3.gpio_set_one_pin_pull(),设置输入引脚的上下拉状态。

4.request_irq()注册中断函数。

request_irq()函数:

之一个参数为SW_INT_IRQNO_PIO,表示是外部并尺端口的中断号。

第二个参数为中断处理函数名。

第三个参数为中断方式,如IRQ_TYPE_EDGE_RISING,上升沿触发,而IRQ_TYPE_EDGE_FALLING则是下降沿触发,IRQF_SHARED为共享。

第四个参数为中断名。

第五个参数为中断传递的数据。

1.获取IO中断源信息

由于内核使用的是虚拟地址寻址硬件地址,获取中断源就需要将IO硬件地址空间映射到虚拟地址上。可以使用ioremap(PIO_BASE_ADDRESS, PIO_RANGE_SIZE)进行映射。

2.屏蔽中断源

a.读取中断源寄存器的状态,可以使用readl(映射的IO地址 + PIO_INT_STAT_OFFSET);

b.判断对应的中断,使用writel(reg_val&(1

写到这里,本应该很顺利,可是,在驱动程序加载进内核的时候,明显是报错。错误我就不贴出来了,可是我可以将中断信息附上:

从这里,可以看出来,PIO中断号60已经注册进内核了。我们现在使用的一个IO中断是被包含在里面的。所以,需要在内核中找到sunxi-gpio是怎么去注册中断,而我们就需绝兆高要将我们的中断程序内容附加到已经注册的中断上去。

在 maroard\maroard-a20-linux-sdk-v1.2\linux-sunxi\drivers\gpio\Gpio-sunxi.c中我们可以找到函数:

里面最重要的函数是:

最终调用的是:

然而,它又被赋值了:

在一定程度的意义上,gpio-sunxi.c已经猜御将中断基本处理做好了,我们要做的只是和它共享中断。

sys_config.fex文件配置如下:

从上面的实验中,已经发现在request_irq中设置边沿等等触发,在安装ko文件的时候,都会报错,从这里看出,在共享中断的时候,是不允许设置其他的内容的。那么,只能去找A20寄存器中关于io口中断的设置。在这些设置已经设置好的情况下,中断应该就能响应了。这里贴出一个比较简单的驱动程序:

int main(int argc,char *argv)

{

int fd;

int val;

fd = open(“/dev/key_device”,O_RDWR);

if(fd

printf(“—open file error—-\r\n”);

return -1;

}

}

ifeq ($(KERNELRELEASE),)

KERNEL_DIR=/home/wityuan/Downloads/MarsBoard-A20-Linux-SDK-V1.2/linux-sunxi

PWD=$(shell pwd)

modules:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules

arm-linux-gnueabihf-gcc -o key key.c

modules_install:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install

clean:

rm -rf *.ko *.o .tmp_versions

.mod.c modules.order Module.symvers .

.cmd

else

obj-m:=key.o

endif

root@maroard:~# ./key_test

—script.bin key get ok,value:1—-

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

^Ckey irq Interrupt

Other Interrupt

key close—-

root@maroard:~#

root@maroard:~#

/* EINT type PIO controller registers */

/* EINT type defines */

static int int_cfg_addr = {PIO_INT_CFG0_OFFSET,

PIO_INT_CFG1_OFFSET,

PIO_INT_CFG2_OFFSET,

PIO_INT_CFG3_OFFSET};

/* Setup GPIO irq mode (FALLING, RISING, BOTH, etc */

})

/* Enable GPIO interrupt for pin */

})

/* Disable GPIO interrupt for pin */

})

/* Set GPIO pin mode (input, output, etc)

/

/

GPIO port has 4 cfg 32bit registers (8 pins each)

/

/

First port cfg register addr = port_num * 0x24 */

})

static script_gpio_set_t info;

static unsigned key_handler1;

static unsigned key_handler2;

static struct class *key_class;

static struct device *key_device;

static unsigned int key_major;

static unsigned int key_value;

static void *__iomem gpio_addr = NULL;

static int key_open(struct inode *inode, struct file *filp);

static ssize_t key_read (struct file *, char __user *, size_t, loff_t *);

static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off);

static int key_close(struct inode *inode, struct file *filp);

struct file_operations key_operations = {

.owner = THIS_MODULE,

.open = key_open,

.read = key_read,

.write = key_write,

.release = key_close,

};

struct key_str{

char *name;

int val;

};

struct key_str g_key_str={{“key1”,0x1},{“key2”,2}};

static irqreturn_t key_irq_handler1(int irq, void *dev_id)

{

int err;

int reg_val = 0;

int ret_val = 0;

}

static irqreturn_t key_irq_handler2(int irq, void *dev_id)

{

}

static ssize_t key_read (struct file *file, char __user *buf, size_t len, loff_t *off)

{

unsigned int value = 0;

value = copy_to_user(buf,&key_value,4);

}

static int key_open(struct inode *inode, struct file *filp)

{

int err = 0;

int key_test_enabled = 0;

int ret = 0;

}

static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off)

{

}

static int key_close(struct inode *inode, struct file *filp)

{

SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT22);

SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT23);

}

static int __init key_init(void)

{

key_major = register_chrdev(0, “key_chrdev”, &key_operations);

}

static void __exit key_exit(void)

{

if (gpio_addr) {

iounmap(gpio_addr);

}

}

module_init(key_init);

module_exit(key_exit);

MODULE_DESCRIPTION(“Driver for key”);

MODULE_AUTHOR(“wit_yuan”);

MODULE_LICENSE(“GPL”);

ifeq ($(KERNELRELEASE),)

KERNEL_DIR=/home/wityuan/Downloads/MarsBoard-A20-Linux-SDK-V1.2/linux-sunxi

PWD=$(shell pwd)

modules:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules

arm-linux-gnueabihf-gcc -o key key.c

modules_install:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install

clean:

rm -rf *.ko *.o .tmp_versions

.mod.c modules.order Module.symvers .

.cmd

else

obj-m:=key.o

endif

int main(int argc,char *argv)

{

int fd;

int val;

fd = open(“/dev/key_device”,O_RDWR);

if(fd

printf(“—open file error—-\r\n”);

return -1;

}

}

/* EINT type PIO controller registers */

/* EINT type defines */

static wait_queue_head_t key_data_avail;

static unsigned int key_done = 0;

static int int_cfg_addr = {PIO_INT_CFG0_OFFSET,

PIO_INT_CFG1_OFFSET,

PIO_INT_CFG2_OFFSET,

PIO_INT_CFG3_OFFSET};

/* Setup GPIO irq mode (FALLING, RISING, BOTH, etc */

})

/* Enable GPIO interrupt for pin */

})

/* Disable GPIO interrupt for pin */

})

/* Set GPIO pin mode (input, output, etc)

/

/

GPIO port has 4 cfg 32bit registers (8 pins each)

/

/

First port cfg register addr = port_num * 0x24 */

})

static script_gpio_set_t info;

static unsigned key_handler1;

static unsigned key_handler2;

static struct class *key_class;

static struct device *key_device;

static unsigned int key_major;

static unsigned int key_value;

static void *__iomem gpio_addr = NULL;

static int key_open(struct inode *inode, struct file *filp);

static ssize_t key_read (struct file *, char __user *, size_t, loff_t *);

static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off);

static int key_close(struct inode *inode, struct file *filp);

struct file_operations key_operations = {

.owner = THIS_MODULE,

.open = key_open,

.read = key_read,

.write = key_write,

.release = key_close,

};

struct key_str{

char *name;

int val;

};

struct key_str g_key_str={{“key1”,0x1},{“key2”,2}};

static irqreturn_t key_irq_handler1(int irq, void *dev_id)

{

int err;

int reg_val = 0;

int ret_val = 0;

}

static irqreturn_t key_irq_handler2(int irq, void *dev_id)

{

}

static ssize_t key_read (struct file *file, char __user *buf, size_t len, loff_t *off)

{

unsigned int value = 0;

}

static int key_open(struct inode *inode, struct file *filp)

{

int err = 0;

int key_test_enabled = 0;

int ret = 0;

}

static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off)

{

}

static int key_close(struct inode *inode, struct file *filp)

{

SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT22);

SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT23);

}

static int __init key_test_init(void)

{

key_major = register_chrdev(0, “key_chrdev”, &key_operations);

}

static void __exit key_test_exit(void)

{

if (gpio_addr) {

iounmap(gpio_addr);

}

}

module_init(key_test_init);

module_exit(key_test_exit);

MODULE_DESCRIPTION(“Driver for key”);

MODULE_AUTHOR(“wit_yuan”);

MODULE_LICENSE(“GPL”);

ifeq ($(KERNELRELEASE),)

KERNEL_DIR=/home/wityuan/Downloads/MarsBoard-A20-Linux-SDK-V1.2/linux-sunxi

PWD=$(shell pwd)

modules:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules

arm-linux-gnueabihf-gcc -o key key.c

modules_install:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install

clean:

rm -rf *.ko *.o .tmp_versions

.mod.c modules.order Module.symvers .

.cmd

else

obj-m:=key.o

endif

int main(int argc,char *argv)

{

int fd;

int val;

fd = open(“/dev/key_device”,O_RDWR);

if(fd

printf(“—open file error—-\r\n”);

return -1;

}

1.首先要安装libu: sudo aptitude install libu-dev

JLink要求64位系统要由32位的libu,官方提示后续版本会修正此问题(很多系统默认已安装)。

2.下载并安装

(1)到segger官网下载JLink for Linux 驱动:

(2)解压JLink_Linux_XXX.tgz(XXX代表相应版本)

(3)执行以下命令安装delivered shared library:

sudo cp libjlinkarm.so.* /usr/lib

sudo ldconfig

执行sudo ldconfig时可能会出现此错误:/usr/lib/libjlinkarm.so.4 is not a symbolic link,可能是由于符号连接文件拷贝以后属性变化乎携,需要重新建立连接:

cd /usr/lib

sudo rm -rf libjlinkarm.so.4

ls libjlinkarm.so.4* (查看当前系统使用的版本)

ln -s libjlinkarm.so.4.XXX libjlinkarm.so.4 (XXX代表相应版本)

这时再执行sudo ldconfig就行了。

(4)执行sudo cp 45-jlink.rules /etc/udev/rules.d/,确保当前用户在plugdev用户组中,执行命令sudo useradd -G plugdev XXX(XXX代表你的用户名)。

【如果用户组plugdev不存在,需要按以下步骤建立:

sudo groupadd plugdev创建用户组

sudo usermod -a -G plugdev XXX 添加用户

然后重启完成添加。】

(5)进入JLink文件夹,执行JLinkExe。

若出现此错误:libreadline.so.5: cannot open shared object file: No such file or directory,32位系统参照网上通用方法解决。64位系统安装sudo aptitude install lib32readline5即可解决(若lib32文件夹下已有libreadline.so.5符号连接文件,需删除后再安装)。

(6)为方便使用,可在PATH路径中创建JLinkExe的符号连接:

sudo ln -s /opt/JLink_Linux_V462a/JLinkExe /usr/bin/JLinkExe

这样在主文件夹中输入JLinkExe就能调出程序。

注意:(1)要获得root权限来运行sudo jlink,否则会出现问题:Can not connect to J-Link via USB.

(2)系统启动过程中出现invalid rule:/etc/udev/rules.d/45-jlink.rules,需要修改该文件,将BUS!=”u”删除或注释掉,然后重启就可以了,不影响使用。

3.使用JLink

在J-Link>输入”?”,即给出命令列表。我在使用过程中,总体觉得Linux下JLink不够成熟,主要表现在资料太小、功能不易用、操作成功与否不提示(当然不排除不熟练的原因)。

3.1 下载loadbin

loadbin用于将二进制文件下载行顷戚到目标存储器,语法如下:

Syntax: loadbin , //Load binary file into target memory

下载之前需要设置下目标版的处理器,否则无法正常烧写,我的型号是STM32F103R6,但在指定的时候只指定为STM32F103RB,如下:

J-Link>exec device = STM32F103RB

有个麻烦,下载完没有明显提示成功与否,可以通过这样解决:在PC通过命令xxd查看待下载文件,下载进去通过JLink命令mem查看,判断这两者是否一样(只比较前面若干字节即可),若一样,则表示烧写成功。举个例子,把/bin/cp文件烧到档陵板子:

关于linux v1.2 arm的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » Linux v1.2成功移植到ARM平台 (linux v1.2 arm)