OK6410A 开发板 (三) 12 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 boot 详细解析1

2024-05-27 15:58

本文主要是介绍OK6410A 开发板 (三) 12 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 boot 详细解析1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

url 		: git@github.com:lisider/u-boot.git
branch 		: ok6410a
commit id 	: e63a4077ad3aea53107495b0b68b95e720fe6033
config 		: ok6410a_mini_defconfig
// 涉及的 .S .s .c 文件 有 223个
reset														arch/arm/cpu/arm1176/start.S 39lowlevel_init(108)										board/samsung/ok6410a/lowlevel_init.S 72_main(110) 												arch/arm/lib/crt0.S 91board_init_f(117)									common/board_f.c 954initcall_run_list(init_sequence_f)(959) 		include/initcall.h 21init_sequence_f								common/board_f.c 818board_init_r(177) 									common/board_r.c 901initcall_run_list(init_sequence_r)(927) 		include/initcall.h 21init_sequence_r 							common/board_f.c 695run_main_loop(898)						common/board_r.c 678main_loop(685) 						common/main.c 39
  • 解析概要
// 入口 为 arch/arm/lib/vectors.S 中的 _start 标号处的 b reset
resetlowlevel_init时钟串口ddr_main// 从代码运行起始位置0x5FB00000 往下 找 gd 和栈 的位置bl board_init_f_alloc_reserve// 设置栈mov sp, r0// 设置gd mov r9, r0// 初始化gdbl board_init_f_init_reserve bl board_init_f 查找 设备树的地址准备 early malloc驱动模型的前期准备定时器初始化,为delay做准备env 初始化,为查找环境变量做准备串口波特率环境变量的查找和串口波特率的设置,为printf做准备从 ddr 顶端 0x5FFF FFFF 往下 找 空间1. mmu2. u-boot3. malloc4. new_gd5. fdt6. irq 栈7. 栈搬移 gd搬移设备树(fdt)// 搬移 u-boot 并 fixloopb relocate_code// 搬移向量表 到 0x0000 0000bl relocate_vectorsCLEAR_BSS// 清.bss 段 , 这是u-boot阶段第一次清, relocate 之前没有清过ldr pc,=board_init_r// 开 icache 和 dcacheinitr_caches// 为 full malloc 做准备initr_malloc// 驱动模型的后期准备initr_dm// 初始化 board IDboard_init// 串口及控制台的初始化stdio_init_tablesserial_initialize stdio_add_devicesconsole_init_r// 其他设备的初始化initr_mmcinitr_ethaddrinitr_net// env 的后初始化initr_env// 跳转表???// the jump table contains pointers to exported functions.// A pointer to the jump table is passed to standalone applications.// 也就是 说 导出 让 standalone 应用用的// u-boot 命令行 可以 加载 bin 文件,并执行 这些bin文件就是 standalone applications// 查看 doc/README.standaloneinitr_jumptable// 中断相关的初始化(开中断,相关变量)interrupt_initmain_loopbootcmd以及cmdline
  • 详细解析

