最近在做一个项目,是基于双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");

基于双核的双系统制作相关推荐

  1. Windows11Ubuntu18.04双系统制作、安装及软件安装

    Windows11&Ubuntu18.04双系统制作.安装及软件安装 一 Windows11系统制作 1.1 下载镜像 1.2 制作Windows11U盘启动盘 1.3 Windows11系统 ...

  2. 基于Win10安装双系统Ubuntu不能正常进入的问题

    基于Win10安装双系统Ubuntu不能正常进入的问题 1.基于Windows安装Ubuntu,如果需要再次覆盖安装 需要进入Windows,将需要覆盖安装的磁盘,重新分区 2.安装Ubuntu结束, ...

  3. ubuntuandroid双系统制作过程

    ubuntu&android双系统制作过程 转载 作者 :orbbec-wmy 链接方式: link 同样站在巨人的肩膀上总结制作过程,参(nian)考(tie)这个版主:点击跳转 硬件:rk ...

  4. Windows11 + Ubuntu 18.04 双系统制作教程(详细流程无法联网问题解决)

    文章目录 一.安装前确认信息 二.双系统制作流程说明 step 1:下载 Ubuntu 镜像文件 step 2:制作 USB 启动盘 step 3:为 Ubuntu 新建硬盘分区 step 4:确认引 ...

  5. Win11上安装Ubuntu18.04双系统制作教程

    在Win11上安装Ubuntu18.04的双系统 1. 下载Ubuntu系统镜像.刻录装机U盘 2. 从windows11的硬盘中,划分出独立空间,用于安装Ubuntu 3. 重启系统,进入安装程序 ...

  6. 神州战神win10+ubuntu双系统制作

    序言 神船装系统不仅需要过硬的技术,更需要的是一个强大的心态!!! 我的电脑是Z7-KP7GC: 配置:Intel core i7-8750H:128SSD+1TBHDD:显卡NVIDIA GTX10 ...

  7. 2013-2014Mac book Air 创建4个分区Macos加win7双系统制作安装详细教程

    此方法需格式化全盘,如有资料提早备份.(本文用一个8G U盘)部分资料来源网上,加上自己整理,谢谢大神们 第一部份:制作os u盘系统,重新安装os系统 准备工作: 1.8G空白U盘一只: 2.OS ...

  8. WIN7/XP双主分区独立双系统的引导教程

    WIN7/XP双主分区独立双系统的引导教程 本文来自网络,经由本人亲测可用,现整理如下: 很多人在安装双系统(如C盘XP,D盘Vista/Win7)时,硬盘的分区状况是一个活动的主分区,若干个逻辑分区 ...

  9. Windows10+Ubuntu20.04双系统 惠普暗影精灵OMEN

    暗影精灵5-air Windows10+Ubuntu20.04双系统 制作U盘启动盘 压缩磁盘空间 更改bios设置 安装Ubuntu 分区问题 安装 配置apt软件源 配置中文输入法 制作U盘启动盘 ...

  10. 双系统windows+ubuntu18.04的安装和基本配置

    一.安装前确认信息 1.确认引导模式 win+R 输入msinfo32,打开系统信息,可以看到BIOS模式为UEFI,表示 UEFI Boot 引导模式. 二.双系统制作流程 1.下载Ubuntu镜像 ...

最新文章

  1. 【spring 5】AOP:spring中对于AOP的的实现
  2. 在应用程序中宿主MEF
  3. v-for中为什么要有key属性
  4. QTextEdit 总结
  5. 每周一题 —— 3n+1问题
  6. cocostudio 实现换行功能的label (文本区) lua
  7. 多系统通讯-DotNetMQ
  8. 施一公谈自己35岁和53岁的区别
  9. 飞秋_常用正则表达式集锦
  10. python腐蚀膨胀代码_OpenCV+python实现膨胀和腐蚀的示例
  11. 由ViewStateException: The client disconnected想到的
  12. Flink+Alink,当大数据遇见机器学习! 博文视点Broadview 前天
  13. CICD详解(九)——gitlab简单使用
  14. Git小乌龟的安装及使用
  15. Java对象与JSON数据的相互转换
  16. 翻译: 深入神经网络概览Dive into Deep Learning
  17. 探讨 “tun2socks” 技术的一些问题
  18. Robotics正运动学求解仿真(附代码和解释)
  19. 从零开始学习html(十)CSS格式化排版——下
  20. Xmanager安装与使用攻略

热门文章

  1. kali rpm 安装方法_解决kali linux中无法使用RPM命令
  2. wps2019将表格数据转换成工资条的操作方法
  3. OPPO Reno7 Pro刷root强解锁BL刷面具Magisk框架 OPPO reno7pro免深度测试 root教程
  4. 谷歌浏览器导入插件教程
  5. 绩效打c被开除,员工将新东方告上法院,获赔416000元!
  6. 计算机温度在20度最佳湿度环境,空调房温度20℃湿度一般是多少
  7. v-distpicker 直辖市的修改
  8. Nginx实现静态资源服务器
  9. 电工技术(3)—电路的分析方法二
  10. 微信小程序新手向——界面布局