基于双核的双系统制作
最近在做一个项目,是基于双core跑双linux系统的架构,有点类似于linux里的SMP概念,分为主CPU和次CPU。首先主CPU把系统跑起来后,由其中的驱动(我们可以叫做loader驱动)去加载另外一个次CPU然后跑次linux系统。也许有些小伙伴会问两个linux如何在不同的core上跑起来呢,内存怎么访问,外设怎么访问呢。我们这边可以把内存平均分成两份,一份给主CPU访问,一份给次CPU访问。至于外设,我们可以有选择性的进行分配,相信这个不是什么难度也不是我要讲的重点。废话少说,下面进入我们的双核双系统设计:
首先我们可以把内存分为如下空间:
供不同的内核访问不同的内存空间。
下面是双核双系统的整体架构设计:
从图中可以明显的看出双系统的关系,boot_module是主系统里的一个驱动,负责加载次系统的镜像。这里我不做进一步的解释,如果看不懂的朋友可以给我留言。
我们知道内核启动的汇编文件是head.S。里面的主要工作是初始化CPU,关闭看门狗,初始化堆栈等工作。最终进入解压后的内核vmlinux。参考head.S可以实现次linux系统镜像的汇编初始化:
/** File : start_gcc.S* This file is part of RT-Thread RTOS* COPYRIGHT (C) 2013, RT-Thread Development Team** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License along* with this program; if not, write to the Free Software Foundation, Inc.,* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.** Change Logs:* Date Author Notes* 2013-07-05 Bernard the first version*/
.equ Mode_USR, 0x10
.equ Mode_FIQ, 0x11
.equ Mode_IRQ, 0x12
.equ Mode_SVC, 0x13
.equ Mode_ABT, 0x17
.equ Mode_UND, 0x1B
.equ Mode_SYS, 0x1F
.equ I_Bit, 0x80 //@ when I bit is set, IRQ is disabled
.equ F_Bit, 0x40 //@ when F bit is set, FIQ is disabled
.equ UND_Stack_Size, 0x00000000
.equ SVC_Stack_Size, 0x00000000
.equ ABT_Stack_Size, 0x00000000
.equ FIQ_Stack_Size, 0x00000100
.equ IRQ_Stack_Size, 0x00000100
.equ USR_Stack_Size, 0x00000000
#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \FIQ_Stack_Size + IRQ_Stack_Size)
/* stack */
.globl stack_start
.globl stack_top
.bss
stack_start:
.rept ISR_Stack_Size
.long 0
.endr
stack_top:
.text
/* reset entry */
.globl _reset
_reset:/* invalidate SCU */ldr r7, =0xF8F0000Cldr r6, =0xFFFFstr r6, [r7]/* disable MMU */mrc p15, 0, r0, c1, c0, 0 /* read CP15 register 1 */bic r0, r0, #0x1 /* clear bit 0 */mcr p15, 0, r0, c1, c0, 0 /* write value back *//* set the cpu to SVC32 mode and disable interrupt */mrs r0, cpsrbic r0, r0, #0x1forr r0, r0, #0x13msr cpsr_c, r0/* setup stack */bl stack_setup/* clear .bss */mov r0,#0 /* get a zero */ldr r1,=__bss_start /* bss start */ldr r2,=__bss_end /* bss end */
bss_loop:cmp r1,r2 /* check if data to clear */strlo r0,[r1],#4 /* clear 4 bytes */blo bss_loop /* loop until done *//* call C++ constructors of global objects */ldr r0, =__ctors_start__ldr r1, =__ctors_end__
ctor_loop:cmp r0, r1beq ctor_endldr r2, [r0], #4stmfd sp!, {r0-r1}mov lr, pcbx r2ldmfd sp!, {r0-r1}b ctor_loop
ctor_end:/* start RT-Thread Kernel */ldr pc, _rtthread_startup
_rtthread_startup:.word rtthread_startup
stack_setup:ldr r0, =stack_top@ Set the startup stack for svcmov sp, r0@ Enter Undefined Instruction Mode and set its Stack Pointermsr cpsr_c, #Mode_UND|I_Bit|F_Bitmov sp, r0sub r0, r0, #UND_Stack_Size@ Enter Abort Mode and set its Stack Pointermsr cpsr_c, #Mode_ABT|I_Bit|F_Bitmov sp, r0sub r0, r0, #ABT_Stack_Size@ Enter FIQ Mode and set its Stack Pointermsr cpsr_c, #Mode_FIQ|I_Bit|F_Bitmov sp, r0sub r0, r0, #FIQ_Stack_Size@ Enter IRQ Mode and set its Stack Pointermsr cpsr_c, #Mode_IRQ|I_Bit|F_Bitmov sp, r0sub r0, r0, #IRQ_Stack_Size@ Switch back to SVCmsr cpsr_c, #Mode_SVC|I_Bit|F_Bitbx lr
.section .text.isr, "ax"
/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */.align 5
.globl vector_fiq
vector_fiq:stmfd sp!,{r0-r7,lr}bl rt_hw_trap_fiqldmfd sp!,{r0-r7,lr}subs pc,lr,#4
.globl rt_interrupt_enter
.globl rt_interrupt_leave
.globl rt_thread_switch_interrupt_flag
.globl rt_interrupt_from_thread
.globl rt_interrupt_to_thread.align 5
.globl vector_irq
vector_irq:stmfd sp!, {r0-r12,lr}bl rt_interrupt_enterbl rt_hw_trap_irqbl rt_interrupt_leave@ if rt_thread_switch_interrupt_flag set, jump to@ rt_hw_context_switch_interrupt_do and don't returnldr r0, =rt_thread_switch_interrupt_flagldr r1, [r0]cmp r1, #1beq rt_hw_context_switch_interrupt_doldmfd sp!, {r0-r12,lr}subs pc, lr, #4
rt_hw_context_switch_interrupt_do:mov r1, #0 @ clear flagstr r1, [r0]mov r1, sp @ r1 point to {r0-r3} in stackadd sp, sp, #4*4ldmfd sp!, {r4-r12,lr}@ reload saved registersmrs r0, spsr @ get cpsr of interrupt threadsub r2, lr, #4 @ save old task's pc to r2@ Switch to SVC mode with no interrupt.msr cpsr_c, #I_Bit|F_Bit|Mode_SVCstmfd sp!, {r2} @ push old task's pcstmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt threadstmfd sp!, {r1-r4} @ push old task's r0-r3stmfd sp!, {r0} @ push old task's cpsrldr r4, =rt_interrupt_from_threadldr r5, [r4]str sp, [r5] @ store sp in preempted tasks's TCBldr r6, =rt_interrupt_to_threadldr r7, [r6]ldr sp, [r7] @ get new task's stack pointerldmfd sp!, {r4} @ pop new task's cpsr to spsrmsr spsr_cxsf, r4ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr
.macro push_svc_regsub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */stmia sp, {r0 - r12} @/* Calling r0-r12 */mov r0, spmrs r6, spsr @/* Save CPSR */str lr, [r0, #15*4] @/* Push PC */str r6, [r0, #16*4] @/* Push CPSR */cps #Mode_SVCstr sp, [r0, #13*4] @/* Save calling SP */str lr, [r0, #14*4] @/* Save calling PC */
.endm.align 5.globl vector_swi
vector_swi:push_svc_regbl rt_hw_trap_swib ..align 5.globl vector_undef
vector_undef:push_svc_regbl rt_hw_trap_undefb ..align 5.globl vector_pabt
vector_pabt:push_svc_regbl rt_hw_trap_pabtb ..align 5.globl vector_dabt
vector_dabt:push_svc_regbl rt_hw_trap_dabtb ..align 5.globl vector_resv
vector_resv:push_svc_regbl rt_hw_trap_resvb .
这里有个地方需要注意的是在内存地址链接的时候有个重定位的概念,由lds文件来重定位,定位后的结果可以看system.map文件。我们的设计思路是有写个 加载镜像的驱动loader.ko,该驱动负责加载编写好的内核镜像到指定内存位置,然后设置次核启动次CPU进而启动次linux系统。下面贴出驱动代码loader.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cpu.h>
#include <linux/memblock.h>
#include <asm/cacheflush.h>
#include <linux/dw_apb_timer.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/of_net.h>
#include <linux/stmmac.h>
#include <linux/phy.h>
#include <linux/micrel_phy.h>
#include <linux/sys_soc.h>#include <asm/hardware/cache-l2x0.h>
#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/smp_twd.h>//#define _REG32(addr) (*(volatile uint32_t *)(addr))//#define CPU1STARTADDR_REG _REG32(0xFFD080C4)
//#define MPUMODRST_REG _REG32(0xFFD05010)#define RT_BASE_ADDR 0x20000000
#define RT_MEM_SIZE 0x00400000
#define BUFF_SZ (4 * 1024)unsigned char __iomem *membase;/*static inline void __raw_writel(u32 v, volatile void __iomem *addr)
{*(volatile u32 __force *)addr = v;
}*/static void au_serial_out(unsigned char __iomem *membase, int offset, int value)
{//offset = au_io_out_map[offset] << p->regshift;//offset = au_io_out_map[offset];__raw_writel(value, membase + offset);
}void boot_cpu1(uint32_t start_addr)
{unsigned long dat;unsigned long tmp;void __iomem *sys_manager_cpu1start_addr;void __iomem *rst_manager_mpu_addr;printk("^^^^^^^^^^^^^^\n");//CPU1STARTADDR_REG = start_addr;//MPUMODRST_REG &= ~0x2;sys_manager_cpu1start_addr = ioremap(0xFFD080C4, 0x4000);rst_manager_mpu_addr = ioremap(0xFFD05010, 0x1000);printk("cpu1start_addr = 0x%lx\n", sys_manager_cpu1start_addr);printk("rst_manager_base_addr = 0x%lx\n", rst_manager_mpu_addr);__raw_writel(start_addr, sys_manager_cpu1start_addr);//tmp = __raw_readl(sys_manager_cpu1start_addr);//printk(">>>>tmp = 0x%lx\n", tmp);dat = __raw_readl(rst_manager_mpu_addr);dat &= ~0x2;__raw_writel(dat, rst_manager_mpu_addr);__raw_writel(start_addr, sys_manager_cpu1start_addr);dat = __raw_readl(rst_manager_mpu_addr);dat &= ~0x2;__raw_writel(dat, rst_manager_mpu_addr);__raw_writel(start_addr, sys_manager_cpu1start_addr);dat = __raw_readl(rst_manager_mpu_addr);dat &= ~0x2;__raw_writel(dat, rst_manager_mpu_addr);__raw_writel(start_addr, sys_manager_cpu1start_addr);dat = __raw_readl(rst_manager_mpu_addr);dat &= ~0x2;__raw_writel(dat, rst_manager_mpu_addr);
}int do_load_fw(const char* filename,unsigned long base_addr,size_t mem_size)
{mm_segment_t oldfs = {0};ssize_t len;unsigned long file_sz;loff_t pos = 0;struct file *flp = NULL;unsigned long buf_ptr = base_addr;printk("loading u-boot:%s to %08lx....\n",filename, buf_ptr);flp = filp_open(filename, O_RDONLY, S_IRWXU);if(IS_ERR(flp)) {printk("loader: open file failed");return -1;}file_sz = vfs_llseek(flp, 0, SEEK_END);if (file_sz > mem_size) {printk("rtloader: bin file too big. ""mem size: 0x%08x, bin file size: 0x%08lx\n",mem_size, file_sz);filp_close(flp, NULL);return -1;}printk("loader: bin file size: 0x%08lx\n", file_sz);vfs_llseek(flp, 0, SEEK_SET);oldfs = get_fs();set_fs(get_ds());while (file_sz > 0) {len = vfs_read(flp, (void __user __force*)buf_ptr, BUFF_SZ, &pos);if (len < 0) {pr_err("read %08lx error: %d\n", buf_ptr, len);set_fs(oldfs);filp_close(flp, NULL);return -1;}file_sz -= len;buf_ptr += len;}set_fs(oldfs);printk("done!\n");flush_cache_vmap(base_addr, mem_size);return 0;
}static int __init loader_init(void)
{void *va;unsigned char __iomem *membase;membase = ioremap_nocache(0xffc02000, 0x1000);//va = ioremap_nocache(RT_BASE_ADDR, RT_MEM_SIZE);printk(">>>>>>>>>>>>\n");va = phys_to_virt(RT_BASE_ADDR);pr_info("get mapping :%p -> %08x, size: %08x\n", va, RT_BASE_ADDR, RT_MEM_SIZE);if(do_load_fw("/mnt/boot/boot.bin", (unsigned long)va, RT_MEM_SIZE) == 0){ printk("start boot boot.bin......\n");boot_cpu1(RT_BASE_ADDR);printk("end boot boot.bin......\n");}/*while(1){au_serial_out(membase, 0, 123);}*/return 0;
}static void __exit loader_exit(void)
{}module_init(loader_init);
module_exit(loader_exit);MODULE_DESCRIPTION("LOADER");
MODULE_LICENSE("GPL");
基于双核的双系统制作相关推荐
- Windows11Ubuntu18.04双系统制作、安装及软件安装
Windows11&Ubuntu18.04双系统制作.安装及软件安装 一 Windows11系统制作 1.1 下载镜像 1.2 制作Windows11U盘启动盘 1.3 Windows11系统 ...
- 基于Win10安装双系统Ubuntu不能正常进入的问题
基于Win10安装双系统Ubuntu不能正常进入的问题 1.基于Windows安装Ubuntu,如果需要再次覆盖安装 需要进入Windows,将需要覆盖安装的磁盘,重新分区 2.安装Ubuntu结束, ...
- ubuntuandroid双系统制作过程
ubuntu&android双系统制作过程 转载 作者 :orbbec-wmy 链接方式: link 同样站在巨人的肩膀上总结制作过程,参(nian)考(tie)这个版主:点击跳转 硬件:rk ...
- Windows11 + Ubuntu 18.04 双系统制作教程(详细流程无法联网问题解决)
文章目录 一.安装前确认信息 二.双系统制作流程说明 step 1:下载 Ubuntu 镜像文件 step 2:制作 USB 启动盘 step 3:为 Ubuntu 新建硬盘分区 step 4:确认引 ...
- Win11上安装Ubuntu18.04双系统制作教程
在Win11上安装Ubuntu18.04的双系统 1. 下载Ubuntu系统镜像.刻录装机U盘 2. 从windows11的硬盘中,划分出独立空间,用于安装Ubuntu 3. 重启系统,进入安装程序 ...
- 神州战神win10+ubuntu双系统制作
序言 神船装系统不仅需要过硬的技术,更需要的是一个强大的心态!!! 我的电脑是Z7-KP7GC: 配置:Intel core i7-8750H:128SSD+1TBHDD:显卡NVIDIA GTX10 ...
- 2013-2014Mac book Air 创建4个分区Macos加win7双系统制作安装详细教程
此方法需格式化全盘,如有资料提早备份.(本文用一个8G U盘)部分资料来源网上,加上自己整理,谢谢大神们 第一部份:制作os u盘系统,重新安装os系统 准备工作: 1.8G空白U盘一只: 2.OS ...
- WIN7/XP双主分区独立双系统的引导教程
WIN7/XP双主分区独立双系统的引导教程 本文来自网络,经由本人亲测可用,现整理如下: 很多人在安装双系统(如C盘XP,D盘Vista/Win7)时,硬盘的分区状况是一个活动的主分区,若干个逻辑分区 ...
- Windows10+Ubuntu20.04双系统 惠普暗影精灵OMEN
暗影精灵5-air Windows10+Ubuntu20.04双系统 制作U盘启动盘 压缩磁盘空间 更改bios设置 安装Ubuntu 分区问题 安装 配置apt软件源 配置中文输入法 制作U盘启动盘 ...
- 双系统windows+ubuntu18.04的安装和基本配置
一.安装前确认信息 1.确认引导模式 win+R 输入msinfo32,打开系统信息,可以看到BIOS模式为UEFI,表示 UEFI Boot 引导模式. 二.双系统制作流程 1.下载Ubuntu镜像 ...
最新文章
- 【spring 5】AOP:spring中对于AOP的的实现
- 在应用程序中宿主MEF
- v-for中为什么要有key属性
- QTextEdit 总结
- 每周一题 —— 3n+1问题
- cocostudio 实现换行功能的label (文本区) lua
- 多系统通讯-DotNetMQ
- 施一公谈自己35岁和53岁的区别
- 飞秋_常用正则表达式集锦
- python腐蚀膨胀代码_OpenCV+python实现膨胀和腐蚀的示例
- 由ViewStateException: The client disconnected想到的
- Flink+Alink,当大数据遇见机器学习! 博文视点Broadview 前天
- CICD详解(九)——gitlab简单使用
- Git小乌龟的安装及使用
- Java对象与JSON数据的相互转换
- 翻译: 深入神经网络概览Dive into Deep Learning
- 探讨 “tun2socks” 技术的一些问题
- Robotics正运动学求解仿真(附代码和解释)
- 从零开始学习html(十)CSS格式化排版——下
- Xmanager安装与使用攻略