沈阳网站如何制作/百度指数查询工具
想要熟悉内核,看下源码,就非常清晰
Linux内核,head.s,汇编启动cpu相关设置后,启动init文件里的,文件在内核的/init/main.c,看下main函数,做了哪些工作
// SPDX-License-Identifier: GPL-2.0-only
/** linux/init/main.c** Copyright (C) 1991, 1992 Linus Torvalds** GK 2/5/95 - Changed to support mounting root fs via NFS* Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96* Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96* Simplified starting of init: Michael A. Griffith <grif@acm.org>*/#define DEBUG /* Enable initcall_debug */#include <linux/types.h>
#include <linux/extable.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/binfmts.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/stackprotector.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/initrd.h>
#include <linux/memblock.h>
#include <linux/acpi.h>
#include <linux/bootconfig.h>
#include <linux/console.h>
#include <linux/nmi.h>
#include <linux/percpu.h>
#include <linux/kmod.h>
#include <linux/kprobes.h>
#include <linux/kmsan.h>
#include <linux/vmalloc.h>
#include <linux/kernel_stat.h>
#include <linux/start_kernel.h>
#include <linux/security.h>
#include <linux/smp.h>
#include <linux/profile.h>
#include <linux/kfence.h>
#include <linux/rcupdate.h>
#include <linux/srcu.h>
#include <linux/moduleparam.h>
#include <linux/kallsyms.h>
#include <linux/buildid.h>
#include <linux/writeback.h>
#include <linux/cpu.h>
#include <linux/cpuset.h>
#include <linux/cgroup.h>
#include <linux/efi.h>
#include <linux/tick.h>
#include <linux/sched/isolation.h>
#include <linux/interrupt.h>
#include <linux/taskstats_kern.h>
#include <linux/delayacct.h>
#include <linux/unistd.h>
#include <linux/utsname.h>
#include <linux/rmap.h>
#include <linux/mempolicy.h>
#include <linux/key.h>
#include <linux/debug_locks.h>
#include <linux/debugobjects.h>
#include <linux/lockdep.h>
#include <linux/kmemleak.h>
#include <linux/padata.h>
#include <linux/pid_namespace.h>
#include <linux/device/driver.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/sched/init.h>
#include <linux/signal.h>
#include <linux/idr.h>
#include <linux/kgdb.h>
#include <linux/ftrace.h>
#include <linux/async.h>
#include <linux/shmem_fs.h>
#include <linux/slab.h>
#include <linux/perf_event.h>
#include <linux/ptrace.h>
#include <linux/pti.h>
#include <linux/blkdev.h>
#include <linux/sched/clock.h>
#include <linux/sched/task.h>
#include <linux/sched/task_stack.h>
#include <linux/context_tracking.h>
#include <linux/random.h>
#include <linux/moduleloader.h>
#include <linux/list.h>
#include <linux/integrity.h>
#include <linux/proc_ns.h>
#include <linux/io.h>
#include <linux/cache.h>
#include <linux/rodata_test.h>
#include <linux/jump_label.h>
#include <linux/kcsan.h>
#include <linux/init_syscalls.h>
#include <linux/stackdepot.h>
#include <linux/randomize_kstack.h>
#include <net/net_namespace.h>#include <asm/io.h>
#include <asm/setup.h>
#include <asm/sections.h>
#include <asm/cacheflush.h>#define CREATE_TRACE_POINTS
#include <trace/events/initcall.h>#include <kunit/test.h>static int kernel_init(void *);/** Debug helper: via this flag we know that we are in 'early bootup code'* where only the boot processor is running with IRQ disabled. This means* two things - IRQ must not be enabled before the flag is cleared and some* operations which are not allowed with IRQ disabled are allowed while the* flag is set.*/
bool early_boot_irqs_disabled __read_mostly;enum system_states system_state __read_mostly;
EXPORT_SYMBOL(system_state);/** Boot command-line arguments*/
#define MAX_INIT_ARGS CONFIG_INIT_ENV_ARG_LIMIT
#define MAX_INIT_ENVS CONFIG_INIT_ENV_ARG_LIMIT/* Default late time init is NULL. archs can override this later. */
void (*__initdata late_time_init)(void);/* Untouched command line saved by arch-specific code. */
char __initdata boot_command_line[COMMAND_LINE_SIZE];
/* Untouched saved command line (eg. for /proc) */
char *saved_command_line __ro_after_init;
unsigned int saved_command_line_len __ro_after_init;
/* Command line for parameter parsing */
static char *static_command_line;
/* Untouched extra command line */
static char *extra_command_line;
/* Extra init arguments */
static char *extra_init_args;#ifdef CONFIG_BOOT_CONFIG
/* Is bootconfig on command line? */
static bool bootconfig_found;
static size_t initargs_offs;
#else
# define bootconfig_found false
# define initargs_offs 0
#endifstatic char *execute_command;
static char *ramdisk_execute_command = "/init";/** Used to generate warnings if static_key manipulation functions are used* before jump_label_init is called.*/
bool static_key_initialized __read_mostly;
EXPORT_SYMBOL_GPL(static_key_initialized);/** If set, this is an indication to the drivers that reset the underlying* device before going ahead with the initialization otherwise driver might* rely on the BIOS and skip the reset operation.** This is useful if kernel is booting in an unreliable environment.* For ex. kdump situation where previous kernel has crashed, BIOS has been* skipped and devices will be in unknown state.*/
unsigned int reset_devices;
EXPORT_SYMBOL(reset_devices);static int __init set_reset_devices(char *str)
{reset_devices = 1;return 1;
}__setup("reset_devices", set_reset_devices);static const char *argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
const char *envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
static const char *panic_later, *panic_param;static bool __init obsolete_checksetup(char *line)
{const struct obs_kernel_param *p;bool had_early_param = false;p = __setup_start;do {int n = strlen(p->str);if (parameqn(line, p->str, n)) {if (p->early) {/* Already done in parse_early_param?* (Needs exact match on param part).* Keep iterating, as we can have early* params and __setups of same names 8( */if (line[n] == '\0' || line[n] == '=')had_early_param = true;} else if (!p->setup_func) {pr_warn("Parameter %s is obsolete, ignored\n",p->str);return true;} else if (p->setup_func(line + n))return true;}p++;} while (p < __setup_end);return had_early_param;
}/** This should be approx 2 Bo*oMips to start (note initial shift), and will* still work even if initially too large, it will just take slightly longer*/
unsigned long loops_per_jiffy = (1<<12);
EXPORT_SYMBOL(loops_per_jiffy);static int __init debug_kernel(char *str)
{console_loglevel = CONSOLE_LOGLEVEL_DEBUG;return 0;
}static int __init quiet_kernel(char *str)
{console_loglevel = CONSOLE_LOGLEVEL_QUIET;return 0;
}early_param("debug", debug_kernel);
early_param("quiet", quiet_kernel);static int __init loglevel(char *str)
{int newlevel;/** Only update loglevel value when a correct setting was passed,* to prevent blind crashes (when loglevel being set to 0) that* are quite hard to debug*/if (get_option(&str, &newlevel)) {console_loglevel = newlevel;return 0;}return -EINVAL;
}early_param("loglevel", loglevel);#ifdef CONFIG_BLK_DEV_INITRD
static void * __init get_boot_config_from_initrd(size_t *_size)
{u32 size, csum;char *data;u32 *hdr;int i;if (!initrd_end)return NULL;data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN;/** Since Grub may align the size of initrd to 4, we must* check the preceding 3 bytes as well.*/for (i = 0; i < 4; i++) {if (!memcmp(data, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN))goto found;data--;}return NULL;found:hdr = (u32 *)(data - 8);size = le32_to_cpu(hdr[0]);csum = le32_to_cpu(hdr[1]);data = ((void *)hdr) - size;if ((unsigned long)data < initrd_start) {pr_err("bootconfig size %d is greater than initrd size %ld\n",size, initrd_end - initrd_start);return NULL;}if (xbc_calc_checksum(data, size) != csum) {pr_err("bootconfig checksum failed\n");return NULL;}/* Remove bootconfig from initramfs/initrd */initrd_end = (unsigned long)data;if (_size)*_size = size;return data;
}
#else
static void * __init get_boot_config_from_initrd(size_t *_size)
{return NULL;
}
#endif#ifdef CONFIG_BOOT_CONFIGstatic char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;#define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)static int __init xbc_snprint_cmdline(char *buf, size_t size,struct xbc_node *root)
{struct xbc_node *knode, *vnode;char *end = buf + size;const char *val;int ret;xbc_node_for_each_key_value(root, knode, val) {ret = xbc_node_compose_key_after(root, knode,xbc_namebuf, XBC_KEYLEN_MAX);if (ret < 0)return ret;vnode = xbc_node_get_child(knode);if (!vnode) {ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf);if (ret < 0)return ret;buf += ret;continue;}xbc_array_for_each_value(vnode, val) {ret = snprintf(buf, rest(buf, end), "%s=\"%s\" ",xbc_namebuf, val);if (ret < 0)return ret;buf += ret;}}return buf - (end - size);
}
#undef rest/* Make an extra command line under given key word */
static char * __init xbc_make_cmdline(const char *key)
{struct xbc_node *root;char *new_cmdline;int ret, len = 0;root = xbc_find_node(key);if (!root)return NULL;/* Count required buffer size */len = xbc_snprint_cmdline(NULL, 0, root);if (len <= 0)return NULL;new_cmdline = memblock_alloc(len + 1, SMP_CACHE_BYTES);if (!new_cmdline) {pr_err("Failed to allocate memory for extra kernel cmdline.\n");return NULL;}ret = xbc_snprint_cmdline(new_cmdline, len + 1, root);if (ret < 0 || ret > len) {pr_err("Failed to print extra kernel cmdline.\n");memblock_free(new_cmdline, len + 1);return NULL;}return new_cmdline;
}static int __init bootconfig_params(char *param, char *val,const char *unused, void *arg)
{if (strcmp(param, "bootconfig") == 0) {bootconfig_found = true;}return 0;
}static int __init warn_bootconfig(char *str)
{/* The 'bootconfig' has been handled by bootconfig_params(). */return 0;
}static void __init setup_boot_config(void)
{static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata;const char *msg, *data;int pos, ret;size_t size;char *err;/* Cut out the bootconfig data even if we have no bootconfig option */data = get_boot_config_from_initrd(&size);/* If there is no bootconfig in initrd, try embedded one. */if (!data)data = xbc_get_embedded_bootconfig(&size);strscpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, NULL,bootconfig_params);if (IS_ERR(err) || !(bootconfig_found || IS_ENABLED(CONFIG_BOOT_CONFIG_FORCE)))return;/* parse_args() stops at the next param of '--' and returns an address */if (err)initargs_offs = err - tmp_cmdline;if (!data) {/* If user intended to use bootconfig, show an error level message */if (bootconfig_found)pr_err("'bootconfig' found on command line, but no bootconfig found\n");elsepr_info("No bootconfig data provided, so skipping bootconfig");return;}if (size >= XBC_DATA_MAX) {pr_err("bootconfig size %ld greater than max size %d\n",(long)size, XBC_DATA_MAX);return;}ret = xbc_init(data, size, &msg, &pos);if (ret < 0) {if (pos < 0)pr_err("Failed to init bootconfig: %s.\n", msg);elsepr_err("Failed to parse bootconfig: %s at %d.\n",msg, pos);} else {xbc_get_info(&ret, NULL);pr_info("Load bootconfig: %ld bytes %d nodes\n", (long)size, ret);/* keys starting with "kernel." are passed via cmdline */extra_command_line = xbc_make_cmdline("kernel");/* Also, "init." keys are init arguments */extra_init_args = xbc_make_cmdline("init");}return;
}static void __init exit_boot_config(void)
{xbc_exit();
}#else /* !CONFIG_BOOT_CONFIG */static void __init setup_boot_config(void)
{/* Remove bootconfig data from initrd */get_boot_config_from_initrd(NULL);
}static int __init warn_bootconfig(char *str)
{pr_warn("WARNING: 'bootconfig' found on the kernel command line but CONFIG_BOOT_CONFIG is not set.\n");return 0;
}#define exit_boot_config() do {} while (0)#endif /* CONFIG_BOOT_CONFIG */early_param("bootconfig", warn_bootconfig);/* Change NUL term back to "=", to make "param" the whole string. */
static void __init repair_env_string(char *param, char *val)
{if (val) {/* param=val or param="val"? */if (val == param+strlen(param)+1)val[-1] = '=';else if (val == param+strlen(param)+2) {val[-2] = '=';memmove(val-1, val, strlen(val)+1);} elseBUG();}
}/* Anything after -- gets handed straight to init. */
static int __init set_init_arg(char *param, char *val,const char *unused, void *arg)
{unsigned int i;if (panic_later)return 0;repair_env_string(param, val);for (i = 0; argv_init[i]; i++) {if (i == MAX_INIT_ARGS) {panic_later = "init";panic_param = param;return 0;}}argv_init[i] = param;return 0;
}/** Unknown boot options get handed to init, unless they look like* unused parameters (modprobe will find them in /proc/cmdline).*/
static int __init unknown_bootoption(char *param, char *val,const char *unused, void *arg)
{size_t len = strlen(param);/* Handle params aliased to sysctls */if (sysctl_is_alias(param))return 0;repair_env_string(param, val);/* Handle obsolete-style parameters */if (obsolete_checksetup(param))return 0;/* Unused module parameter. */if (strnchr(param, len, '.'))return 0;if (panic_later)return 0;if (val) {/* Environment option */unsigned int i;for (i = 0; envp_init[i]; i++) {if (i == MAX_INIT_ENVS) {panic_later = "env";panic_param = param;}if (!strncmp(param, envp_init[i], len+1))break;}envp_init[i] = param;} else {/* Command line option */unsigned int i;for (i = 0; argv_init[i]; i++) {if (i == MAX_INIT_ARGS) {panic_later = "init";panic_param = param;}}argv_init[i] = param;}return 0;
}static int __init init_setup(char *str)
{unsigned int i;execute_command = str;/** In case LILO is going to boot us with default command line,* it prepends "auto" before the whole cmdline which makes* the shell think it should execute a script with such name.* So we ignore all arguments entered _before_ init=... [MJ]*/for (i = 1; i < MAX_INIT_ARGS; i++)argv_init[i] = NULL;return 1;
}
__setup("init=", init_setup);static int __init rdinit_setup(char *str)
{unsigned int i;ramdisk_execute_command = str;/* See "auto" comment in init_setup */for (i = 1; i < MAX_INIT_ARGS; i++)argv_init[i] = NULL;return 1;
}
__setup("rdinit=", rdinit_setup);#ifndef CONFIG_SMP
static inline void setup_nr_cpu_ids(void) { }
static inline void smp_prepare_cpus(unsigned int maxcpus) { }
#endif/** We need to store the untouched command line for future reference.* We also need to store the touched command line since the parameter* parsing is performed in place, and we should allow a component to* store reference of name/value for future reference.*/
static void __init setup_command_line(char *command_line)
{size_t len, xlen = 0, ilen = 0;if (extra_command_line)xlen = strlen(extra_command_line);if (extra_init_args)ilen = strlen(extra_init_args) + 4; /* for " -- " */len = xlen + strlen(boot_command_line) + 1;saved_command_line = memblock_alloc(len + ilen, SMP_CACHE_BYTES);if (!saved_command_line)panic("%s: Failed to allocate %zu bytes\n", __func__, len + ilen);len = xlen + strlen(command_line) + 1;static_command_line = memblock_alloc(len, SMP_CACHE_BYTES);if (!static_command_line)panic("%s: Failed to allocate %zu bytes\n", __func__, len);if (xlen) {/** We have to put extra_command_line before boot command* lines because there could be dashes (separator of init* command line) in the command lines.*/strcpy(saved_command_line, extra_command_line);strcpy(static_command_line, extra_command_line);}strcpy(saved_command_line + xlen, boot_command_line);strcpy(static_command_line + xlen, command_line);if (ilen) {/** Append supplemental init boot args to saved_command_line* so that user can check what command line options passed* to init.* The order should always be* " -- "[bootconfig init-param][cmdline init-param]*/if (initargs_offs) {len = xlen + initargs_offs;strcpy(saved_command_line + len, extra_init_args);len += ilen - 4; /* strlen(extra_init_args) */strcpy(saved_command_line + len,boot_command_line + initargs_offs - 1);} else {len = strlen(saved_command_line);strcpy(saved_command_line + len, " -- ");len += 4;strcpy(saved_command_line + len, extra_init_args);}}saved_command_line_len = strlen(saved_command_line);
}/** We need to finalize in a non-__init function or else race conditions* between the root thread and the init thread may cause start_kernel to* be reaped by free_initmem before the root thread has proceeded to* cpu_idle.** gcc-3.4 accidentally inlines this function, so use noinline.*/static __initdata DECLARE_COMPLETION(kthreadd_done);noinline void __ref __noreturn rest_init(void)
{struct task_struct *tsk;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.*/pid = user_mode_thread(kernel_init, NULL, CLONE_FS);/** Pin init on the boot CPU. Task migration is not properly working* until sched_init_smp() has been run. It will set the allowed* CPUs for init to the non isolated CPUs.*/rcu_read_lock();tsk = find_task_by_pid_ns(pid, &init_pid_ns);tsk->flags |= PF_NO_SETAFFINITY;set_cpus_allowed_ptr(tsk, cpumask_of(smp_processor_id()));rcu_read_unlock();numa_default_policy();pid = kernel_thread(kthreadd, NULL, NULL, CLONE_FS | CLONE_FILES);rcu_read_lock();kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);rcu_read_unlock();/** Enable might_sleep() and smp_processor_id() checks.* They cannot be enabled earlier because with CONFIG_PREEMPTION=y* kernel_thread() would trigger might_sleep() splats. With* CONFIG_PREEMPT_VOLUNTARY=y the init task might have scheduled* already, but it's stuck on the kthreadd_done completion.*/system_state = SYSTEM_SCHEDULING;complete(&kthreadd_done);/** The boot idle thread must execute schedule()* at least once to get things moving:*/schedule_preempt_disabled();/* Call into cpu_idle with preempt disabled */cpu_startup_entry(CPUHP_ONLINE);
}/* Check for early params. */
static int __init do_early_param(char *param, char *val,const char *unused, void *arg)
{const struct obs_kernel_param *p;for (p = __setup_start; p < __setup_end; p++) {if ((p->early && parameq(param, p->str)) ||(strcmp(param, "console") == 0 &&strcmp(p->str, "earlycon") == 0)) {if (p->setup_func(val) != 0)pr_warn("Malformed early option '%s'\n", param);}}/* We accept everything at this stage. */return 0;
}void __init parse_early_options(char *cmdline)
{parse_args("early options", cmdline, NULL, 0, 0, 0, NULL,do_early_param);
}/* Arch code calls this early on, or if not, just before other parsing. */
void __init parse_early_param(void)
{static int done __initdata;static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata;if (done)return;/* All fall through to do_early_param. */strscpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);parse_early_options(tmp_cmdline);done = 1;
}void __init __weak arch_post_acpi_subsys_init(void) { }void __init __weak smp_setup_processor_id(void)
{
}# if THREAD_SIZE >= PAGE_SIZE
void __init __weak thread_stack_cache_init(void)
{
}
#endifvoid __init __weak poking_init(void) { }void __init __weak pgtable_cache_init(void) { }void __init __weak trap_init(void) { }bool initcall_debug;
core_param(initcall_debug, initcall_debug, bool, 0644);#ifdef TRACEPOINTS_ENABLED
static void __init initcall_debug_enable(void);
#else
static inline void initcall_debug_enable(void)
{
}
#endif#ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,randomize_kstack_offset);
DEFINE_PER_CPU(u32, kstack_offset);static int __init early_randomize_kstack_offset(char *buf)
{int ret;bool bool_result;ret = kstrtobool(buf, &bool_result);if (ret)return ret;if (bool_result)static_branch_enable(&randomize_kstack_offset);elsestatic_branch_disable(&randomize_kstack_offset);return 0;
}
early_param("randomize_kstack_offset", early_randomize_kstack_offset);
#endifvoid __init __weak __noreturn arch_call_rest_init(void)
{rest_init();
}static void __init print_unknown_bootoptions(void)
{char *unknown_options;char *end;const char *const *p;size_t len;if (panic_later || (!argv_init[1] && !envp_init[2]))return;/** Determine how many options we have to print out, plus a space* before each*/len = 1; /* null terminator */for (p = &argv_init[1]; *p; p++) {len++;len += strlen(*p);}for (p = &envp_init[2]; *p; p++) {len++;len += strlen(*p);}unknown_options = memblock_alloc(len, SMP_CACHE_BYTES);if (!unknown_options) {pr_err("%s: Failed to allocate %zu bytes\n",__func__, len);return;}end = unknown_options;for (p = &argv_init[1]; *p; p++)end += sprintf(end, " %s", *p);for (p = &envp_init[2]; *p; p++)end += sprintf(end, " %s", *p);/* Start at unknown_options[1] to skip the initial space */pr_notice("Unknown kernel command line parameters \"%s\", will be passed to user space.\n",&unknown_options[1]);memblock_free(unknown_options, len);
}asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
void start_kernel(void)
{char *command_line;char *after_dashes;set_task_stack_end_magic(&init_task);smp_setup_processor_id();debug_objects_early_init();init_vmlinux_build_id();cgroup_init_early();local_irq_disable();early_boot_irqs_disabled = true;/** Interrupts are still disabled. Do necessary setups, then* enable them.*/boot_cpu_init();page_address_init();pr_notice("%s", linux_banner);early_security_init();setup_arch(&command_line);setup_boot_config();setup_command_line(command_line);setup_nr_cpu_ids();setup_per_cpu_areas();smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */boot_cpu_hotplug_init();pr_notice("Kernel command line: %s\n", saved_command_line);/* parameters may set static keys */jump_label_init();parse_early_param();after_dashes = parse_args("Booting kernel",static_command_line, __start___param,__stop___param - __start___param,-1, -1, NULL, &unknown_bootoption);print_unknown_bootoptions();if (!IS_ERR_OR_NULL(after_dashes))parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,NULL, set_init_arg);if (extra_init_args)parse_args("Setting extra init args", extra_init_args,NULL, 0, -1, -1, NULL, set_init_arg);/* Architectural and non-timekeeping rng init, before allocator init */random_init_early(command_line);/** These use large bootmem allocations and must precede* initalization of page allocator*/setup_log_buf(0);vfs_caches_init_early();sort_main_extable();trap_init();mm_core_init();poking_init();ftrace_init();/* trace_printk can be enabled here */early_trace_init();/** 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();if (WARN(!irqs_disabled(),"Interrupts were enabled *very* early, fixing it\n"))local_irq_disable();radix_tree_init();maple_tree_init();/** Set up housekeeping before setting up workqueues to allow the unbound* workqueue to take non-housekeeping into account.*/housekeeping_init();/** Allow workqueue creation and work item queueing/cancelling* early. Work item execution depends on kthreads and starts after* workqueue_init().*/workqueue_init_early();rcu_init();/* Trace events are available after this */trace_init();if (initcall_debug)initcall_debug_enable();context_tracking_init();/* init some links before init_ISA_irqs() */early_irq_init();init_IRQ();tick_init();rcu_init_nohz();init_timers();srcu_init();hrtimers_init();softirq_init();timekeeping_init();time_init();/* This must be after timekeeping is initialized */random_init();/* These make use of the fully initialized rng */kfence_init();boot_init_stack_canary();perf_event_init();profile_init();call_function_init();WARN(!irqs_disabled(), "Interrupts were enabled early\n");early_boot_irqs_disabled = false;local_irq_enable();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();if (panic_later)panic("Too many boot %s vars at `%s'", panic_later,panic_param);lockdep_init();/** 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_INITRDif (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;}
#endifsetup_per_cpu_pageset();numa_policy_init();acpi_early_init();if (late_time_init)late_time_init();sched_clock_init();calibrate_delay();arch_cpu_finalize_init();pid_idr_init();anon_vma_init();
#ifdef CONFIG_X86if (efi_enabled(EFI_RUNTIME_SERVICES))efi_enter_virtual_mode();
#endifthread_stack_cache_init();cred_init();fork_init();proc_caches_init();uts_ns_init();key_init();security_init();dbg_late_init();net_ns_init();vfs_caches_init();pagecache_init();signals_init();seq_file_init();proc_root_init();nsfs_init();cpuset_init();cgroup_init();taskstats_init_early();delayacct_init();acpi_subsystem_init();arch_post_acpi_subsys_init();kcsan_init();/* Do the rest non-__init'ed, we're now alive */arch_call_rest_init();/** Avoid stack canaries in callers of boot_init_stack_canary for gcc-10* and older.*/
#if !__has_attribute(__no_stack_protector__)prevent_tail_call_optimization();
#endif
}/* Call all constructor functions linked into the kernel. */
static void __init do_ctors(void)
{
/** For UML, the constructors have already been called by the* normal setup code as it's just a normal ELF binary, so we* cannot do it again - but we do need CONFIG_CONSTRUCTORS* even on UML for modules.*/
#if defined(CONFIG_CONSTRUCTORS) && !defined(CONFIG_UML)ctor_fn_t *fn = (ctor_fn_t *) __ctors_start;for (; fn < (ctor_fn_t *) __ctors_end; fn++)(*fn)();
#endif
}#ifdef CONFIG_KALLSYMS
struct blacklist_entry {struct list_head next;char *buf;
};static __initdata_or_module LIST_HEAD(blacklisted_initcalls);static int __init initcall_blacklist(char *str)
{char *str_entry;struct blacklist_entry *entry;/* str argument is a comma-separated list of functions */do {str_entry = strsep(&str, ",");if (str_entry) {pr_debug("blacklisting initcall %s\n", str_entry);entry = memblock_alloc(sizeof(*entry),SMP_CACHE_BYTES);if (!entry)panic("%s: Failed to allocate %zu bytes\n",__func__, sizeof(*entry));entry->buf = memblock_alloc(strlen(str_entry) + 1,SMP_CACHE_BYTES);if (!entry->buf)panic("%s: Failed to allocate %zu bytes\n",__func__, strlen(str_entry) + 1);strcpy(entry->buf, str_entry);list_add(&entry->next, &blacklisted_initcalls);}} while (str_entry);return 1;
}static bool __init_or_module initcall_blacklisted(initcall_t fn)
{struct blacklist_entry *entry;char fn_name[KSYM_SYMBOL_LEN];unsigned long addr;if (list_empty(&blacklisted_initcalls))return false;addr = (unsigned long) dereference_function_descriptor(fn);sprint_symbol_no_offset(fn_name, addr);/** fn will be "function_name [module_name]" where [module_name] is not* displayed for built-in init functions. Strip off the [module_name].*/strreplace(fn_name, ' ', '\0');list_for_each_entry(entry, &blacklisted_initcalls, next) {if (!strcmp(fn_name, entry->buf)) {pr_debug("initcall %s blacklisted\n", fn_name);return true;}}return false;
}
#else
static int __init initcall_blacklist(char *str)
{pr_warn("initcall_blacklist requires CONFIG_KALLSYMS\n");return 0;
}static bool __init_or_module initcall_blacklisted(initcall_t fn)
{return false;
}
#endif
__setup("initcall_blacklist=", initcall_blacklist);static __init_or_module void
trace_initcall_start_cb(void *data, initcall_t fn)
{ktime_t *calltime = data;printk(KERN_DEBUG "calling %pS @ %i\n", fn, task_pid_nr(current));*calltime = ktime_get();
}static __init_or_module void
trace_initcall_finish_cb(void *data, initcall_t fn, int ret)
{ktime_t rettime, *calltime = data;rettime = ktime_get();printk(KERN_DEBUG "initcall %pS returned %d after %lld usecs\n",fn, ret, (unsigned long long)ktime_us_delta(rettime, *calltime));
}static ktime_t initcall_calltime;#ifdef TRACEPOINTS_ENABLED
static void __init initcall_debug_enable(void)
{int ret;ret = register_trace_initcall_start(trace_initcall_start_cb,&initcall_calltime);ret |= register_trace_initcall_finish(trace_initcall_finish_cb,&initcall_calltime);WARN(ret, "Failed to register initcall tracepoints\n");
}
# define do_trace_initcall_start trace_initcall_start
# define do_trace_initcall_finish trace_initcall_finish
#else
static inline void do_trace_initcall_start(initcall_t fn)
{if (!initcall_debug)return;trace_initcall_start_cb(&initcall_calltime, fn);
}
static inline void do_trace_initcall_finish(initcall_t fn, int ret)
{if (!initcall_debug)return;trace_initcall_finish_cb(&initcall_calltime, fn, ret);
}
#endif /* !TRACEPOINTS_ENABLED */int __init_or_module do_one_initcall(initcall_t fn)
{int count = preempt_count();char msgbuf[64];int ret;if (initcall_blacklisted(fn))return -EPERM;do_trace_initcall_start(fn);ret = fn();do_trace_initcall_finish(fn, ret);msgbuf[0] = 0;if (preempt_count() != count) {sprintf(msgbuf, "preemption imbalance ");preempt_count_set(count);}if (irqs_disabled()) {strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));local_irq_enable();}WARN(msgbuf[0], "initcall %pS returned with %s\n", fn, msgbuf);add_latent_entropy();return ret;
}static initcall_entry_t *initcall_levels[] __initdata = {__initcall0_start,__initcall1_start,__initcall2_start,__initcall3_start,__initcall4_start,__initcall5_start,__initcall6_start,__initcall7_start,__initcall_end,
};/* Keep these in sync with initcalls in include/linux/init.h */
static const char *initcall_level_names[] __initdata = {"pure","core","postcore","arch","subsys","fs","device","late",
};static int __init ignore_unknown_bootoption(char *param, char *val,const char *unused, void *arg)
{return 0;
}static void __init do_initcall_level(int level, char *command_line)
{initcall_entry_t *fn;parse_args(initcall_level_names[level],command_line, __start___param,__stop___param - __start___param,level, level,NULL, ignore_unknown_bootoption);trace_initcall_level(initcall_level_names[level]);for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)do_one_initcall(initcall_from_entry(fn));
}static void __init do_initcalls(void)
{int level;size_t len = saved_command_line_len + 1;char *command_line;command_line = kzalloc(len, GFP_KERNEL);if (!command_line)panic("%s: Failed to allocate %zu bytes\n", __func__, len);for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) {/* Parser modifies command_line, restore it each time */strcpy(command_line, saved_command_line);do_initcall_level(level, command_line);}kfree(command_line);
}/** Ok, the machine is now initialized. None of the devices* have been touched yet, but the CPU subsystem is up and* running, and memory and process management works.** Now we can finally start doing some real work..*/
static void __init do_basic_setup(void)
{cpuset_init_smp();driver_init();init_irq_proc();do_ctors();do_initcalls();
}static void __init do_pre_smp_initcalls(void)
{initcall_entry_t *fn;trace_initcall_level("early");for (fn = __initcall_start; fn < __initcall0_start; fn++)do_one_initcall(initcall_from_entry(fn));
}static int run_init_process(const char *init_filename)
{const char *const *p;argv_init[0] = init_filename;pr_info("Run %s as init process\n", init_filename);pr_debug(" with arguments:\n");for (p = argv_init; *p; p++)pr_debug(" %s\n", *p);pr_debug(" with environment:\n");for (p = envp_init; *p; p++)pr_debug(" %s\n", *p);return kernel_execve(init_filename, argv_init, envp_init);
}static int try_to_run_init_process(const char *init_filename)
{int ret;ret = run_init_process(init_filename);if (ret && ret != -ENOENT) {pr_err("Starting init: %s exists but couldn't execute it (error %d)\n",init_filename, ret);}return ret;
}static noinline void __init kernel_init_freeable(void);#if defined(CONFIG_STRICT_KERNEL_RWX) || defined(CONFIG_STRICT_MODULE_RWX)
bool rodata_enabled __ro_after_init = true;#ifndef arch_parse_debug_rodata
static inline bool arch_parse_debug_rodata(char *str) { return false; }
#endifstatic int __init set_debug_rodata(char *str)
{if (arch_parse_debug_rodata(str))return 0;if (str && !strcmp(str, "on"))rodata_enabled = true;else if (str && !strcmp(str, "off"))rodata_enabled = false;elsepr_warn("Invalid option string for rodata: '%s'\n", str);return 0;
}
early_param("rodata", set_debug_rodata);
#endif#ifdef CONFIG_STRICT_KERNEL_RWX
static void mark_readonly(void)
{if (rodata_enabled) {/** load_module() results in W+X mappings, which are cleaned* up with init_free_wq. Let's make sure that queued work is* flushed so that we don't hit false positives looking for* insecure pages which are W+X.*/flush_module_init_free_work();mark_rodata_ro();rodata_test();} elsepr_info("Kernel memory protection disabled.\n");
}
#elif defined(CONFIG_ARCH_HAS_STRICT_KERNEL_RWX)
static inline void mark_readonly(void)
{pr_warn("Kernel memory protection not selected by kernel config.\n");
}
#else
static inline void mark_readonly(void)
{pr_warn("This architecture does not have kernel memory protection.\n");
}
#endifvoid __weak free_initmem(void)
{free_initmem_default(POISON_FREE_INITMEM);
}static int __ref kernel_init(void *unused)
{int ret;/** Wait until kthreadd is all set-up.*/wait_for_completion(&kthreadd_done);kernel_init_freeable();/* need to finish all async __init code before freeing the memory */async_synchronize_full();system_state = SYSTEM_FREEING_INITMEM;kprobe_free_init_mem();ftrace_free_init_mem();kgdb_free_init_mem();exit_boot_config();free_initmem();mark_readonly();/** Kernel mappings are now finalized - update the userspace page-table* to finalize PTI.*/pti_finalize();system_state = SYSTEM_RUNNING;numa_default_policy();rcu_end_inkernel_boot();do_sysctl_args();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.*/if (execute_command) {ret = run_init_process(execute_command);if (!ret)return 0;panic("Requested init %s failed (error %d).",execute_command, ret);}if (CONFIG_DEFAULT_INIT[0] != '\0') {ret = run_init_process(CONFIG_DEFAULT_INIT);if (ret)pr_err("Default init %s failed (error %d)\n",CONFIG_DEFAULT_INIT, ret);elsereturn 0;}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/admin-guide/init.rst for guidance.");
}/* Open /dev/console, for stdin/stdout/stderr, this should never fail */
void __init console_on_rootfs(void)
{struct file *file = filp_open("/dev/console", O_RDWR, 0);if (IS_ERR(file)) {pr_err("Warning: unable to open an initial console.\n");return;}init_dup(file);init_dup(file);init_dup(file);fput(file);
}static noinline void __init kernel_init_freeable(void)
{/* Now the scheduler is fully set up and can do blocking allocations */gfp_allowed_mask = __GFP_BITS_MASK;/** init can allocate pages on any node*/set_mems_allowed(node_states[N_MEMORY]);cad_pid = get_pid(task_pid(current));smp_prepare_cpus(setup_max_cpus);workqueue_init();init_mm_internals();rcu_init_tasks_generic();do_pre_smp_initcalls();lockup_detector_init();smp_init();sched_init_smp();workqueue_init_topology();padata_init();page_alloc_init_late();do_basic_setup();kunit_run_all_tests();wait_for_initramfs();console_on_rootfs();/** check if there is an early userspace init. If yes, let it do all* the work*/if (init_eaccess(ramdisk_execute_command) != 0) {ramdisk_execute_command = NULL;prepare_namespace();}/** Ok, we have completed the initial bootup, and* we're essentially up and running. Get rid of the* initmem segments and start the user-mode stuff..** rootfs is available now, try loading the public keys* and default modules*/integrity_load_keys();
}
相关文章:

