Comparing LINUX and CORTTEX-M startup processes

Keywords: Linux REST shell Fragment

1 CORTEX-M

1.1 boot program

Take stm32 as an example, add an online upgrade boot program with rom address:

LR_IROM1 0x08000000 0x00004000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00004000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

boot boots the application:

#define APPLICATION_ADDRESS   (uint32_t)0x08004000

            
JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
      /* Jump to user application */
      Jump_To_Application = (pFunction) JumpAddress;
      /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); Jump_To_Application();

 

1.2 Application

rom address

LR_IROM1 0x08004000 0x0001c000  {    ; load region size_region
  ER_IROM1 0x08004000 0x00300000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

 

Start assembly file startup***.s

Stack_Size      EQU     0x00000400  
;Stack_Size      EQU     0x00001000
    ,,,
Reset_Handler   PROC
                EXPORT  Reset_Handler                     [WEAK]
                IMPORT  SystemInit
                IMPORT  __main

2 The boot and start process for LINUX

2.1 uboot

In mian_loop

#define CONFIG_BOOTDELAY 3  //Set Startup Delay Time

//Boot the kernel if the delay is greater than or equal to zero and no keys are received during the delay

if (bootdelay >= 0 && s && !abortboot (bootdelay)) { //

# ifdef CONFIG_AUTOBOOT_KEYED

      intprev = disable_ctrlc(1);/* disable Control C checking */

# endif   //Status Settings

 

# ifndef CFG_HUSH_PARSER

        {

             printf("Booting Linux ...\n");       //start-up linux   

         run_command (s, 0);  //Run commands to boot the kernel,s=getenv("bootcmd")           

        }

 

The variables "bootcmd" and "bootargs" are used when loading the linux kernel.

The values of variables "bootcmd" and "bootargs" can be used before the linux kernel is loaded.

Modification in uboot's command console

bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0

 

The first command Read kernel from flash kernel is a partition flag

The second command The startup command indicates the startup address

bootargs are other parameter information, run_command (getenv ("bootcmd"), flag)

bootm in bootcmd, boot application image from memory

Parameter form:'bootm addr', bootm loads default configuration macro when addr is omitted

#define CONFIG_SYS_LOAD_ADDR  0x30008000  /* default load address */

 

2.2 linux Kernel State

Find the location of the label u mmap_switched: /linux/arch/arm/kernel/head-common.S

__mmap_switched:
/*
* The following fragment of code is executed with the MMU on in MMU mode,
* and uses absolute addresses; this is not position independent.
*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags/dtb pointer
* r9 = processor ID
*/
//Save device information, device tree, and boot parameter storage addresses
,,
b    start_kernel

 

Function location: /linux/init/Main.c, start_kernel involves a lot of initialization work, only the important ones are listed.

asmlinkage void __init start_kernel(void)
{
...... //Type Judgment
smp_setup_processor_id(); //smp Relevant, back to startup CPU Number
......
local_irq_disable(); //Close the current CPU interrupt
early_boot_irqs_disabled = true;
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
boot_cpu_init();
page_address_init(); //Initialization Page Address
pr_notice("%s", linux_banner); //Display Kernel Version Information
setup_arch(&command_line);
mm_init_owner(&init_mm, &init_task);
mm_init_cpumask(&init_mm);
setup_command_line(command_line);
setup_nr_cpu_ids();
setup_per_cpu_areas();
smp_prepare_boot_cpu();    /* arch-specific boot-cpu hooks */

build_all_zonelists(NULL, NULL);
page_alloc_init(); //Page memory request initialization

pr_notice("Kernel command line: %s\n", boot_command_line); //Print kernel boot command line parameters
parse_early_param();
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
-1, -1, &unknown_bootoption);

......
/*
* 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(); //Process Scheduler Initialization
/*
* Disable preemption - early bootup scheduling is extremely
* fragile until we cpu_idle() for the first time.
*/
preempt_disable(); //Kernel Preemption Prohibited
if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
local_irq_disable(); //Check off CPU interrupt


/*Mass Initialization Content Knowledgeable*/
idr_init_cache();
rcu_init();
tick_nohz_init();
context_tracking_init();
radix_tree_init();
/* init some links before init_ISA_irqs() */
early_irq_init();
init_IRQ();
tick_init();
init_timers();
hrtimers_init();
softirq_init();
timekeeping_init();
time_init();
sched_clock_postinit();
perf_event_init();
profile_init();
call_function_init();
WARN(!irqs_disabled(), "Interrupts were enabled early\n");
early_boot_irqs_disabled = false;
local_irq_enable(); //Local interrupts are available

kmem_cache_init_late();

/*
* 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(); //Initialize the console to use printk Yes
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_cgroup_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(totalram_pages); //Initialization fork
proc_caches_init();
buffer_init();
key_init();
security_init();
dbg_late_init();
vfs_caches_init(totalram_pages); //Virtual File System Initialization
signals_init();
/* rootfs populating might need page-writeback */
page_writeback_init();
#ifdef CONFIG_PROC_FS
proc_root_init();
#endif
cgroup_init();
cpuset_init();
taskstats_init_early();
delayacct_init();

check_bugs();

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();
}
//Function last calls rest_init() function

/*Most Important Mission: Create the kernel_init process and subsequently initialize it*/
static noinline void __init_refok rest_init(void)
{
int pid;

rcu_scheduler_starting();
/*
* 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 | CLONE_SIGHAND); //Establish kernel_init process

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_idle This is the idle function used to reduce power usage and heat generation when the system is idle. The function is not returned at this point, and the rest of the work is done from kernel_init Process Initiation
cpu_startup_entry(CPUHP_ONLINE);
}
kernel_init The function will complete the initialization of the device driver and call init_post Function Starts User Process

//Some books describe the kernel startup process based on the classic version 2.6. The kernel_init function also calls the init_post function, which is responsible for the startup of the _init process. The current version has been integrated.

static int __ref kernel_init(void *unused)
{
int ret;

kernel_init_freeable(); //Completed in this function smp Turn on driver initialization, shared memory initialization, etc.
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem(); //Initialization End, Clear Memory Unused Data
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)
return 0;
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.
*Find the init function and create process 1_init (the first user space process)*/
if (execute_command) {
ret = run_init_process(execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s (error %d). Attempting defaults...\n",
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"))
return 0;

panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/init.txt for guidance.");
}
static int __ref kernel_init(void *unused)
{
int ret;

kernel_init_freeable(); //Completed in this function smp Turn on driver initialization, shared memory initialization, etc.
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem(); //Initialization End, Clear Memory Unused Data
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)
return 0;
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.
*Find the init function and create process 1_init (the first user space process)*/
if (execute_command) {
ret = run_init_process(execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s (error %d). Attempting defaults...\n",
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"))
return 0;

panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/init.txt for guidance.");
}
 

 

At this point, the kernel initialization is nearing its end, and all initialization functions have been called, so the free_initmem function can discard data between u init_begin and u init_end in memory.

When the kernel is booted and initialized, the kernel starts its first user space application, init, which is the first program called to compile using the standard C library with a process number clock of 1.

_init is responsible for starting other necessary processes to make the system available as a whole.

The following is a kernel startup flowchart:

 

Source of picture: https://blog.csdn.net/perfect1t/article/details/81741531

Reference: https://blog.csdn.net/perfect1t/article/details/81741531

---

 

https://blog.csdn.net/perfect1t/article/details/81741531

Posted by emfung on Tue, 14 Apr 2020 21:54:26 -0700