// common/init/board_init.c
// register volatile gd_t *gd asm ("r9");
// arch/arm/include/asm/global_data.h:112:#define DECLARE_GLOBAL_DATA_PTR          register volatile gd_t *gd asm ("r9")reset // 运行在 5FB0 0000// sdram : 0x5000_0000 0x5FFF_FFFFlowlevel_initspl_config_uart_baudrateulong val = spl_uart_getclk(is_mpll) / 115200;_UBRDIV = val / 16 - 1;_UDIVSLOT = udivslot[val % 16];mem_ctrl_asm_init// ddr初始化_mainboard_init_f_alloc_reserve // 算出gd的地址为 0x5f9fff20// 过程与数据和spl 完全一样申请 struct global_data 个字节 用来存储 gd_t *gd 指向的 gd_t 结构体// include/asm-generic/global_data.h 中 有 gd_t 的 定义board_init_f_init_reserve // 根据 gd的地址 0x5f9fff20 算出结构体// 过程与数据和spl 完全一样初始化 gd_t *gd 指向的 gd_t 结构体 空间 为 0初始化 gd_t *gd 指向的 gd_t 结构体 的 成员 malloc_base = 5F9F FFF0// u-boot过程和 spl 过程用到的 gd 指针是同一个位置// 但是 内容不同,因为在 初始化的时候,已经将 gd指针指向的位置全部 memset 0 了	// spl 加载 u-boot 的过程中, 就是 A加载B// A 加载 B 可以 通过 寄存器 来传值// 但是 spl 加载 u-boot 的过程中可以说没有传递任何值// 虽然 都用r9 保存了 gd的指针值,但是 r9 是算出来的,不是 spl 传过来的./*下面的这几行有两个目标1. 设置sp2. 存储gd指针变量并clear gd指针变量指向的空间,并设置 gd->malloc_base = 0x5f9f ff20;ldr r0, =((0x5FB00000 - 0x0C)) 		=> r0 : 5FAF FFF4bic r0, r0, #7 						=> r0 : 5FAF FFF0mov sp, r0 							=> sp : 5FAF FFF0bl board_init_f_alloc_reserve 		=> r0 : 5f9f ff20 (5FAF FFF0 - 0x10 0000 - 0xD0)mov sp, r0 							=> sp : 5f9f ff20             ***** 设置了 栈指针mov r9, r0 							=> r9 : 5f9f ff20 			  ***** 存储了 gd指针变量的值bl board_init_f_init_reserve 		=> 初始化 (5f9fff20 - 5f9fff20+0xD0) 的空间*//*// .code .rodata .data .bss .stack .heap此时的内存分布5FFF FFFF---------------------5FFF FFFF5120KB(0x500000)大小,被512KB u-boot.bin占据 // 不管u-boot.bin有没有512KB,都会从mmc上拷贝512KB过来 // U-boot.bin实际大小 248K内存中的u-boot.bin 中存在 .bss段,起始为5FB3 61F0,结束为5FB3 BAD4内存中的u-boot.bin 也存在 .code .rodata .data5FB0 0000---------------------16B(0x10)大小,空洞5FAF FFF0---------------------1024KB(0x100000)大小,用于sys_malloc (.heap)5F9F FFF0---------------------208B(0xD0)大小,用于gd (很特殊的一个全局变量)5F9F FF20---------------------255999KB(约250MB)大小,用于栈 (.stack)5000 0000---------------------5000 0000*/board_init_f // 被调用的时候传递的参数为 0 ,用来设置flags.gd->flags = 0;gd->have_console = 0;setup_mon_len // 第一次使用栈,(sp) // 重要参考点1gd->mon_len = (ulong)&__bss_end - (ulong)_start;// = 0x3bc4c// 为 reserve_uboot 做准备fdtdec_setup // 为设备树的解析做准备gd->fdt_blob = board_fdt_blob_setup();return (ulong *)&_end;gd->fdt_blob = map_sysmem (env_get_ulong("fdtcontroladdr", 16, (unsigned long)map_to_sysmem(gd->fdt_blob)), 0);// 解码fdtcontroladdr环境变量的值,16进制,如果为空则为gd->fdt_blobfdtdec_prepare_fdt // 检查gd->fdt_blob为空,则报错fdtdec_board_setup// nullinitf_malloc // 为 early malloc 做准备// 用于 early malloc// 此前 gd->malloc_base 已经被初始化为 5F9F FFF0 // base address of early mallocgd->malloc_limit = 0x100000; // limit address of early mallocgd->malloc_ptr = 0; // current address of early malloclog_init// nullinitf_bootstagebootstage_init(1)// nullbootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f")show_boot_progress(id);//null // TODO, 另一个路径大概率是 printfsetup_spl_handoff// nullinitf_console_record// nullarch_cpu_init// nullmach_cpu_init// nullinitf_dm // dm 架构(driver-model),比较复杂,后续有空更新专题 // 为 驱动和设备的注册做准备bootstage_start(BOOTSTAGE_ID_ACCUM_DM_F, "dm_f");// nulldm_init_and_scan(1)dm_init(0)INIT_LIST_HEAD(&(((gd_t *)gd)->uclass_root));list->next = list;list->prev = list;device_bind_by_name(0,0,&root_info, &(((gd_t *)gd)->dm_root)));lists_driver_lookup_name(info->name);device_bind_common(parent, drv, info->name, (void *)info->platdata, 0, ofnode_null(), platdata_size, devp);(((gd_t *)gd)->dm_root)->node = offset_to_ofnode(0)device_probe((((gd_t *)gd)->dm_root))dm_scan_platdata(1)lists_bind_drivers((((gd_t *)gd)->dm_root), 1)dm_extended_scan_fdt(gd->fdt_blob, 1)dm_scan_fdt(gd->fdt_blob,1)dm_scan_fdt_node(gd->dm_root, blob, 0, 1);for_each_node dm_scan_fdt_ofnode_path(blob, nodes[i], 1);dm_scan_other(1)// nullbootstage_accum(BOOTSTAGE_ID_ACCUM_DM_F);// nullarch_cpu_init_dm// nulltimer_init // 为 delay 做准备// 设置 s3c6410的 硬件timergd->arch.timer_rate_hz = pre_freq/1;gd->arch.timer_rate_hz *= 1000;gd->arch.lastinc = timers->TCNTB4 = gd->arch.timer_rate_hz;gd->arch.timer_reset_value = 0;env_initenv_driver_lookupenv_get_locationreturn env_locations[prio] ; // ENVL_MMC_env_driver_lookupn_ents = xxxin section .u_boot_list_2_env_driver ,根据 ENVL_MMC 找到对应的 驱动对应的结构体 struct env_driverdrv->init	 // drv 为找到的结构体 struct env_driver _u_boot_list_2_env_driver_2_mmc 中没有 init 成员env_set_inited(drv->location)gd->env_has_init |= (1UL << (location));gd->env_addr = (ulong)&default_environment[0]; // 待研究gd->env_valid = ENV_VALID;init_baud_rategd->baudrate = env_get_ulong("baudrate", 10, 115200);const char *str = env_get(name);env_get_fenv_get_charenv_matchreturn str ? simple_strtoul(str,0,10) : default_val;serial_initserial_find_console_or_panicserial_check_stdoutstr = fdtdec_get_chosen_prop(blob, "stdout-path");node = fdt_path_offset_namelen(blob, str, namelen);lists_bind_fdtdevice_probe(&dev)gd->cur_serial_dev = dev;gd->flags |= GD_FLG_SERIAL_READY;serial_setbrggd->cur_serial_dev->driver->ops->setbrg(gd->cur_serial_dev, gd->baudrate)// s3c_serial_setbrgs3c_serial_setbrg_internal((struct s3c64xx_uart * )CONFIG_DEBUG_UART_BASE, 0 /*CFG_SERIAL_ID*/,CONFIG_BAUDRATE);u32 uclk = get_uart_clk(id)s3c64xx_serial_baud(uart, uclk, baudrate);uart->UBRDIV = uclk / baudrate / 16 - 1;uart->UDIVSLOT = udivslot[val];barrier(); // 内存顺序模型相关console_init_fgd->have_console = 1;console_update_silent// nullprint_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);// null TODO// PRE_CONSOLE_BUFFERdisplay_options // printf 可以使用 // 重要参考点2display_options_get_banner(true, buf, sizeof(buf));display_options_get_banner_privsnprintfprintf("%s", buf);display_text_infobss_start = (ulong)&__bss_start;bss_end = (ulong)&__bss_end;text_base = 0x5FB00000;checkcpu// nullprint_cpuinfoprintf("**    Updated for OK6410A Board        **\r\n");show_board_infomodel = fdt_getprop(gd->fdt_blob, 0, "model", ((void *)0));printf("Model: %s\n", model);// 实际打印 为 Model: Samsung SMDK6410 based on S3C6410// 打印的字符串为 arch/arm/dts/s3c64xx-ok6410a.dts 中的 model 节点的属性checkboardprintf("Board:   OK6410A\n");announce_dram_initputs("DRAM:  ");dram_initgd->ram_size += SDRAM_BANK_SIZE; // = 0x1000 0000setup_dest_addrgd->ram_base = 0x50000000;gd->ram_top = gd->ram_base + get_effective_memsize();// get_effective_memsize: gd->ram_size// = 0x6000 0000gd->ram_top = board_get_usable_ram_top(gd->mon_len);// = gd->ram_top // = 0x6000 0000gd->relocaddr = gd->ram_top;// = 0x6000 0000reserve_round_4kgd->relocaddr &= ~(4096 - 1);// hex 后三位与0// 0x6000 0000arch_reserve_mmuarm_reserve_mmugd->arch.tlb_size = (4096 * 4);// 0x4000 16Kgd->relocaddr -= gd->arch.tlb_size;// 0x5FFF C000gd->relocaddr &= ~(0x10000 - 1);// hex 后四位 与0// 0x5fff 0000gd->arch.tlb_addr = gd->relocaddr;// 0x5fff 0000reserve_video// nullreserve_trace// nullreserve_ubootgd->relocaddr -= gd->mon_len;// = 5FFB 33B4gd->relocaddr &= ~(4096 - 1);// hex 后三位与0// 5FFB 3000gd->start_addr_sp = gd->relocaddr;// 5FFB 3000reserve_mallocgd->start_addr_sp = reserve_stack_aligned((1024*1024));// 0x5feb3000reserve_board// gd->bd 不为null , 什么都不做setup_machinegd->bd->bi_arch_number = 1626;reserve_global_datagd->start_addr_sp = reserve_stack_aligned(sizeof(gd_t));// 0x5feb2f30gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));// 0x5feb2f30reserve_fdtgd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob), 32);// 0xe80gd->start_addr_sp = reserve_stack_aligned(gd->fdt_size);// 0x5feb20b0gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);// 0x5feb20b0reserve_bootstage// nullreserve_bloblist// nullreserve_arch// nullreserve_stacksgd->start_addr_sp = reserve_stack_aligned(16);// 这16个字节应该用于 irq的栈// 0x5feb20a0arch_reserve_stacksgd->irq_sp = gd->start_addr_sp;// 0x5feb20a0dram_init_banksize // 只有一个bankfor_each_bankgd->bd->bi_dram[i].start = addr;// 0x50000000gd->bd->bi_dram[i].size = (0x10000000);// 0x10000000show_dram_configfor_each_bank // 只有一个banksize += gd->bd->bi_dram[i].size;// 0x10000000print_size(size, "");// 实际打印 256 MiBboard_add_ram_info(0);nullputc('\n');setup_bdinfo// nulldisplay_new_sp// nullreloc_fdtgd->fdt_blob = gd->new_fdt;reloc_bootstage// nullreloc_bloblist// nullsetup_relocgd->reloc_off = gd->relocaddr - 0x5FB00000;// 004b4000// 该值是 u-boot的code段 搬移目标地址 与 当前地址的差值memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));clear_bss// null// 运行到此时,sp还没更改// u-boot 还没搬运// 此时,搬运了 gd和设备树// 此时 r9里面存放的还是gdldr r0, [r9, #72] // 72 是 start_addr_spbic r0, r0, #7 // 与上0b1000 , 第三位清0mov sp, r0 // 更改 spldr r9, [r9, #80] // 此时 r9 中存放的 是 new_gdadr lr, here // 存放 lr, 为  b(跳转) 做准备ldr r0, [r9, #76] // 将 new_gd 中的 reloc_off 存放到r0,用作新的lr的计算add lr, lr, r0 	 // 更改lr ,让 relocate_code 返回时,跳转到 已经 搬移好的代码 中去,ldr r0, [r9, #56] // 将 new_gd 中的 relocaddr存放到r0,作为第一个参数b relocate_code// 搬移 u-boot的 code 段arch/arm/lib/relocate.S +80搬移,修复绝对地址???// 此时已经在 搬移过后的代码 中bl relocate_vectors // TODO// arch/arm/lib/relocate.S +28ldr r0, [r9, #56] // 将 new_gd 中的 relocaddr存放到r0mcr p15, 0, r0, c12, c0, 0bl c_runtime_cpu_setup// nullCLEAR_BSS// 问题,搬移过后,__bss_start的值有变化吗?// 宏汇编// ldr r0, =__bss_start                                                            // ldr r3, =__bss_end                                                              // mov r1, #0x00000000                                                             // subs r2, r3, r0                                                                 // bl memsetbl coloured_LED_init// nullbl red_led_on// null/*// .code .rodata .data .bss .stack .heap此时的内存分布5FFF FFFF---------------------5FFF FFFFmmu(0x4000B,16KB)5FFF C000---------------------空洞(0xC000B,48KB)5FFF 0000--------------------- // 5FFF 0000 存放在 gd->arch.tlb_addr 中u-boot.bin (包括.code .data .ro-data .bss)(0x3D000B,244KB)5FFB 3000--------------------- // 5FFB 3000 存放在 new_gd->relocaddr 中malloc(0x100000B,1024KB)5FEB 3000---------------------new_gd(0xD0B,208B)5FEB 2F30--------------------- // 5FEB 2F30 存放在 r9中fdt(0xE80B,3KB)5FEB 20B0---------------------空洞(0x10,16B)5FEB 20A0--------------------- // 5FEB 20A0 存放在 start_addr_sp 中栈(254.695465MB)5000 0000---------------------*/mov r0, r9 		// 将 new_gd 的地址 存放到r0,作为第一个参数ldr r1, [r9, #56] // 将 new_gd 中的 relocaddr 存放到r1,作为第二个参数ldr pc,=board_init_rgd->flags &= ~GD_FLG_LOG_READY;// 虽然这里用的是gd,但是和用new_gd 效果一样// 因为 gd指针的值 是寄存器(r9中的值// new_gd指针的值 也是寄存器(r9)中的值initr_trace// nullinitr_relocgd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT;// 表示 code was relocated to RAM// 表示 full malloc() is readyinitr_cachesenable_cachesicache_enablecache_enable((1 << 12));reg = get_cr();set_cr(reg | cache_bit);dcache_enablecache_enable((1 << 2));if !mmu_enabled() mmu_setup();reg = get_cr();set_cr(reg | cache_bit);// 此时mmu 没有enableinitr_reloc_global_datamonitor_flash_len = _end - __image_copy_start// 计算出 monitor_flash_len// 之后用来填充 gd->bd->bi_flashoffset// reserved area for startup monitor // 不知道用来干什么的// struct bd_info 定义在 include/asm-generic/u-boot.hinitr_barrier// nullinitr_mallocmalloc_start = gd->relocaddr - (1024*1024);// = 5FEB 3000// malloc 的区域 在 5FEB 3000 - 5FFB 3000 , 有 1024KBmem_malloc_init((ulong)map_sysmem(malloc_start, (1024*1024)), (1024*1024));mem_malloc_start = start;// 5FEB 3000mem_malloc_end = start + size;// 5FFB 3000mem_malloc_brk = start;memset((void *)mem_malloc_start, 0x0, size);malloc_bin_reloc();// nulllog_init// nullinitr_bootstagebootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");initr_console_record// nullinitr_of_live// nullinitr_dmgd->dm_root_f = gd->dm_root;gd->dm_root = 0;dm_init_and_scan(0);bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_R);board_initcs8900_pre_init // 这里不是cs8900,而是dm9000a// SROM 控制器的初始化(*(vu_long *)(0x70000000 +0x0)) &= ~(0xf << 4);(*(vu_long *)(0x70000000 +0x0)) |= (1 << 7) | (1 << 6) | (1 << 4);(*(vu_long *)(0x70000000 +0x8)) = (((0x0) << 28) + ((0x4) << 24) + ((0xE) << 16) + ((0x1) << 12) + ((0x4) << 8) + ((0x6) << 4) + (0x0));// 0x7000_0000 0x700F_FFFF SROM SFRgd->bd->bi_arch_number = 1626;// CONFIG_MACH_TYPE// unique id for this board gd->bd->bi_boot_params = (0x50000000 +0x100);// where this board expects paramsinitr_binman// nullinitr_dm_devices// nullstdio_init_tablesINIT_LIST_HEAD(&devs.list);serial_initialize serial_initinitr_announce// nullpower_init_board// nullinitr_mmcputs("MMC:   ");mmc_initialize(gd->bd);initr_envenv_set_default(0,0)image_load_addr = env_get_ulong("loadaddr", 16, image_load_addr);initr_secondary_cpucpu_secondary_init_r// nullstdio_add_devicesdrv_system_initserial_stdio_initinitr_jumptablejumptable_initgd->jt = malloc(sizeof(struct jt_funcs));gd->jt->get_version = get_version;gd->jt->getc = getchar;gd->jt->tstc = tstc;gd->jt->putc = putc;gd->jt->puts = puts;gd->jt->printf = printf;gd->jt->install_hdlr = dummy;gd->jt->free_hdlr = dummy;gd->jt->malloc = malloc;gd->jt->free = free;gd->jt->udelay = udelay;gd->jt->get_timer = get_timer;gd->jt->vprintf = vprintf;gd->jt->do_reset = do_reset;gd->jt->env_get = env_get;gd->jt->env_set = env_set;gd->jt->simple_strtoul = simple_strtoul;gd->jt->strict_strtoul = strict_strtoul;gd->jt->simple_strtol = simple_strtol;gd->jt->strcmp = strcmp;gd->jt->i2c_write = dummy;gd->jt->i2c_read = dummy;gd->jt->spi_setup_slave = dummy;gd->jt->spi_free_slave = dummy;gd->jt->spi_claim_bus = dummy;gd->jt->spi_release_bus = dummy;gd->jt->spi_xfer = dummy;gd->jt->ustrtoul = ustrtoul;gd->jt->ustrtoull = ustrtoull;gd->jt->strcpy = strcpy;gd->jt->mdelay = mdelay;gd->jt->memset = memset;console_init_rgd->flags |= GD_FLG_DEVINIT;print_pre_console_buffer(flushpoint);interrupt_initIRQ_STACK_START_IN = gd->irq_sp + 8;// gd->irq_sp 上面有16字节可用// 现在IRQ_STACK_START_IN在 gd->irq_sp 上面8字节// 且arm栈向下移动// 所以irq栈应该只有8个字节可用// 此举和 之前的 relocate_vectors有关enable_interrupts// nullinitr_ethaddreth_env_get_enetaddr("ethaddr", bd->bi_enetaddr);initr_netputs("Net:   ");eth_initializerun_main_loopmain_loop