Linux内核.之 init文件,/init/main.c
想要熟悉内核,看下源码,就非常清晰 Linux内核,head.s,汇编启动cpu相关设置后,启动init文件里的,文件在内核的/init/main.c,看下main函数,做了哪些工作 // SPDX-License-Identifier: …...

CentOS系统中查看内网端口映射的多种方法
在网络管理中,了解和控制内网端口映射是至关重要的。本文将为您详细介绍在CentOS系统中查看内网端口映射的多种方法,助您提升网络管理效率。 使用netstat命令查看端口映射 netstat是一个强大的网络诊断工具。要查看当前的端口映射情况,可以在…...

Mac中禁用系统更新
Mac中禁用系统更新 文章目录 Mac中禁用系统更新1. 修改hosts,屏蔽系统更新检测联网1. 去除系统偏好设置--系统更新已有的小红点标记 1. 修改hosts,屏蔽系统更新检测联网 打开终端,执行命令: sudo vim /etc/hosts127.0.0.1 swdis…...

GoogLeNet-水果分类
GoogLeNet-水果分类 1.数据集 官方下载地址:https://www.kaggle.com/datasets/karimabdulnabi/fruit-classification10-class?resourcedownload 备用下载地址:https://www.123684.com/s/xhlWjv-pRAPh 介绍: 十个类别:苹果、…...