这篇关于OK6410A 开发板 (三) 12 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 boot 详细解析1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1007934

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

跨系统环境下LabVIEW程序稳定运行

在LabVIEW开发中,不同电脑的配置和操作系统(如Win11与Win7)可能对程序的稳定运行产生影响。为了确保程序在不同平台上都能正常且稳定运行,需要从兼容性、驱动、以及性能优化等多个方面入手。本文将详细介绍如何在不同系统环境下,使LabVIEW开发的程序保持稳定运行的有效策略。 LabVIEW版本兼容性 LabVIEW各版本对不同操作系统的支持存在差异。因此,在开发程序时,尽量使用

OWASP十大安全漏洞解析

OWASP(开放式Web应用程序安全项目)发布的“十大安全漏洞”列表是Web应用程序安全领域的权威指南,它总结了Web应用程序中最常见、最危险的安全隐患。以下是对OWASP十大安全漏洞的详细解析: 1. 注入漏洞(Injection) 描述:攻击者通过在应用程序的输入数据中插入恶意代码,从而控制应用程序的行为。常见的注入类型包括SQL注入、OS命令注入、LDAP注入等。 影响:可能导致数据泄

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

沁恒CH32在MounRiver Studio上环境配置以及使用详细教程

目录 1.  RISC-V简介 2.  CPU架构现状 3.  MounRiver Studio软件下载 4.  MounRiver Studio软件安装 5.  MounRiver Studio软件介绍 6.  创建工程 7.  编译代码 1.  RISC-V简介         RISC就是精简指令集计算机(Reduced Instruction SetCom