深度学习入门指南:一篇文章全解
目录 0.前言 1.深度学习的背景历史 2.深度学习主要研究的内容 3.深度学习的分支 3.1.卷积神经网络(CNN) 3.2 递归神经网络(RNN) 3. 3长短期记忆网络(LSTM) 4.深度学习的主要应用 4.1计算机视觉 4…...

java ssm 医院病房管理系统 医院管理 医疗病房信息管理 源码 jsp
一、项目简介 本项目是一套基于SSM的医院病房管理系统,主要针对计算机相关专业的和需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本、软件工具等。 项目都经过严格调试,确保可以运行! 二、技术实现 后端技术&#x…...

钩子函数的使用
钩子函数在计算机科学和软件工程中,特别是在编程框架和库中,是一种特殊的函数或方法,它们允许用户在框架或库的特定点插入自定义代码。这些钩子提供了一种扩展框架功能而无需修改其源代码的方式。 在前后端分离的项目中,如使用Dj…...

【Docker】自定义网络:实现容器之间通过域名相互通讯
文章目录 一. 默认网络:docker0网络的问题二. 自定义网络三. nginx容器指之间通过主机名进行内部通讯四. redis集群容器(跳过宿主机)内部网络通讯1. 集群描述2. 基于bitnami镜像的环境变量快速构建redis集群 一. 默认网络:docker0…...

护理陪护系统|护理陪护软件|陪护软件
在当今社会,随着人口老龄化的加剧和生活节奏的加快,护理陪护服务的需求日益增长。为了满足这一需求,开发定制一套高效、专业的护理陪护系统显得尤为重要。在开发过程中,有几个关键方面不能忽视。 一、用户需求分析 护理陪护系统的…...

苍穹外卖-账号被锁定怎么办?
刚刚解决的小问题, 最近在搞黑马程序员的苍穹外卖项目, 在完善开发编辑员工功能的时候, 不知道怎么搞的, 无论是swagger接口测试, 还是前后端联调, 都显示"账号被锁定", 原本想在网上找找解释, 结果我太笨, 搜不到, 那就只能在代码里面排查咯, 既然是登录接口出…...

webpack loader全解析,从入门到精通(10)
webpack 的核心功能是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。更多复杂的功能需要借助 webpack loaders 和 plugins 来完成。 1. 什么是 Loader Loader 本质上是一个函数,它的作用是将某个源码字符串转换成…...

python机器人Agent编程——实现一个本地大模型和爬虫结合的手机号归属地天气查询Agent
目录 一、前言二、准备工作三、Agent结构四、python模块实现4.1 实现手机号归属地查询工具4.2实现天气查询工具4.3定义创建Agent主体4.4创建聊天界面 五、小结PS.扩展阅读ps1.六自由度机器人相关文章资源ps2.四轴机器相关文章资源ps3.移动小车相关文章资源ps3.wifi小车控制相关…...

【动态规划】斐波那契数列模型总结
一、第 N 个泰波那契数 题目链接: 第 N 个泰波那契数 题目描述: 题目分析: 1、状态表示: dp[i] 表示:第 i 个斐波那契数的值 2、状态转移方程: 由题意可知第 i 个数等于其前三个数之和 dp[i] dp[i-…...

EasyUI弹出框行编辑,通过下拉框实现内容联动
EasyUI弹出框行编辑,通过下拉框实现内容联动 需求 实现用户支付方式配置,当弹出框加载出来的时候,显示用户现有的支付方式,datagrid的第一列为conbobox,下来选择之后实现后面的数据直接填充; 点击新增:新…...

国产linux系统(银河麒麟,统信uos)使用 PageOffice 实现word文件在线留痕
PageOffice 国产版 :支持信创系统,支持银河麒麟V10和统信UOS,支持X86(intel、兆芯、海光等)、ARM(飞腾、鲲鹏、麒麟等)、龙芯(LoogArch)芯片架构。 查看本示例演示效果 …...

使用亚马逊 S3 连接器为 PyTorch 和 MinIO 创建地图式数据集
在深入研究 Amazon 的 PyTorch S3 连接器之前,有必要介绍一下它要解决的问题。许多 AI 模型需要使用无法放入内存的数据进行训练。此外,许多为计算机视觉和生成式 AI 构建的真正有趣的模型使用的数据甚至无法容纳在单个服务器附带的磁盘驱动器上。解决存…...

自动化运维:提升效率与稳定性的关键技术实践
自动化运维:提升效率与稳定性的关键技术实践 在数字化转型的浪潮中,企业对于IT系统的依赖日益加深,系统的复杂性和规模也随之膨胀。面对这一挑战,传统的运维模式——依靠人工进行服务器的监控、配置变更、故障排查等任务…...

Google Go编程风格指南-介绍
关于 首先应该明确的是:Go语言是Google搞出来的,这个编程风格指南也是它提出来的,详见:https://google.github.io/styleguide/go/。 然后国内翻译组跟上,于是有了中文版:https://gocn.github.io/stylegui…...

思科模拟器路由器配置实验
一、实验目的 了解路由器的作用。掌握路由器的基本配置方法。掌握路由器模块的使用和互连方式。 二、实验环境 设备: 2811 路由器 1 台计算机 2 台Console 配置线 1 根网线若干根 拓扑图:实验拓扑图如图 8-1 所示。计算机 IP 地址规划:如表…...

机器学习—选择激活函数
可以为神经网络中的不同神经元选择激活函数,我们将从如何为输出层选择它的一些指导开始,事实证明,取决于目标标签或地面真相标签y是什么,对于输出层的激活函数,将有一个相当自然的选择,然后看看激活函数的选…...

[ Linux 命令基础 4 ] Linux 命令详解-文本处理命令
🍬 博主介绍 👨🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…...

Odoo:免费开源的钢铁冶金行业ERP管理系统
文 / 开源智造 Odoo亚太金牌服务 简介 Odoo免费开源ERP集成计质量设备大宗原料采购,备件设材全生命周期,多业务模式货控销售,全要素追溯单品,无人值守计量物流,大宗贸易交易和精细化成本管理等方案;覆盖…...

33.Redis多线程
1.Redis队列与Stream Redis5.0 最大的新特性就是多出了一个数据结构 Stream,它是一个新的强大的支持多播的可持久化的消息队列。 Redis Stream 的结构如上图所示,每一个Stream都有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯…...

【Python】解析 XML
1、Python 对 XML 的解析 1.1 SAX (simple API for XML ) SAX 解析器使用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。 xml.sax 模块牺牲了便捷性来换取速度和内存占用。 事件驱动指一种基于回调(ca…...

【复平面】-复数相乘的几何性质
文章目录 从数学上证明1. 计算乘积 z 1 ⋅ z 2 z_1 \cdot z_2 z1⋅z22. 应用三角恒等式3. 得出结果 从几何角度证明1.给出待乘的复数 u i u_i ui2.给出任意复数 l l l3.复数 l l l 在不同坐标轴下的表示图 首先说结论: 在复平面中,两个复数&a…...

为什么ta【给脸不要脸】:利他是一种选择,善良者的自我救赎与智慧策略
你满腔热忱,他却视而不见; 你伸出援手,他却恩将仇报; 你谦让包容,他却得寸进尺; 你善意提拔,他却并不领情,反而“给脸不要脸”。 所有人都曾被这种“好心当成驴肝肺”遭遇内耗&a…...

mysql 配置文件 my.cnf 增加 lower_case_table_names = 1 服务启动不了的原因
原因:在MySQL8.0之后的版本,只允许在数据库初始化时指定,之后不允许修改了 mysql 配置文件 my.cnf 增加 lower_case_table_names 1 服务启动不了 报错信息:Job for mysqld.service failed because the control process exited …...

SIwave:释放 SIwizard 求解器的强大功能
SIwave 是一种电源完整性和信号完整性工具。SIwizard 是 SIwave 中 SI 分析的主要工具,也是本博客的主题。 SIwizard 用于研究 RF、clock 和 control traces 的信号完整性。该工具允许用户进行瞬态分析、眼图分析和 BER 计算。用户可以将 IBIS 和 IBIS-AMI 模型添加…...

强化学习不愧“顶会收割机”!2大创新思路带你上大分,毕业不用愁!
强化学习之父Richard Sutton悄悄搞了个大的,提出了一个简单思路:奖励聚中。这思路简单效果却不简单,等于是给几乎所有的强化学习算法上了一个增强buff,所以这篇论文已经入选了首届强化学习会议(RLC 2024)&a…...

mac 修改启动图图标数量
调整每行显示图标数量: defaults write com.apple.dock springboard-rows -int 7 调整每列显示的数量 defaults write com.apple.dock springboard-columns -int 8 最后重置一下启动台 defaults write com.apple.dock ResetLaunchPad -bool TRUE;killall Dock 其…...