├── assets └── efifetch-vmware.png ├── efifetch ├── lib │ ├── stb_sprintf.c │ ├── init.c │ ├── ctype.c │ ├── dbg.c │ ├── failed.c │ ├── stderr.c │ ├── stdout.c │ ├── net.c │ ├── alloc.c │ ├── readable.c │ ├── printf.c │ ├── mem.c │ ├── num.c │ ├── print.c │ ├── utils.c │ ├── dump.c │ ├── encode.c │ └── str.c ├── efifetch.dec ├── include │ ├── net.h │ ├── utils.h │ ├── init.h │ ├── x86.h │ ├── regexp.h │ ├── dump.h │ ├── readable.h │ ├── efifetch.h │ ├── data.h │ ├── arm64.h │ ├── logo.h │ ├── print.h │ ├── fdt.h │ ├── libfdt_env.h │ ├── info.h │ ├── str.h │ └── libfdt_internal.h ├── data │ ├── efi_guids.c │ └── string.c ├── entry │ ├── relocate.S │ ├── start-riscv64.S │ ├── start-x86_64.S │ ├── start-aarch64.S │ ├── start-i386.S │ ├── GenericUefi.c │ ├── relocate-aarch64.c │ ├── relocate-i386.c │ ├── relocate-riscv64.c │ ├── relocate-x86_64.c │ ├── efi-x86_64.lds │ ├── efi-i386.lds │ ├── efi-riscv64.lds │ └── efi-aarch64.lds ├── libfdt │ ├── fdt_empty_tree.c │ ├── fdt_strerror.c │ ├── fdt_check.c │ ├── fdt_wip.c │ └── fdt_addresses.c ├── logo │ ├── logos.c │ ├── ami.c │ ├── kunlun.c │ ├── huawei.c │ ├── quanta.c │ ├── dell.c │ ├── phoenix.c │ ├── virtualbox.c │ ├── microsoft.c │ ├── byosoft.c │ ├── vmware.c │ ├── insyde.c │ ├── hp.c │ ├── lenovo.c │ ├── uefi.c │ ├── tianocore.c │ ├── apple.c │ ├── qcom.c │ ├── parsec.c │ ├── uboot.c │ └── logo.c ├── info │ ├── fdt.c │ ├── sys.c │ ├── mem.c │ ├── fs.c │ ├── cpuid.c │ ├── time.c │ ├── gpu.c │ ├── info.c │ ├── net.c │ ├── smbios.c │ ├── smbios_base.c │ └── disk.c ├── efifetch.dsc ├── efifetch.inf ├── objs.mk └── main.c ├── .gitignore ├── scripts ├── qemu.sh └── gpu-list.py ├── .github └── workflows │ └── ci.yml ├── README.md └── Makefile /assets/efifetch-vmware.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigfootACA/efifetch/HEAD/assets/efifetch-vmware.png -------------------------------------------------------------------------------- /efifetch/lib/stb_sprintf.c: -------------------------------------------------------------------------------- 1 | #define STB_SPRINTF_IMPLEMENTATION 2 | #define STB_SPRINTF_NOFLOAT 3 | #include"efi.h" 4 | #include"str.h" 5 | #include"stb_sprintf.h" 6 | -------------------------------------------------------------------------------- /efifetch/efifetch.dec: -------------------------------------------------------------------------------- 1 | [Defines] 2 | DEC_SPECIFICATION = 0x00010005 3 | PACKAGE_NAME = efifetch 4 | PACKAGE_VERSION = 0.01 5 | 6 | [Includes] 7 | include 8 | -------------------------------------------------------------------------------- /efifetch/include/net.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_H 2 | #define NET_H 3 | #include"efi.h" 4 | extern int ipv4_to_string(efi_ipv4_address*ip,char*buff,size_t len); 5 | extern int ipv4_to_prefix(efi_ipv4_address*msk); 6 | extern int ipv6_to_string(efi_ipv6_address*ip,char*buff,size_t len); 7 | #endif 8 | -------------------------------------------------------------------------------- /efifetch/data/efi_guids.c: -------------------------------------------------------------------------------- 1 | #include"data.h" 2 | #define DECL_GUID(name,guid...) __unused __weak efi_guid name=guid; 3 | #include"guids.h" 4 | #undef DECL_GUID 5 | __unused __weak const struct efi_guid_item efi_guid_table[]={ 6 | #define DECL_GUID(_name,_guid...) {.guid=&_name,.name=#_name}, 7 | #include"guids.h" 8 | #undef DECL_GUID 9 | {NULL,NULL} 10 | }; 11 | -------------------------------------------------------------------------------- /efifetch/entry/relocate.S: -------------------------------------------------------------------------------- 1 | .data 2 | dummy0: .4byte 0 3 | dummy1: .4byte 0 4 | 5 | #define IMAGE_REL_ABSOLUTE 0 6 | .section .reloc, "a", %progbits 7 | .4byte dummy1 - dummy0 8 | .4byte 12 9 | .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 10 | .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 11 | #if defined(__ELF__) && defined(__linux__) 12 | .section .note.GNU-stack,"",%progbits 13 | #endif 14 | -------------------------------------------------------------------------------- /efifetch/lib/init.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"init.h" 3 | #include"print.h" 4 | 5 | efi_handle g_ih=NULL; 6 | efi_system_table*g_st=NULL; 7 | efi_boot_services*g_bs=NULL; 8 | efi_runtime_services*g_rt=NULL; 9 | 10 | void efiapi initialize(efi_handle ih,efi_system_table*st){ 11 | g_ih=ih,g_st=st; 12 | if(st){ 13 | g_bs=st->boot_services, 14 | g_rt=st->runtime_services; 15 | } 16 | print_init(); 17 | } 18 | -------------------------------------------------------------------------------- /efifetch/entry/start-riscv64.S: -------------------------------------------------------------------------------- 1 | .text 2 | .globl _start 3 | .type _start,%function 4 | _start: 5 | addi sp, sp, -24 6 | sd a0, 0(sp) 7 | sd a1, 8(sp) 8 | sd ra, 16(sp) 9 | lla a0, ImageBase 10 | lla a1, _DYNAMIC 11 | call relocate 12 | bne a0, zero, .L_exit 13 | ld a1, 8(sp) 14 | ld a0, 0(sp) 15 | call initialize 16 | ld a1, 8(sp) 17 | ld a0, 0(sp) 18 | call uefi_main 19 | ld ra, 16(sp) 20 | .L_exit: 21 | addi sp, sp, 24 22 | ret 23 | -------------------------------------------------------------------------------- /efifetch/entry/start-x86_64.S: -------------------------------------------------------------------------------- 1 | .text 2 | .align 4 3 | .globl _start 4 | .type _start,%function 5 | _start: 6 | subq $24, %rsp 7 | movq %rcx, 16(%rsp) 8 | movq %rdx, 8(%rsp) 9 | lea ImageBase(%rip), %rdi 10 | lea _DYNAMIC(%rip), %rsi 11 | call relocate 12 | movq 16(%rsp), %rcx 13 | movq 8(%rsp), %rdx 14 | call initialize 15 | movq 16(%rsp), %rcx 16 | movq 8(%rsp), %rdx 17 | call uefi_main 18 | addq $24, %rsp 19 | .L_exit: 20 | ret 21 | -------------------------------------------------------------------------------- /efifetch/entry/start-aarch64.S: -------------------------------------------------------------------------------- 1 | .text 2 | .align 12 3 | .globl _start 4 | .type _start,%function 5 | 6 | _start: 7 | stp x29, x30, [sp, #-32]! 8 | mov x29, sp 9 | stp x0, x1, [sp, #16] 10 | adr x0, ImageBase 11 | adrp x1, _DYNAMIC 12 | add x1, x1, #:lo12:_DYNAMIC 13 | bl relocate 14 | cbnz x0, .L_exit 15 | ldp x0, x1, [sp, #16] 16 | bl initialize 17 | ldp x0, x1, [sp, #16] 18 | bl uefi_main 19 | .L_exit: 20 | ldp x29, x30, [sp], #32 21 | ret 22 | -------------------------------------------------------------------------------- /efifetch/include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | #include"efi.h" 4 | extern efi_handle efi_get_parent_device(efi_handle handle); 5 | extern efi_loaded_image_protocol*efi_get_loaded_image(void); 6 | extern efi_handle efi_get_current_device(void); 7 | extern void*efi_file_get_info_by(efi_file_protocol*f,const efi_guid*guid); 8 | extern efi_file_system_info*efi_get_fs_info(efi_simple_file_system_protocol*fs); 9 | extern efi_simple_file_system_protocol*efi_get_current_fs(void); 10 | #endif 11 | -------------------------------------------------------------------------------- /efifetch/lib/ctype.c: -------------------------------------------------------------------------------- 1 | #include"str.h" 2 | 3 | __weak int isspace(int c){return c==' '||(unsigned)c-'\t'<5;} 4 | __weak int isalpha(int c){return ((unsigned)c|32)-'a'<26;} 5 | __weak int islower(int c){return (unsigned)c-'a'<26;} 6 | __weak int isupper(int c){return (unsigned)c-'A'<26;} 7 | __weak int tolower(int c){return (isupper(c))?(c|32):c;} 8 | __weak int toupper(int c){return (islower(c))?(c&0x5f):c;} 9 | __weak int isdigit(int c){return (unsigned)c-'0'<10;} 10 | __weak int isprint(int c){return (unsigned)c-' '<0x5f;} -------------------------------------------------------------------------------- /efifetch/include/init.h: -------------------------------------------------------------------------------- 1 | #ifndef INIT_H 2 | #define INIT_H 3 | #include"efi.h" 4 | extern efi_handle g_ih; 5 | extern efi_system_table*g_st; 6 | extern efi_boot_services*g_bs; 7 | extern efi_runtime_services*g_rt; 8 | #ifdef stdin 9 | #undef stdin 10 | #endif 11 | #ifdef stdout 12 | #undef stdout 13 | #endif 14 | #ifdef stderr 15 | #undef stderr 16 | #endif 17 | #define stdin (g_st?g_st->con_stdin:NULL) 18 | #define stdout (g_st?g_st->con_stdout:NULL) 19 | #define stderr (g_st?g_st->con_stderr:NULL) 20 | extern void efiapi initialize(efi_handle ih,efi_system_table*st); 21 | #endif 22 | -------------------------------------------------------------------------------- /efifetch/include/x86.h: -------------------------------------------------------------------------------- 1 | #ifndef X86_H 2 | #define X86_H 3 | #include"efi.h" 4 | typedef union eflags_data eflags_data; 5 | union eflags_data{ 6 | struct{ 7 | bool CF:1; 8 | uint8_t:1; 9 | bool PF:1; 10 | uint8_t:1; 11 | bool AF:1; 12 | uint8_t:1; 13 | bool ZF:1; 14 | bool SF:1; 15 | bool TF:1; 16 | bool IF:1; 17 | bool DF:1; 18 | bool OF:1; 19 | bool IOPL:2; 20 | bool NT:1; 21 | uint8_t:1; 22 | bool RF:1; 23 | bool VM:1; 24 | bool AC:1; 25 | bool VIF:1; 26 | bool VIP:1; 27 | bool ID:1; 28 | uint16_t:10; 29 | }__packed; 30 | uint32_t value; 31 | }__packed; 32 | #endif 33 | -------------------------------------------------------------------------------- /efifetch/entry/start-i386.S: -------------------------------------------------------------------------------- 1 | .text 2 | .align 4 3 | .globl _start 4 | .type _start,%function 5 | _start: 6 | pushl %ebp 7 | movl %esp,%ebp 8 | pushl %esi 9 | pushl %edi 10 | movl 8(%ebp),%esi 11 | movl 12(%ebp),%edi 12 | call 0f 13 | 0: popl %eax 14 | movl %eax,%ebx 15 | addl $ImageBase-0b,%eax 16 | addl $_DYNAMIC-0b,%ebx 17 | pushl %ebx 18 | pushl %eax 19 | call relocate 20 | addl $8,%esp 21 | testl %eax,%eax 22 | jne .L_exit 23 | pushl %edi 24 | pushl %esi 25 | call initialize 26 | addl $8,%esp 27 | pushl %edi 28 | pushl %esi 29 | call uefi_main 30 | addl $8,%esp 31 | .L_exit: 32 | popl %edi 33 | popl %esi 34 | leave 35 | ret 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.rej 2 | *.orig 3 | *.swp 4 | *.save* 5 | *.o 6 | *.a 7 | *.out 8 | *.lib 9 | *.obj 10 | *.dll 11 | *.so 12 | *.exe 13 | *.gch 14 | *.plist 15 | *.mo 16 | *.gmo 17 | *.fd 18 | *.iso 19 | *.img 20 | *.img.* 21 | *.qcow2 22 | *.vhd 23 | *.vdi 24 | *.vmdk 25 | *.cpio 26 | *.cpio.* 27 | *.ttf 28 | *.ttc 29 | *.pcf 30 | *.pcf.* 31 | *.efi 32 | vgcore.* 33 | /build* 34 | /busybox 35 | initramfs*.* 36 | initrd*.* 37 | System.map* 38 | /cmake-build-* 39 | /.idea 40 | /.vscode 41 | /.cache 42 | CMakeCache.txt 43 | CMakeFiles 44 | cmake_install.cmake 45 | node_modules 46 | package.json 47 | package-lock.json 48 | fonts.scale 49 | fonts.dir 50 | compile_commands.json 51 | __pycache__ 52 | /Build 53 | /edk2 54 | 55 | -------------------------------------------------------------------------------- /efifetch/include/regexp.h: -------------------------------------------------------------------------------- 1 | #ifndef regexp_h 2 | #define regexp_h 3 | 4 | typedef struct Reprog Reprog; 5 | typedef struct Resub Resub; 6 | 7 | extern Reprog *regexp_comp(const char *pattern, int cflags, const char **errorp); 8 | extern int regexp_exec(Reprog *prog, const char *string, Resub *sub, int eflags); 9 | extern void regexp_free(Reprog *prog); 10 | extern int regexp_match(const char *regex, const char *str, int flags); 11 | 12 | enum { 13 | /* regexp_comp flags */ 14 | REG_ICASE = 1, 15 | REG_NEWLINE = 2, 16 | 17 | /* regexp_exec flags */ 18 | REG_NOTBOL = 4, 19 | 20 | /* limits */ 21 | REG_MAXSUB = 10 22 | }; 23 | 24 | struct Resub { 25 | unsigned int nsub; 26 | struct { 27 | const char *sp; 28 | const char *ep; 29 | } sub[REG_MAXSUB]; 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /efifetch/entry/GenericUefi.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"init.h" 3 | 4 | extern efi_status efiapi uefi_main( 5 | efi_handle image_handle, 6 | efi_system_table*system_table 7 | ); 8 | 9 | static_assert(sizeof(efi_status) == sizeof(EFI_STATUS), "efi_status mismatch"); 10 | static_assert(sizeof(efi_handle) == sizeof(EFI_HANDLE), "efi_handle mismatch"); 11 | static_assert(sizeof(efi_system_table) == sizeof(EFI_SYSTEM_TABLE), "efi_system_table mismatch"); 12 | 13 | EFI_STATUS EFIAPI UefiMain( 14 | IN EFI_HANDLE ImageHandle, 15 | IN EFI_SYSTEM_TABLE *SystemTable 16 | ){ 17 | initialize( 18 | (efi_handle)ImageHandle, 19 | (efi_system_table*)SystemTable 20 | ); 21 | return (efi_status)uefi_main( 22 | (efi_handle)ImageHandle, 23 | (efi_system_table*)SystemTable 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /efifetch/include/dump.h: -------------------------------------------------------------------------------- 1 | #ifndef DUMP_H 2 | #define DUMP_H 3 | #include"efi.h" 4 | typedef struct mem_dump mem_dump; 5 | struct mem_dump{ 6 | uint8_t step; 7 | uint8_t addr_len; 8 | bool show_header; 9 | bool print_ascii; 10 | bool real_address; 11 | bool buffered; 12 | const char**table; 13 | void*data; 14 | char*buffer; 15 | size_t buf_size,buf_pos; 16 | int(*printf)(mem_dump*d,const char*fmt,...); 17 | int(*putchar)(mem_dump*d,char ch); 18 | int(*print)(mem_dump*d,const char*str); 19 | int(*write)(mem_dump*d,const char*str,size_t len); 20 | void(*finish)(mem_dump*d); 21 | }; 22 | extern const char*unicode_fat_table_char[]; 23 | extern const char*unicode_table_char[]; 24 | extern const char*ascii_table_char[]; 25 | extern mem_dump mem_dump_def; 26 | extern void mem_dump_with(void*addr,size_t len,mem_dump*dump); 27 | #endif 28 | -------------------------------------------------------------------------------- /efifetch/libfdt/fdt_empty_tree.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2012 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include "fdt.h" 9 | #include "libfdt.h" 10 | 11 | #include "libfdt_internal.h" 12 | 13 | int fdt_create_empty_tree(void *buf, int bufsize) 14 | { 15 | int err; 16 | 17 | err = fdt_create(buf, bufsize); 18 | if (err) 19 | return err; 20 | 21 | err = fdt_finish_reservemap(buf); 22 | if (err) 23 | return err; 24 | 25 | err = fdt_begin_node(buf, ""); 26 | if (err) 27 | return err; 28 | 29 | err = fdt_end_node(buf); 30 | if (err) 31 | return err; 32 | 33 | err = fdt_finish(buf); 34 | if (err) 35 | return err; 36 | 37 | return fdt_open_into(buf, buf, bufsize); 38 | } 39 | -------------------------------------------------------------------------------- /efifetch/include/readable.h: -------------------------------------------------------------------------------- 1 | #ifndef READABLE_H 2 | #define READABLE_H 3 | #include"efi.h" 4 | extern const char*size_units_b[]; 5 | extern const char*size_units_ib[]; 6 | extern const char*size_units_ibs[]; 7 | extern const char*size_units_hz[]; 8 | extern const char*format_size_ex(char*buf,size_t len,uint64_t val,const char**units,size_t blk); 9 | extern const char*format_size_float_ex(char*buf,size_t len,uint64_t val,const char**units,size_t blk,uint8_t dot); 10 | #define format_size(buf,val) format_size_ex(buf,sizeof(buf),val,size_units_ib,1024) 11 | #define format_size_hz(buf,val) format_size_ex(buf,sizeof(buf),val,size_units_hz,1000) 12 | #define format_size_float(buf,val) format_size_float_ex(buf,sizeof(buf),val,size_units_ib,1024,2) 13 | #define format_size_float_hz(buf,val) format_size_float_ex(buf,sizeof(buf),val,size_units_hz,1000,2) 14 | #endif 15 | -------------------------------------------------------------------------------- /efifetch/lib/dbg.c: -------------------------------------------------------------------------------- 1 | #define STB_SPRINTF_NOFLOAT 2 | #include"efi.h" 3 | #include"print.h" 4 | #include"stb_sprintf.h" 5 | 6 | efi_simple_text_output_protocol*debug_output=NULL; 7 | 8 | efi_status dbg_printf(const char*str,...){ 9 | va_list va; 10 | if(!debug_output)return efi_success; 11 | va_start(va,str); 12 | efi_status st=text_vprintf(debug_output,str,va); 13 | va_end(va); 14 | return st; 15 | } 16 | 17 | efi_status dbg_vprintf(const char*str,va_list va){ 18 | if(!debug_output)return efi_success; 19 | return text_vprintf(debug_output,str,va); 20 | } 21 | 22 | efi_status dbg_print(const char*str){ 23 | if(!debug_output)return efi_success; 24 | return text_print(debug_output,str); 25 | } 26 | 27 | efi_status dbg_printn(const char*str,size_t len){ 28 | if(!debug_output)return efi_success; 29 | return text_printn(debug_output,str,len); 30 | } 31 | -------------------------------------------------------------------------------- /efifetch/entry/relocate-aarch64.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"elf.h" 3 | 4 | efi_status relocate(uintn_t b,Elf64_Dyn*d){ 5 | intn_t relsz=0,relent=0; 6 | Elf64_Rela *rel=NULL; 7 | uintn_t*addr; 8 | int i; 9 | for(i=0;d[i].d_tag!=DT_NULL;++i)switch(d[i].d_tag){ 10 | case DT_RELA:rel=(Elf64_Rela*)((uintn_t)d[i].d_un.d_ptr+b);break; 11 | case DT_RELASZ:relsz=d[i].d_un.d_val;break; 12 | case DT_RELAENT:relent=d[i].d_un.d_val;break; 13 | default:break; 14 | } 15 | if(!rel&&relent==0)return EFI_SUCCESS; 16 | if(!rel||relent==0)return EFI_LOAD_ERROR; 17 | while(relsz>0){ 18 | switch(ELF64_R_TYPE(rel->r_info)){ 19 | case R_AARCH64_NONE:break; 20 | case R_AARCH64_RELATIVE: 21 | addr=(uintn_t*)(b+rel->r_offset); 22 | *addr=b+rel->r_addend; 23 | break; 24 | default:break; 25 | } 26 | rel=(Elf64_Rela*)((char*)rel+relent); 27 | relsz-=relent; 28 | } 29 | return EFI_SUCCESS; 30 | } 31 | -------------------------------------------------------------------------------- /efifetch/entry/relocate-i386.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"elf.h" 3 | 4 | efi_status relocate(uintn_t b,Elf32_Dyn*d){ 5 | intn_t relsz=0,relent=0; 6 | Elf32_Rel*rel=NULL; 7 | uintn_t*addr; 8 | int i; 9 | for(i=0;d[i].d_tag!=DT_NULL;++i)switch(d[i].d_tag){ 10 | case DT_REL:rel=(Elf32_Rel*)((uintn_t)d[i].d_un.d_ptr+b);break; 11 | case DT_RELSZ:relsz=d[i].d_un.d_val;break; 12 | case DT_RELENT:relent=d[i].d_un.d_val;break; 13 | case DT_RELA:break; 14 | default:break; 15 | } 16 | if(!rel&&relent==0)return EFI_SUCCESS; 17 | if(!rel||relent==0)return EFI_LOAD_ERROR; 18 | while(relsz>0){ 19 | switch(ELF32_R_TYPE(rel->r_info)){ 20 | case R_386_NONE:break; 21 | case R_386_RELATIVE: 22 | addr=(uintn_t*)(b+rel->r_offset); 23 | *addr+=b; 24 | break; 25 | default:break; 26 | } 27 | rel=(Elf32_Rel*)((char*)rel+relent); 28 | relsz-=relent; 29 | } 30 | return EFI_SUCCESS; 31 | } 32 | -------------------------------------------------------------------------------- /efifetch/entry/relocate-riscv64.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"elf.h" 3 | 4 | efi_status relocate(uintn_t b,Elf64_Dyn*d){ 5 | intn_t relsz=0,relent=0; 6 | Elf64_Rela *rel=NULL; 7 | uintn_t*addr; 8 | int i; 9 | for(i=0;d[i].d_tag!=DT_NULL;++i)switch(d[i].d_tag){ 10 | case DT_RELA:rel=(Elf64_Rela*)((uintn_t)d[i].d_un.d_ptr+b);break; 11 | case DT_RELASZ:relsz=d[i].d_un.d_val;break; 12 | case DT_RELAENT:relent=d[i].d_un.d_val;break; 13 | default:break; 14 | } 15 | if(!rel&&relent==0)return EFI_SUCCESS; 16 | if(!rel||relent==0)return EFI_LOAD_ERROR; 17 | while(relsz>0){ 18 | switch(ELF64_R_TYPE(rel->r_info)){ 19 | case R_RISCV_NONE:break; 20 | case R_RISCV_RELATIVE: 21 | addr=(uintn_t*)(b+rel->r_offset); 22 | *addr=b+rel->r_addend; 23 | break; 24 | default:break; 25 | } 26 | rel=(Elf64_Rela*)((char*)rel+relent); 27 | relsz-=relent; 28 | } 29 | return EFI_SUCCESS; 30 | } 31 | -------------------------------------------------------------------------------- /efifetch/entry/relocate-x86_64.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"elf.h" 3 | 4 | efi_status relocate(uintn_t b,Elf64_Dyn*d){ 5 | intn_t relsz=0,relent=0; 6 | Elf64_Rela *rel=NULL; 7 | uintn_t*addr; 8 | int i; 9 | for(i=0;d[i].d_tag!=DT_NULL;++i)switch(d[i].d_tag){ 10 | case DT_RELA:rel=(Elf64_Rela*)((uintn_t)d[i].d_un.d_ptr+b);break; 11 | case DT_RELASZ:relsz=d[i].d_un.d_val;break; 12 | case DT_RELAENT:relent=d[i].d_un.d_val;break; 13 | default:break; 14 | } 15 | if(!rel&&relent==0)return EFI_SUCCESS; 16 | if(!rel||relent==0)return EFI_LOAD_ERROR; 17 | while(relsz>0){ 18 | switch(ELF64_R_TYPE(rel->r_info)){ 19 | case R_X86_64_NONE:break; 20 | case R_X86_64_RELATIVE: 21 | addr=(uintn_t*)(b+rel->r_offset); 22 | *addr=b+rel->r_addend; 23 | break; 24 | default:break; 25 | } 26 | rel=(Elf64_Rela*)((char*)rel+relent); 27 | relsz-=relent; 28 | } 29 | return EFI_SUCCESS; 30 | } 31 | -------------------------------------------------------------------------------- /efifetch/lib/failed.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"init.h" 3 | #include"print.h" 4 | 5 | #if __SIZEOF_POINTER__==8 6 | void*__stack_chk_guard=(void*)(uintptr_t)0xDEADBEEFDEADFEED; 7 | #elif __SIZEOF_POINTER__==4 8 | void*__stack_chk_guard=(void*)(uintptr_t)0xDEADBEEF; 9 | #else 10 | #error unknown pointer size 11 | #endif 12 | 13 | __attribute__((noreturn)) 14 | void abort(void){ 15 | if(g_bs)g_bs->exit(g_ih,EFI_ABORTED,0,NULL); 16 | while(1); 17 | } 18 | 19 | __attribute__((noreturn)) 20 | void __assert_fail(const char*expr,const char*file,int line,const char*func){ 21 | err_printf("assert failed at %s:%d: %s: %s\n",file,line,func,expr); 22 | abort(); 23 | } 24 | 25 | __attribute__((noreturn)) 26 | void __stack_chk_fail(void){ 27 | if(g_st)g_st->con_stderr->output_string( 28 | g_st->con_stderr, 29 | L"stack smashing detected\n" 30 | ); 31 | abort(); 32 | } 33 | 34 | __attribute__((noreturn)) 35 | void __stack_chk_fail_local(void){ 36 | __stack_chk_fail(); 37 | } 38 | -------------------------------------------------------------------------------- /efifetch/include/efifetch.h: -------------------------------------------------------------------------------- 1 | #ifndef EFIFETCH_H 2 | #define EFIFETCH_H 3 | #include"efi.h" 4 | #include"logo.h" 5 | #include"smbios.h" 6 | enum efifetch_field{ 7 | EFIFETCH_FIELD_MIN=0, 8 | EFIFETCH_FIELD_NAME=0, 9 | EFIFETCH_FIELD_FIRMWARE, 10 | EFIFETCH_FIELD_HOST, 11 | EFIFETCH_FIELD_SPEC, 12 | EFIFETCH_FIELD_UPTIME, 13 | EFIFETCH_FIELD_DISPLAY, 14 | EFIFETCH_FIELD_ARCH, 15 | EFIFETCH_FIELD_CPUID, 16 | EFIFETCH_FIELD_CPU, 17 | EFIFETCH_FIELD_GPU, 18 | EFIFETCH_FIELD_MEMORY, 19 | EFIFETCH_FIELD_FILESYSTEM, 20 | EFIFETCH_FIELD_DISK, 21 | EFIFETCH_FIELD_IP4, 22 | EFIFETCH_FIELD_IP6, 23 | EFIFETCH_FIELD_SECURE_BOOT, 24 | EFIFETCH_FIELD_MAX, 25 | 26 | }; 27 | typedef struct efifetch{ 28 | logo_context logo; 29 | void*fdt; 30 | smbios_table2_entry_point*smbios2; 31 | smbios_table3_entry_point*smbios3; 32 | struct{ 33 | char value[80]; 34 | }fields[EFIFETCH_FIELD_MAX]; 35 | }efifetch; 36 | extern void efifetch_load_info(efifetch*ctx); 37 | extern void efifetch_print_all(efifetch*ctx); 38 | extern void efifetch_print_field(efifetch*ctx,enum efifetch_field field); 39 | #endif 40 | -------------------------------------------------------------------------------- /efifetch/lib/stderr.c: -------------------------------------------------------------------------------- 1 | #define STB_SPRINTF_NOFLOAT 2 | #include"efi.h" 3 | #include"init.h" 4 | #include"print.h" 5 | #include"stb_sprintf.h" 6 | 7 | uintn_t con_stderr_def_attr=EFI_WHITE|EFI_BACKGROUND_BLACK; 8 | 9 | efi_status err_printf(const char*str,...){ 10 | va_list va; 11 | if(!stderr)return efi_device_error; 12 | va_start(va,str); 13 | efi_status st=text_vprintf(stderr,str,va); 14 | va_end(va); 15 | return st; 16 | } 17 | 18 | efi_status err_vprintf(const char*str,va_list va){ 19 | if(!stderr)return efi_device_error; 20 | return text_vprintf(stderr,str,va); 21 | } 22 | 23 | efi_status err_print(const char*str){ 24 | if(!stderr)return efi_device_error; 25 | return text_print(stderr,str); 26 | } 27 | 28 | efi_status err_printn(const char*str,size_t len){ 29 | if(!stderr)return efi_device_error; 30 | return text_printn(stderr,str,len); 31 | } 32 | 33 | efi_status err_setattr(uintn_t attr){ 34 | if(!stderr)return efi_device_error; 35 | return stderr->set_attribute(stderr,attr); 36 | } 37 | 38 | efi_status err_resetattr(void){ 39 | return err_setattr(con_stderr_def_attr); 40 | } 41 | -------------------------------------------------------------------------------- /efifetch/lib/stdout.c: -------------------------------------------------------------------------------- 1 | #define STB_SPRINTF_NOFLOAT 2 | #include"efi.h" 3 | #include"init.h" 4 | #include"print.h" 5 | #include"stb_sprintf.h" 6 | 7 | uintn_t con_stdout_def_attr=EFI_WHITE|EFI_BACKGROUND_BLACK; 8 | 9 | efi_status out_printf(const char*str,...){ 10 | va_list va; 11 | if(!stdout)return efi_device_error; 12 | va_start(va,str); 13 | efi_status st=text_vprintf(stdout,str,va); 14 | va_end(va); 15 | return st; 16 | } 17 | 18 | efi_status out_vprintf(const char*str,va_list va){ 19 | if(!stdout)return efi_device_error; 20 | return text_vprintf(stdout,str,va); 21 | } 22 | 23 | efi_status out_print(const char*str){ 24 | if(!stdout)return efi_device_error; 25 | return text_print(stdout,str); 26 | } 27 | 28 | efi_status out_printn(const char*str,size_t len){ 29 | if(!stdout)return efi_device_error; 30 | return text_printn(stdout,str,len); 31 | } 32 | 33 | efi_status out_setattr(uintn_t attr){ 34 | if(!stdout)return efi_device_error; 35 | return stdout->set_attribute(stdout,attr); 36 | } 37 | 38 | efi_status out_resetattr(void){ 39 | return out_setattr(con_stdout_def_attr); 40 | } 41 | -------------------------------------------------------------------------------- /efifetch/logo/logos.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | extern logo_desc logo_ami; 4 | extern logo_desc logo_apple; 5 | extern logo_desc logo_byosoft; 6 | extern logo_desc logo_dell; 7 | extern logo_desc logo_hp; 8 | extern logo_desc logo_huawei; 9 | extern logo_desc logo_insyde; 10 | extern logo_desc logo_kunlun; 11 | extern logo_desc logo_lenovo; 12 | extern logo_desc logo_microsoft; 13 | extern logo_desc logo_parsec; 14 | extern logo_desc logo_phoenix; 15 | extern logo_desc logo_qualcomm; 16 | extern logo_desc logo_quanta; 17 | extern logo_desc logo_virtualbox; 18 | extern logo_desc logo_vmware; 19 | extern logo_desc logo_tianocore; 20 | extern logo_desc logo_uboot; 21 | extern logo_desc logo_uefi; 22 | logo_desc*logos[]={ 23 | &logo_ami, 24 | &logo_apple, 25 | &logo_byosoft, 26 | &logo_dell, 27 | &logo_hp, 28 | &logo_huawei, 29 | &logo_insyde, 30 | &logo_kunlun, 31 | &logo_lenovo, 32 | &logo_microsoft, 33 | &logo_parsec, 34 | &logo_phoenix, 35 | &logo_qualcomm, 36 | &logo_quanta, 37 | &logo_virtualbox, 38 | &logo_vmware, 39 | &logo_tianocore, 40 | &logo_uboot, 41 | &logo_uefi, 42 | NULL, 43 | }; 44 | -------------------------------------------------------------------------------- /efifetch/include/data.h: -------------------------------------------------------------------------------- 1 | #ifndef DATA_H 2 | #define DATA_H 3 | #include"efi.h" 4 | struct efi_guid_item{ 5 | const efi_guid*guid; 6 | const char*name; 7 | }; 8 | extern const struct efi_guid_item efi_guid_table[]; 9 | typedef struct arm_cpuid_item{ 10 | uint8_t implementer; 11 | uint16_t part; 12 | const char*name; 13 | }arm_cpuid_item; 14 | extern const arm_cpuid_item arm_cpuid_items[]; 15 | #define DECL_CPUID_ARM_START const arm_cpuid_item arm_cpuid_items[]={ 16 | #define DECL_CPUID_ARM_END {0,0,NULL}}; 17 | #define DECL_CPUID_ARM_PART(_imp,_part,_name) \ 18 | {.implementer=_imp,.part=_part,.name=_name}, 19 | #define DECL_CPUID_ARM_IMPL(_imp,_name) \ 20 | DECL_CPUID_ARM_PART(_imp,0xFFFF,_name) 21 | typedef struct gpu_item{ 22 | uint16_t vendor; 23 | uint16_t device; 24 | const char*name; 25 | }gpu_item; 26 | extern const gpu_item gpu_db[]; 27 | #define GPU_DB_START const gpu_item gpu_db[]={ 28 | #define GPU_DB_END {0,0,NULL}}; 29 | #define GPU_DB_ITEM(_vendor,_device,_name) {.vendor=(_vendor),.device=(_device),.name=(_name)}, 30 | #define GPU_DB_VENDOR(_vendor,_name) GPU_DB_ITEM(_vendor,0xFFFF,_name) 31 | #endif 32 | -------------------------------------------------------------------------------- /efifetch/info/fdt.c: -------------------------------------------------------------------------------- 1 | #include"info.h" 2 | #include"init.h" 3 | #include"libfdt.h" 4 | #include"print.h" 5 | 6 | extern efi_guid gFdtTableGuid; 7 | 8 | void efifetch_init_info_fdt(efifetch*ctx){ 9 | int r; 10 | void*fdt=NULL; 11 | ctx->fdt=NULL; 12 | for(uintn_t i=0;ientries;i++){ 13 | if(memcmp(&g_st->cfg_table[i].guid,&gFdtTableGuid,sizeof(efi_guid))==0){ 14 | dbg_printf("found fdt cfg table %p\n",fdt); 15 | fdt=g_st->cfg_table[i].table; 16 | } 17 | } 18 | if(!fdt){ 19 | dbg_print("fdt not found\n"); 20 | return; 21 | } 22 | if((r=fdt_check_header(fdt))){ 23 | dbg_printf( 24 | "fdt check header failed: %s\n", 25 | fdt_strerror(r) 26 | ); 27 | return; 28 | } 29 | ctx->fdt=fdt; 30 | } 31 | 32 | void efifetch_load_info_fdt(efifetch*ctx){ 33 | int len=0; 34 | const char*data; 35 | if(!ctx->fdt)return; 36 | int root=fdt_path_offset(ctx->fdt,"/"); 37 | if(root<0)return; 38 | if(IS_EMPTY(HOST)&&(data=fdt_getprop(ctx->fdt,root,"model",&len))) 39 | SETN(HOST,data,len); 40 | if(IS_EMPTY(NAME)&&(data=fdt_getprop(ctx->fdt,root,"compatible",&len))) 41 | SETN(NAME,data,len); 42 | } 43 | -------------------------------------------------------------------------------- /efifetch/include/arm64.h: -------------------------------------------------------------------------------- 1 | #ifndef ARM64_H 2 | #define ARM64_H 3 | #include"efi.h" 4 | typedef enum current_el_val current_el_val; 5 | typedef union current_el_data current_el_data; 6 | enum current_el_val{ 7 | CURR_EL0 = 0, 8 | CURR_EL1 = 1, 9 | CURR_EL2 = 2, 10 | CURR_EL3 = 3, 11 | }; 12 | union current_el_data{ 13 | struct{ 14 | uint64_t:2; 15 | current_el_val EL:2; 16 | uint64_t:60; 17 | }__packed; 18 | uint64_t value; 19 | }__packed; 20 | typedef enum mpidr_u mpidr_u; 21 | typedef union mpidr_data mpidr_data; 22 | enum mpidr_u{ 23 | MPIDR_MP=0, 24 | MPIDR_UP=1, 25 | }; 26 | union mpidr_data{ 27 | struct{ 28 | uint8_t AFF0; 29 | uint8_t AFF1; 30 | uint8_t AFF2; 31 | bool MT:1; 32 | uint8_t:5; 33 | mpidr_u U:1; 34 | uint8_t:1; 35 | uint8_t AFF3; 36 | uint32_t:24; 37 | }__packed; 38 | uint64_t value; 39 | }__packed; 40 | typedef union midr_data midr_data; 41 | union midr_data{ 42 | struct{ 43 | uint8_t Revision:4; 44 | uint16_t PartNum:12; 45 | uint8_t Arch:4; 46 | uint8_t Variant:4; 47 | uint8_t Implementer; 48 | uint32_t:32; 49 | }__packed; 50 | uint64_t value; 51 | }__packed; 52 | #endif 53 | -------------------------------------------------------------------------------- /efifetch/include/logo.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGO_H 2 | #define LOGO_H 3 | #include"efi.h" 4 | 5 | typedef struct attr_map{ 6 | char ch; 7 | uintn_t attr; 8 | }attr_map; 9 | 10 | typedef struct logo_desc{ 11 | uintn_t main_color; 12 | uintn_t width; 13 | const char*const*lines; 14 | uintn_t lines_count; 15 | attr_map*attr_map; 16 | uintn_t attr_map_count; 17 | const char*const*matchs; 18 | }logo_desc; 19 | 20 | typedef struct logo_context{ 21 | efi_simple_text_output_protocol*con; 22 | logo_desc*target_logo; 23 | uintn_t cur_line; 24 | int margin; 25 | }logo_context; 26 | 27 | extern logo_desc*logos[]; 28 | extern logo_desc logo_uefi; 29 | 30 | extern efi_status logo_desc_print(efi_simple_text_output_protocol*con,logo_desc*logo); 31 | extern efi_status logo_desc_print_line(efi_simple_text_output_protocol*con,logo_desc*logo,uintn_t line); 32 | extern efi_status logo_ctx_init(logo_context*ctx,efi_simple_text_output_protocol*con,logo_desc*logo,uintn_t margin); 33 | extern efi_status logo_ctx_print_line(logo_context*ctx); 34 | extern efi_status logo_ctx_print_line(logo_context*ctx); 35 | extern efi_status logo_ctx_print_remain(logo_context*ctx); 36 | extern logo_desc*logo_find(const char*name); 37 | #endif 38 | -------------------------------------------------------------------------------- /efifetch/efifetch.dsc: -------------------------------------------------------------------------------- 1 | [Defines] 2 | PLATFORM_NAME = efifetch 3 | PLATFORM_GUID = 8CBCE486-F3C9-449F-8DE0-BEDA10385C6A 4 | PLATFORM_VERSION = 1.02 5 | DSC_SPECIFICATION = 0x00010006 6 | SUPPORTED_ARCHITECTURES = IA32|X64|ARM|AARCH64|RISCV64|LOONGARCH64|EBC 7 | BUILD_TARGETS = DEBUG|RELEASE|NOOPT 8 | SKUID_IDENTIFIER = DEFAULT 9 | 10 | !include MdePkg/MdeLibs.dsc.inc 11 | 12 | [Packages] 13 | MdePkg/MdePkg.dec 14 | 15 | [LibraryClasses] 16 | efifetch|efifetch/efifetch.inf 17 | BaseLib|MdePkg/Library/BaseLib/BaseLib.inf 18 | BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf 19 | DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf 20 | DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf 21 | PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf 22 | PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf 23 | UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf 24 | UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf 25 | 26 | [Components] 27 | efifetch/efifetch.inf 28 | -------------------------------------------------------------------------------- /efifetch/lib/net.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"str.h" 3 | #include"net.h" 4 | 5 | int ipv4_to_string(efi_ipv4_address*ip,char*buff,size_t len){ 6 | if(!ip||!buff||len<8)return -1; 7 | return snprintf(buff,len,"%u.%u.%u.%u", 8 | ip->addr[0],ip->addr[1], 9 | ip->addr[2],ip->addr[3] 10 | ); 11 | } 12 | 13 | int ipv4_to_prefix(efi_ipv4_address*msk){ 14 | if(!msk)return -1; 15 | int prefix=0; 16 | uint32_t mask_val=msk->raw; 17 | unsigned long m=0x80000000; 18 | while(prefix<32&&m){ 19 | if(mask_val&m)prefix++; 20 | m>>=1; 21 | } 22 | return prefix; 23 | } 24 | 25 | int ipv6_to_string(efi_ipv6_address*ip,char*buff,size_t len){ 26 | if(!ip||!buff||len<39)return -1; 27 | memset(buff,0,len); 28 | if(ip->u64[0]==0&&ip->u16[4]==0&&ip->u16[5]==0xFFFF){ 29 | strlcat(buff,"::ffff:",len); 30 | efi_ipv4_address addr={.raw=ip->u32[3]}; 31 | int r=ipv4_to_string(&addr,buff+7,len-7); 32 | return r<0?-1:r+7; 33 | } 34 | bool zeroed=false,in_zero=false; 35 | for(int i=0;i<8;i++){ 36 | if(ip->u16[i]==0){ 37 | if(!zeroed){ 38 | zeroed=true; 39 | in_zero=true; 40 | strlcat(buff,"::",len); 41 | continue; 42 | }else if(in_zero)continue; 43 | }else if(in_zero){ 44 | in_zero=false; 45 | }else if(i>0)strlcat(buff,":",len); 46 | scprintf(buff,len,"%x",SWAP16(ip->u16[i])); 47 | } 48 | return strlen(buff); 49 | } 50 | -------------------------------------------------------------------------------- /efifetch/logo/ami.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_ami_data[]={ 4 | " .*#. ", 5 | " -####- ", 6 | " :######## ", 7 | " ***********- ", 8 | " :::::::::-----:. ", 9 | " ..........:****+. ", 10 | " +####**********#####* ", 11 | " :#######: .#######: ", 12 | " :::::-----: :::::-----: ", 13 | " =****= .=****+. ", 14 | " ..........:#####=..........#####- ", 15 | " :+++++++++++++++++++++++++++++*#####: ", 16 | ":######################################-", 17 | NULL 18 | }; 19 | 20 | static attr_map logo_ami_attr_map[]={ 21 | {'+', EFI_RED}, 22 | {'-', EFI_RED}, 23 | {'=', EFI_RED}, 24 | {':', EFI_RED}, 25 | {'.', EFI_RED}, 26 | {'*', EFI_RED}, 27 | {0,0} 28 | }; 29 | 30 | static const char*logo_ami_matchs[]={ 31 | "American Megatrends", 32 | "@American Megatrends", 33 | "@AMI", 34 | NULL, 35 | }; 36 | 37 | logo_desc logo_ami={ 38 | .main_color=EFI_RED, 39 | .width=40, 40 | .lines=logo_ami_data, 41 | .lines_count=sizeof(logo_ami_data)/sizeof(logo_ami_data[0])-1, 42 | .attr_map=logo_ami_attr_map, 43 | .attr_map_count=sizeof(logo_ami_attr_map)/sizeof(logo_ami_attr_map[0])-1, 44 | .matchs=logo_ami_matchs, 45 | }; 46 | -------------------------------------------------------------------------------- /efifetch/logo/kunlun.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_kunlun_data[]={ 4 | " ", 5 | " #################### ", 6 | " ######### ###### ", 7 | " ###### ### ", 8 | " ##### ## ### ", 9 | " #### ####### ### ## ", 10 | "#### ##### ###### ##### ###", 11 | "### ######## ### # ##### ## ", 12 | "############ # ## ### ## ## ### ", 13 | "### ######### ######## ## # ## ", 14 | "#### ######### ######### ###### ", 15 | "############### ################### ", 16 | " ############################## ", 17 | " ####################### ", 18 | " ", 19 | NULL 20 | }; 21 | 22 | static attr_map logo_kunlun_attr_map[]={ 23 | {'#', EFI_BLUE}, 24 | {0,0} 25 | }; 26 | 27 | static const char*logo_kunlun_matchs[]={ 28 | "@zdtech", 29 | "@zd-tech", 30 | "@kunlun", 31 | NULL, 32 | }; 33 | 34 | logo_desc logo_kunlun={ 35 | .main_color=EFI_RED, 36 | .width=40, 37 | .lines=logo_kunlun_data, 38 | .lines_count=sizeof(logo_kunlun_data)/sizeof(logo_kunlun_data[0])-1, 39 | .attr_map=logo_kunlun_attr_map, 40 | .attr_map_count=sizeof(logo_kunlun_attr_map)/sizeof(logo_kunlun_attr_map[0])-1, 41 | .matchs=logo_kunlun_matchs, 42 | }; 43 | -------------------------------------------------------------------------------- /efifetch/logo/huawei.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_huawei_data[]={ 4 | " :++= ---. ", 5 | " **++=- .::::: ", 6 | " = =**++== --::--- - ", 7 | " :***. .***++=. ------. .=++: ", 8 | " *****- +***++-:=====- :+++** ", 9 | " ******+ +****=-++++= =++**** ", 10 | " :*******.****==**+*.+******- ", 11 | " =#*. :****** ***--*** ******: .**= ", 12 | " -###**-.-**** =*. *+ ****=.:*****- ", 13 | " =####***=.:+*.- -.*+:.=*******= ", 14 | " =####***** +********= ", 15 | " .-====++++- :+++====--: ", 16 | " .*####= -*****. ", 17 | " ", 18 | NULL 19 | }; 20 | 21 | static attr_map logo_huawei_attr_map[]={ 22 | {'*', EFI_RED}, 23 | {'=', EFI_RED}, 24 | {'-', EFI_RED}, 25 | {'+', EFI_RED}, 26 | {':', EFI_RED}, 27 | {'.', EFI_RED}, 28 | {0,0} 29 | }; 30 | 31 | static const char*logo_huawei_matchs[]={ 32 | "HUAWEI", 33 | "@huawei", 34 | NULL, 35 | }; 36 | 37 | logo_desc logo_huawei={ 38 | .main_color=EFI_RED, 39 | .width=40, 40 | .lines=logo_huawei_data, 41 | .lines_count=sizeof(logo_huawei_data)/sizeof(logo_huawei_data[0])-1, 42 | .attr_map=logo_huawei_attr_map, 43 | .attr_map_count=sizeof(logo_huawei_attr_map)/sizeof(logo_huawei_attr_map[0])-1, 44 | .matchs=logo_huawei_matchs, 45 | }; 46 | -------------------------------------------------------------------------------- /efifetch/lib/alloc.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"str.h" 3 | #include"init.h" 4 | 5 | __weak void*realloc(void*old,size_t size){ 6 | void*pool=NULL; 7 | if(!g_bs)return NULL; 8 | pool=malloc(size); 9 | if(pool){ 10 | uint64_t os=*((uint64_t*)old-8); 11 | memcpy(pool,old,MIN(size,os)); 12 | free(old); 13 | } 14 | return pool; 15 | } 16 | 17 | __weak void*malloc(size_t size){ 18 | void*pool=NULL; 19 | if(!g_bs)return NULL; 20 | g_bs->alloc_pool(efi_loader_data,size+8,(void**)&pool); 21 | if(!pool)return NULL; 22 | *((uint64_t*)pool)=size; 23 | return pool+8; 24 | } 25 | 26 | __weak void free(void*buffer){ 27 | if(!g_bs||!buffer)return; 28 | g_bs->free_pool(buffer-8); 29 | } 30 | 31 | __weak char*strdup(const char*str){ 32 | if(!str)return NULL; 33 | size_t len=strlen(str); 34 | void*dup=malloc(len+1); 35 | if(!dup)return NULL; 36 | memcpy(dup,str,len+1); 37 | return dup; 38 | } 39 | 40 | __weak char*strndup(const char*str,size_t max){ 41 | if(!str)return NULL; 42 | size_t len=strnlen(str,max); 43 | void*dup=malloc(len+1); 44 | if(!dup)return NULL; 45 | memcpy(dup,str,len+1); 46 | return dup; 47 | } 48 | 49 | __weak void*memdup(const void*mem,size_t len){ 50 | if(!mem||len<=0)return NULL; 51 | void*dup=malloc(len); 52 | if(!dup)return NULL; 53 | memcpy(dup,mem,len); 54 | return dup; 55 | } 56 | 57 | __weak void*zalloc(size_t size){ 58 | void*m=malloc(size); 59 | if(m)memset(m,0,size); 60 | return m; 61 | } 62 | 63 | __weak void*calloc(size_t nmemb,size_t size){ 64 | return zalloc(size*nmemb); 65 | } 66 | -------------------------------------------------------------------------------- /efifetch/logo/quanta.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_quanta_data[]={ 4 | " ######### ", 5 | " ################## ", 6 | " ####################### ", 7 | " ########## ########## ", 8 | " ######## ######## ", 9 | " ####### ####### ", 10 | " ###### ####### ", 11 | "###### ###### ", 12 | "###### ###### ", 13 | "###### ", 14 | "###### ************************", 15 | " ###### ***********************", 16 | " ####### ", 17 | " ######## *********************", 18 | " ########## ********************", 19 | " ########### ", 20 | " ######### ****************", 21 | " #### ***************", 22 | NULL 23 | }; 24 | 25 | static attr_map logo_quanta_attr_map[]={ 26 | {'#', EFI_BLUE}, 27 | {'*', EFI_RED}, 28 | {0,0} 29 | }; 30 | 31 | static const char*logo_quanta_matchs[]={ 32 | "QUANTA", 33 | "@QUANTA", 34 | NULL, 35 | }; 36 | 37 | logo_desc logo_quanta={ 38 | .main_color=EFI_BLUE, 39 | .width=40, 40 | .lines=logo_quanta_data, 41 | .lines_count=sizeof(logo_quanta_data)/sizeof(logo_quanta_data[0])-1, 42 | .attr_map=logo_quanta_attr_map, 43 | .attr_map_count=sizeof(logo_quanta_attr_map)/sizeof(logo_quanta_attr_map[0])-1, 44 | .matchs=logo_quanta_matchs, 45 | }; 46 | -------------------------------------------------------------------------------- /efifetch/include/print.h: -------------------------------------------------------------------------------- 1 | #ifndef PRINT_H 2 | #define PRINT_H 3 | #include"efi.h" 4 | extern efi_simple_text_output_protocol*debug_output; 5 | extern efi_status text_print_repeat(efi_simple_text_output_protocol*con,char ch,uintn_t cnt); 6 | extern efi_status text_print(efi_simple_text_output_protocol*con,const char*str); 7 | extern efi_status text_printn(efi_simple_text_output_protocol*con,const char*str,size_t len); 8 | extern efi_status text_printf(efi_simple_text_output_protocol*con,const char*str,...); 9 | extern efi_status text_vprintf(efi_simple_text_output_protocol*con,const char*str,va_list va); 10 | extern efi_status dbg_print(const char*str); 11 | extern efi_status dbg_printn(const char*str,size_t len); 12 | extern efi_status dbg_printf(const char*str,...); 13 | extern efi_status dbg_vprintf(const char*str,va_list va); 14 | extern efi_status out_print(const char*str); 15 | extern efi_status out_printn(const char*str,size_t len); 16 | extern efi_status out_printf(const char*str,...); 17 | extern efi_status out_vprintf(const char*str,va_list va); 18 | extern efi_status err_print(const char*str); 19 | extern efi_status err_printn(const char*str,size_t len); 20 | extern efi_status err_printf(const char*str,...); 21 | extern efi_status err_vprintf(const char*str,va_list va); 22 | extern efi_status out_setattr(uintn_t attr); 23 | extern efi_status err_setattr(uintn_t attr); 24 | extern efi_status out_resetattr(void); 25 | extern efi_status err_resetattr(void); 26 | extern void print_init(); 27 | #define trace_line dbg_printf("%s %s:%d\n",__FILE__,__func__,__LINE__); 28 | #endif 29 | -------------------------------------------------------------------------------- /efifetch/logo/dell.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_dell_data[]={ 4 | " ************** ", 5 | " ********************** ", 6 | " **** ***** ", 7 | " **** ***** ", 8 | " **** **** ", 9 | " **** **** ", 10 | " *** ****", 11 | "*** **** ****** * * ***", 12 | "*** * ** * * * ***", 13 | "*** * * ****** * * ***", 14 | "*** * ** * * * ***", 15 | "*** **** ****** ***** ***** ***", 16 | " *** ****", 17 | " **** **** ", 18 | " **** **** ", 19 | " **** **** ", 20 | " ***** ***** ", 21 | " ********************** ", 22 | " ************** ", 23 | NULL 24 | }; 25 | 26 | static attr_map logo_dell_attr_map[]={ 27 | {'*', EFI_BLUE}, 28 | {0,0} 29 | }; 30 | 31 | static const char*logo_dell_matchs[]={ 32 | "Dell Inc.", 33 | "Dell Inc", 34 | "Dell", 35 | "$^.*Dell.*$", 36 | NULL, 37 | }; 38 | 39 | logo_desc logo_dell={ 40 | .main_color=EFI_BLUE, 41 | .width=40, 42 | .lines=logo_dell_data, 43 | .lines_count=sizeof(logo_dell_data)/sizeof(logo_dell_data[0])-1, 44 | .attr_map=logo_dell_attr_map, 45 | .attr_map_count=sizeof(logo_dell_attr_map)/sizeof(logo_dell_attr_map[0])-1, 46 | .matchs=logo_dell_matchs, 47 | }; 48 | -------------------------------------------------------------------------------- /efifetch/logo/phoenix.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_phoenix_data[]={ 4 | " ... ", 5 | " -**************+ ", 6 | " +*+-.. .:=*********: ", 7 | " .*: =*******- ", 8 | " + +********- .*******. ", 9 | ". =:. .-*****-:******= ", 10 | " . .********+**+ ", 11 | " .******++**- : ", 12 | " +***** *** -.", 13 | " +****.-**: =-", 14 | " **** **=.*-", 15 | " **** **+**.", 16 | " +** ****- ", 17 | " ** =***- ", 18 | " : **+ ", 19 | " +- ", 20 | " ", 21 | NULL 22 | }; 23 | 24 | static attr_map logo_phoenix_attr_map[]={ 25 | {'*', EFI_RED}, 26 | {'=', EFI_RED}, 27 | {'-', EFI_RED}, 28 | {'+', EFI_RED}, 29 | {':', EFI_RED}, 30 | {'.', EFI_RED}, 31 | {0,0} 32 | }; 33 | 34 | static const char*logo_phoenix_matchs[]={ 35 | "Phoenix", 36 | "@Phoenix", 37 | NULL, 38 | }; 39 | 40 | logo_desc logo_phoenix={ 41 | .main_color=EFI_RED, 42 | .width=40, 43 | .lines=logo_phoenix_data, 44 | .lines_count=sizeof(logo_phoenix_data)/sizeof(logo_phoenix_data[0])-1, 45 | .attr_map=logo_phoenix_attr_map, 46 | .attr_map_count=sizeof(logo_phoenix_attr_map)/sizeof(logo_phoenix_attr_map[0])-1, 47 | .matchs=logo_phoenix_matchs, 48 | }; 49 | -------------------------------------------------------------------------------- /efifetch/logo/virtualbox.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_virtualbox_data[]={ 4 | "*************** +++++++++++++ ", 5 | "**************** +++++++++++++++", 6 | " *************** +++++++++++++++", 7 | " ***** ****** +++++ +++++", 8 | " ****** ***** +++++ +++++", 9 | " ***** ****** +++++++++++++++++", 10 | " ***** ****** +++++++++++++++++", 11 | " ***** ", 12 | " ****** ", 13 | " ***** ", 14 | " ****** ********************", 15 | " ***** *********************", 16 | " ****** ***** *****", 17 | " ****** ****** *****", 18 | " ***** ***** *****", 19 | " *************** *************", 20 | " ************** **************", 21 | " *********** ************* ", 22 | NULL 23 | }; 24 | 25 | static attr_map logo_virtualbox_attr_map[]={ 26 | {'*', EFI_BLUE}, 27 | {'+', EFI_YELLOW}, 28 | {0,0} 29 | }; 30 | 31 | static const char*logo_virtualbox_matchs[]={ 32 | "virtualbox", 33 | "@virtualbox", 34 | NULL, 35 | }; 36 | 37 | logo_desc logo_virtualbox={ 38 | .main_color=EFI_BLUE, 39 | .width=40, 40 | .lines=logo_virtualbox_data, 41 | .lines_count=sizeof(logo_virtualbox_data)/sizeof(logo_virtualbox_data[0])-1, 42 | .attr_map=logo_virtualbox_attr_map, 43 | .attr_map_count=sizeof(logo_virtualbox_attr_map)/sizeof(logo_virtualbox_attr_map[0])-1, 44 | .matchs=logo_virtualbox_matchs, 45 | }; 46 | -------------------------------------------------------------------------------- /efifetch/logo/microsoft.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_microsoft_data[]={ 4 | "################### *******************", 5 | "################### *******************", 6 | "################### *******************", 7 | "################### *******************", 8 | "################### *******************", 9 | "################### *******************", 10 | "################### *******************", 11 | "################### *******************", 12 | " ", 13 | "@@@@@@@@@@@@@@@@@@@ %%%%%%%%%%%%%%%%%%%", 14 | "@@@@@@@@@@@@@@@@@@@ %%%%%%%%%%%%%%%%%%%", 15 | "@@@@@@@@@@@@@@@@@@@ %%%%%%%%%%%%%%%%%%%", 16 | "@@@@@@@@@@@@@@@@@@@ %%%%%%%%%%%%%%%%%%%", 17 | "@@@@@@@@@@@@@@@@@@@ %%%%%%%%%%%%%%%%%%%", 18 | "@@@@@@@@@@@@@@@@@@@ %%%%%%%%%%%%%%%%%%%", 19 | "@@@@@@@@@@@@@@@@@@@ %%%%%%%%%%%%%%%%%%%", 20 | "@@@@@@@@@@@@@@@@@@@ %%%%%%%%%%%%%%%%%%%", 21 | NULL 22 | }; 23 | 24 | static attr_map logo_microsoft_attr_map[]={ 25 | {'#', EFI_RED}, 26 | {'*', EFI_GREEN}, 27 | {'@', EFI_BLUE}, 28 | {'%', EFI_YELLOW}, 29 | {0,0} 30 | }; 31 | 32 | static const char*logo_microsoft_matchs[]={ 33 | "Microsoft", 34 | "Surface", 35 | "MSFT", 36 | "@microsoft", 37 | "@surface", 38 | "@msft", 39 | NULL, 40 | }; 41 | 42 | logo_desc logo_microsoft={ 43 | .main_color=EFI_GREEN, 44 | .width=40, 45 | .lines=logo_microsoft_data, 46 | .lines_count=sizeof(logo_microsoft_data)/sizeof(logo_microsoft_data[0])-1, 47 | .attr_map=logo_microsoft_attr_map, 48 | .attr_map_count=sizeof(logo_microsoft_attr_map)/sizeof(logo_microsoft_attr_map[0])-1, 49 | .matchs=logo_microsoft_matchs, 50 | }; 51 | -------------------------------------------------------------------------------- /efifetch/logo/byosoft.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_byosoft_data[]={ 4 | " ", 5 | " ##### ####### ", 6 | " ##### ######### ", 7 | " ##### ########### ", 8 | " ##### ############# ", 9 | " ########################## ", 10 | " ################*##### ##### ", 11 | " ##############*##### ###### ", 12 | " ######*##### # ###### ", 13 | " #### ######*##### ### #####* ", 14 | " #################*##### #########* ", 15 | " #################*##### ######* ", 16 | " ###############*##### ## ####* ", 17 | " ###############*### #### ##* ", 18 | " ###### ######*#### ##### ", 19 | " ##### ######*#### ##### ", 20 | " ##### ######*########* ", 21 | " ##### #############* ", 22 | " #################* ", 23 | " ##############* ", 24 | " ", 25 | NULL 26 | }; 27 | 28 | static attr_map logo_byosoft_attr_map[]={ 29 | {'#', EFI_RED}, 30 | {'*', EFI_LIGHTRED}, 31 | {0,0} 32 | }; 33 | 34 | static const char*logo_byosoft_matchs[]={ 35 | "@byosoft", 36 | NULL, 37 | }; 38 | 39 | logo_desc logo_byosoft={ 40 | .main_color=EFI_RED, 41 | .width=40, 42 | .lines=logo_byosoft_data, 43 | .lines_count=sizeof(logo_byosoft_data)/sizeof(logo_byosoft_data[0])-1, 44 | .attr_map=logo_byosoft_attr_map, 45 | .attr_map_count=sizeof(logo_byosoft_attr_map)/sizeof(logo_byosoft_attr_map[0])-1, 46 | .matchs=logo_byosoft_matchs, 47 | }; 48 | -------------------------------------------------------------------------------- /efifetch/logo/vmware.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_vmware_data[]={ 4 | " ++++++++++++++++++++++++ ", 5 | " ++++++++++++++++++++++++++++ ", 6 | " ++++++++++++++++++++++++++++++", 7 | " ++++++ ++++++", 8 | " +++++ +++++", 9 | " *************************** +++++", 10 | " ***************************** +++++", 11 | "******************************* +++++", 12 | "******* +++++ ******** +++++", 13 | "****** +++++ ****** +++++", 14 | "****** +++++ ****** +++++", 15 | "****** +++++ ****** +++++", 16 | "****** ++++++ ****** ++++++", 17 | "****** ++++++++++++++++++++++++++++++", 18 | "****** ++++++++++++++++++++++++++++ ", 19 | "****** ++++++++++++++++++++++++++ ", 20 | "****** ****** ", 21 | "******* ******* ", 22 | "****************************** ", 23 | "****************************** ", 24 | " ************************** ", 25 | NULL 26 | }; 27 | 28 | static attr_map logo_vmware_attr_map[]={ 29 | {'+', EFI_BLUE}, 30 | {'*', EFI_YELLOW}, 31 | {0,0} 32 | }; 33 | 34 | static const char*logo_vmware_matchs[]={ 35 | "VMware", 36 | "@vmware", 37 | NULL, 38 | }; 39 | 40 | logo_desc logo_vmware={ 41 | .main_color=EFI_YELLOW, 42 | .width=40, 43 | .lines=logo_vmware_data, 44 | .lines_count=sizeof(logo_vmware_data)/sizeof(logo_vmware_data[0])-1, 45 | .attr_map=logo_vmware_attr_map, 46 | .attr_map_count=sizeof(logo_vmware_attr_map)/sizeof(logo_vmware_attr_map[0])-1, 47 | .matchs=logo_vmware_matchs, 48 | }; 49 | -------------------------------------------------------------------------------- /scripts/qemu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | DISK=/tmp/disk.img 4 | FLAGS=( 5 | -enable-kvm 6 | -cpu host 7 | -serial stdio 8 | -drive file=$DISK,format=raw,if=none,id=sda 9 | -display vnc=:11 10 | -device qemu-xhci 11 | -device usb-kbd 12 | -device virtio-scsi-pci 13 | -device scsi-hd,drive=sda 14 | $@ 15 | ) 16 | rm -f $DISK 17 | fallocate -l 256M $DISK 18 | parted -s $DISK mklabel gpt 19 | parted -s $DISK mkpart boot 2048s 100% 20 | parted -s $DISK set 1 esp on 21 | LOOP=$(losetup -f -P --show $DISK) 22 | mkfs.vfat -F32 ${LOOP}p1 23 | mkdir -p /tmp/disk 24 | mount -t vfat ${LOOP}p1 /tmp/disk 25 | mkdir -p /tmp/disk/efi/boot/ 26 | cp build/efifetch.efi /tmp/disk/ 27 | CARCH="$(uname -m)" 28 | case "${ARCH:-${CARCH}}" in 29 | aarch64|armv8|armv8l|armv8a) 30 | FLAGS+=( 31 | -machine virt 32 | -device virtio-gpu 33 | -bios /usr/share/edk2/aarch64/QEMU_EFI.fd 34 | ) 35 | QEMU_ARCH=aarch64 36 | cp /usr/share/edk2-shell/aarch64/Shell_Full.efi /tmp/disk/efi/boot/bootaa64.efi 37 | ;; 38 | x86_64|x64|amd64) 39 | FLAGS+=( 40 | -machine q35 41 | -bios /usr/share/edk2/x64/OVMF.4m.fd 42 | ) 43 | QEMU_ARCH=x86_64 44 | cp /usr/share/edk2-shell/x64/Shell_Full.efi /tmp/disk/efi/boot/bootx64.efi 45 | ;; 46 | i386|i486|i586|i686|x86|ia32) 47 | FLAGS+=( 48 | -machine q35 49 | -bios /usr/share/edk2/ia32/OVMF.4m.fd 50 | ) 51 | QEMU_ARCH=i386 52 | cp /usr/share/edk2-shell/ia32/Shell_Full.efi /tmp/disk/efi/boot/bootia32.efi 53 | ;; 54 | *)exit 1;; 55 | esac 56 | cat < /tmp/disk/startup.nsh 57 | ifconfig -s eth0 dhcp 58 | stall 300000 59 | fs0: 60 | efifetch 61 | EOF 62 | umount /tmp/disk 63 | losetup -d $LOOP 64 | exec qemu-system-${QEMU_ARCH} ${FLAGS[@]} 65 | -------------------------------------------------------------------------------- /efifetch/logo/insyde.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_insyde_data[]={ 4 | " .:-=++++=-.. ", 5 | " .=++++++++++++++++=. ", 6 | " -++++++++=:. .-=+: ", 7 | " -+++++++- ..::::. =- ", 8 | " .-=+++++. .----===+++++=:. :. ", 9 | " .--++++- -----++++=--=++++++. . ", 10 | " .--=+++: :---=+-. :=+= ", 11 | " ---=++: ----=: -------. .+= ", 12 | " .---=+= .---- ...:-=----. -= ", 13 | " :---=+- ---- .==--. -. ", 14 | " -----+: .---. :++=. . ", 15 | " :----=- :-. :++- ", 16 | " .------ +++. ", 17 | " :----=. =+= ", 18 | " .------. .++- ", 19 | " .------. .++- ", 20 | " ------- :++. ", 21 | " .------:. .-=:. ", 22 | " .------ ", 23 | " .:. ", 24 | NULL 25 | }; 26 | 27 | static attr_map logo_insyde_attr_map[]={ 28 | {'=', EFI_GREEN}, 29 | {'-', EFI_GREEN}, 30 | {'+', EFI_GREEN}, 31 | {':', EFI_GREEN}, 32 | {'.', EFI_GREEN}, 33 | {0,0} 34 | }; 35 | 36 | static const char*logo_insyde_matchs[]={ 37 | "INSYDE Corp.", 38 | "@INSYDE", 39 | NULL, 40 | }; 41 | 42 | logo_desc logo_insyde={ 43 | .main_color=EFI_GREEN, 44 | .width=40, 45 | .lines=logo_insyde_data, 46 | .lines_count=sizeof(logo_insyde_data)/sizeof(logo_insyde_data[0])-1, 47 | .attr_map=logo_insyde_attr_map, 48 | .attr_map_count=sizeof(logo_insyde_attr_map)/sizeof(logo_insyde_attr_map[0])-1, 49 | .matchs=logo_insyde_matchs, 50 | }; 51 | -------------------------------------------------------------------------------- /efifetch/logo/hp.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_hp_data[]={ 4 | " ** ********* ", 5 | " ***** ************* ", 6 | " ******* **************** ", 7 | " ******** ******************* ", 8 | " ******** ********************* ", 9 | " ********** *********************** ", 10 | " ********** ******* ****** ", 11 | " ********* **** *** ", 12 | "********** **** +*** **** *****", 13 | "********* *** **** +*** *****", 14 | "******** **** **** **** ******", 15 | "******** **** ***** **** *******", 16 | "******* ***** **** **** *******", 17 | "******* **** **** **** ********", 18 | " ***** **** ****+ *** ******** ", 19 | " **** +**** **** ********** ", 20 | " ***************** *************** ", 21 | " ************** *************** ", 22 | " ************* ************** ", 23 | " ********** ************ ", 24 | " ******** *********** ", 25 | " *** +******* ", 26 | NULL 27 | }; 28 | 29 | static attr_map logo_hp_attr_map[]={ 30 | {'*', EFI_BLUE}, 31 | {'+', EFI_BLUE}, 32 | {0,0} 33 | }; 34 | 35 | static const char*logo_hp_matchs[]={ 36 | "HP", 37 | "HPE", 38 | "@Hewlett Packard", 39 | "@Hewlett-Packard", 40 | NULL, 41 | }; 42 | 43 | logo_desc logo_hp={ 44 | .main_color=EFI_BLUE, 45 | .width=40, 46 | .lines=logo_hp_data, 47 | .lines_count=sizeof(logo_hp_data)/sizeof(logo_hp_data[0])-1, 48 | .attr_map=logo_hp_attr_map, 49 | .attr_map_count=sizeof(logo_hp_attr_map)/sizeof(logo_hp_attr_map[0])-1, 50 | .matchs=logo_hp_matchs, 51 | }; 52 | -------------------------------------------------------------------------------- /efifetch/logo/lenovo.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_lenovo_data[]={ 4 | " ********* ", 5 | " ******************** ", 6 | " ************************** ", 7 | " ******************************* ", 8 | " ******************************** ", 9 | " **************###****************** ", 10 | " ***************###******************** ", 11 | "****************###*********************", 12 | "****************###*********************", 13 | "****************###*********************", 14 | "****************###*********************", 15 | "****************###*********************", 16 | "****************###*********************", 17 | "****************###*********************", 18 | "****************###******************** ", 19 | " **************###########************ ", 20 | " ************************************ ", 21 | " ******************************** ", 22 | " ***************************** ", 23 | " ************************* ", 24 | " ******************** ", 25 | " *********** ", 26 | NULL 27 | }; 28 | 29 | static attr_map logo_lenovo_attr_map[]={ 30 | {'*', EFI_RED}, 31 | {'#', EFI_WHITE}, 32 | {0,0} 33 | }; 34 | 35 | static const char*logo_lenovo_matchs[]={ 36 | "Lenovo", 37 | "@Lenovo", 38 | NULL, 39 | }; 40 | 41 | logo_desc logo_lenovo={ 42 | .main_color=EFI_RED, 43 | .width=40, 44 | .lines=logo_lenovo_data, 45 | .lines_count=sizeof(logo_lenovo_data)/sizeof(logo_lenovo_data[0])-1, 46 | .attr_map=logo_lenovo_attr_map, 47 | .attr_map_count=sizeof(logo_lenovo_attr_map)/sizeof(logo_lenovo_attr_map[0])-1, 48 | .matchs=logo_lenovo_matchs, 49 | }; 50 | -------------------------------------------------------------------------------- /efifetch/libfdt/fdt_strerror.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6 | */ 7 | #include "libfdt_env.h" 8 | 9 | #include "fdt.h" 10 | #include "libfdt.h" 11 | 12 | #include "libfdt_internal.h" 13 | 14 | struct fdt_errtabent { 15 | const char *str; 16 | }; 17 | 18 | #define FDT_ERRTABENT(val) \ 19 | [(val)] = { .str = #val, } 20 | 21 | static struct fdt_errtabent fdt_errtable[] = { 22 | FDT_ERRTABENT(FDT_ERR_NOTFOUND), 23 | FDT_ERRTABENT(FDT_ERR_EXISTS), 24 | FDT_ERRTABENT(FDT_ERR_NOSPACE), 25 | 26 | FDT_ERRTABENT(FDT_ERR_BADOFFSET), 27 | FDT_ERRTABENT(FDT_ERR_BADPATH), 28 | FDT_ERRTABENT(FDT_ERR_BADPHANDLE), 29 | FDT_ERRTABENT(FDT_ERR_BADSTATE), 30 | 31 | FDT_ERRTABENT(FDT_ERR_TRUNCATED), 32 | FDT_ERRTABENT(FDT_ERR_BADMAGIC), 33 | FDT_ERRTABENT(FDT_ERR_BADVERSION), 34 | FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), 35 | FDT_ERRTABENT(FDT_ERR_BADLAYOUT), 36 | FDT_ERRTABENT(FDT_ERR_INTERNAL), 37 | FDT_ERRTABENT(FDT_ERR_BADNCELLS), 38 | FDT_ERRTABENT(FDT_ERR_BADVALUE), 39 | FDT_ERRTABENT(FDT_ERR_BADOVERLAY), 40 | FDT_ERRTABENT(FDT_ERR_NOPHANDLES), 41 | FDT_ERRTABENT(FDT_ERR_BADFLAGS), 42 | FDT_ERRTABENT(FDT_ERR_ALIGNMENT), 43 | }; 44 | #define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) 45 | 46 | const char *fdt_strerror(int errval) 47 | { 48 | if (errval > 0) 49 | return ""; 50 | else if (errval == 0) 51 | return ""; 52 | else if (-errval < FDT_ERRTABSIZE) { 53 | const char *s = fdt_errtable[-errval].str; 54 | 55 | if (s) 56 | return s; 57 | } 58 | 59 | return ""; 60 | } 61 | -------------------------------------------------------------------------------- /efifetch/logo/uefi.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_uefi_data[]={ 4 | " %%%+ ", 5 | " %%%#+++++++= ", 6 | " %%%#++++++++++++*% ", 7 | " %%%*++++++++++++*#%%%#++ ", 8 | " %%%#++++++++++++#%%%%*++++++++ ", 9 | " %%%%%*++++++++++#%%%%*++++++++++++#% ", 10 | "%%%%%%%*+++++++*%%%#*++++++++++++#%%%%%%", 11 | "%%%%%%%%#++++++++++++++++++++*#%%%%%%%%%", 12 | "%%%#*++**##+++++++++++++++*#%#*++++++#%%", 13 | "%%+++++++++*#%#**+++++*#%%%*++++++++++%%", 14 | "%+++++++++++++#%%%%%%%%%%#++++++++++++%%", 15 | "#++++++++++++++#%%%%%%%%*++++++++++++#%%", 16 | "#++++++++#*+++++*%%%%%%*+++++%%%+*#%#+%%", 17 | "#++++++++*##+++++*%%%%#+++++#%%%%#++++%%", 18 | "%+++++++++++++++++#%%%++++++###%++++++%%", 19 | "%#+++++++++++++++++%%%++++++++*%++++++%%", 20 | "%%++++++*%#++++++++#%%++++++++*%++++++%%", 21 | "%%#++++++#%%%#*++++#%%++++++++*%++++++%%", 22 | "%%%%++++++++++#%%*+#%%++++++#%%%++++++%%", 23 | " %%%#+++++++++++#%%%%++++++#%%%++++++ ", 24 | " %%*+++++++++++%%%++++++#%%%+++ ", 25 | " %%*++++++*%%%%++++++#%%% ", 26 | " %%%%%%%%%%%++++++* ", 27 | " %%%%%%%%+++= ", 28 | " %%%% ", 29 | NULL 30 | }; 31 | 32 | static attr_map logo_uefi_attr_map[]={ 33 | {'#', EFI_RED}, 34 | {'*', EFI_RED}, 35 | {'+', EFI_WHITE}, 36 | {'%', EFI_RED}, 37 | {0,0} 38 | }; 39 | 40 | logo_desc logo_uefi={ 41 | .main_color=EFI_RED, 42 | .width=40, 43 | .lines=logo_uefi_data, 44 | .lines_count=sizeof(logo_uefi_data)/sizeof(logo_uefi_data[0])-1, 45 | .attr_map=logo_uefi_attr_map, 46 | .attr_map_count=sizeof(logo_uefi_attr_map)/sizeof(logo_uefi_attr_map[0])-1, 47 | }; 48 | -------------------------------------------------------------------------------- /efifetch/lib/readable.c: -------------------------------------------------------------------------------- 1 | #include"readable.h" 2 | #include"str.h" 3 | #include"print.h" 4 | 5 | const char*size_units_b[]={"B","KB","MB","GB","TB","PB","EB","ZB","YB",NULL}; 6 | const char*size_units_ib[]={"B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB",NULL}; 7 | const char*size_units_ibs[]={"B/s","KiB/s","MiB/s","GiB/s","TiB/s","PiB/s","EiB/s","ZiB/s","YiB/s",NULL}; 8 | const char*size_units_hz[]={"Hz","KHz","MHz","GHz","THz","PHz","EHz","ZHz","YHz",NULL}; 9 | 10 | const char*format_size_ex( 11 | char*buf,size_t len, 12 | uint64_t val,const char**units, 13 | size_t blk 14 | ){ 15 | int unit=0; 16 | if(!buf||len<=0||!units)return NULL; 17 | memset(buf,0,len); 18 | if(val==0)return strncpy(buf,"0",len); 19 | while((val>=blk)&&units[unit+1])val/=blk,unit++; 20 | snprintf(buf,len-1,"%llu %s",val,units[unit]); 21 | return buf; 22 | } 23 | 24 | const char*format_size_float_ex( 25 | char*buf,size_t len, 26 | uint64_t val,const char**units, 27 | size_t blk,uint8_t dot 28 | ){ 29 | int unit=0; 30 | uint8_t ncnt=1,append,pdot; 31 | uint64_t left,right,pd=10,xright; 32 | if(!buf||len<=0||!units)return NULL; 33 | if(dot==0)return format_size_ex(buf,len,val,units,blk); 34 | for(pdot=dot;pdot>0;pdot--)pd*=10; 35 | memset(buf,0,len); 36 | if(val==0)return strncpy(buf,"0",len); 37 | while((val>=blk*blk)&&units[unit+1]) 38 | val/=blk,unit++; 39 | left=val,right=0; 40 | if(val>=blk&&units[unit+1]) 41 | left=val/blk,right=(val%blk)*pd/blk,unit++; 42 | if(right%10>=5)right+=10; 43 | right/=10; 44 | while(right>0&&(right%10)==0)right/=10; 45 | for(xright=right;xright>10;xright/=10)ncnt++; 46 | scprintf(buf,len,"%llu",left); 47 | if(dot>0)scprintf(buf,len,".%llu",right); 48 | if(dot>ncnt)for(append=0;append=size)return 0; 22 | return stbsp_vsnprintf(buf+len,size-len,fmt,va); 23 | } 24 | 25 | __weak int vasprintf(char**buf,const char*fmt,va_list va){ 26 | if(!buf)return -1; 27 | *buf=NULL; 28 | int ret=vsnprintf(NULL,0,fmt,va); 29 | if(ret<=0)return ret; 30 | size_t size=ret+4; 31 | if(!(*buf=zalloc(size)))return -1; 32 | return vsnprintf(*buf,size,fmt,va); 33 | } 34 | 35 | __weak int sprintf(char*buf,const char*fmt,...){ 36 | va_list va; 37 | va_start(va,fmt); 38 | int ret=vsprintf(buf,fmt,va); 39 | va_end(va); 40 | return ret; 41 | } 42 | 43 | __weak int snprintf(char*buf,size_t size,const char*fmt,...){ 44 | va_list va; 45 | va_start(va,fmt); 46 | int ret=vsnprintf(buf,size,fmt,va); 47 | va_end(va); 48 | return ret; 49 | } 50 | 51 | __weak int scprintf(char*buf,size_t size,const char*fmt,...){ 52 | va_list va; 53 | va_start(va,fmt); 54 | int ret=vscprintf(buf,size,fmt,va); 55 | va_end(va); 56 | return ret; 57 | } 58 | 59 | __weak int asprintf(char**buf,const char*fmt,...){ 60 | va_list va; 61 | va_start(va,fmt); 62 | int ret=vasprintf(buf,fmt,va); 63 | va_end(va); 64 | return ret; 65 | } 66 | 67 | __weak int printf(const char*fmt,...){ 68 | va_list va; 69 | va_start(va,fmt); 70 | int ret=vprintf(fmt,va); 71 | va_end(va); 72 | return ret; 73 | } 74 | 75 | __weak int puts(const char*str){ 76 | return out_printf("%s\n",str); 77 | } 78 | 79 | __weak int putchar(int ch){ 80 | char buff[2]={ch,0}; 81 | return out_print(buff); 82 | } 83 | -------------------------------------------------------------------------------- /efifetch/info/sys.c: -------------------------------------------------------------------------------- 1 | #include "efi.h" 2 | #include"info.h" 3 | #include"init.h" 4 | #include "print.h" 5 | #include"str.h" 6 | 7 | static void efifetch_load_info_sys_firmware(efifetch*ctx){ 8 | if(!IS_EMPTY(FIRMWARE))return; 9 | if(g_st->firmware_vendor||!g_st->firmware_vendor[0]){ 10 | dbg_print("system table firmware vendor is empty\n"); 11 | return; 12 | } 13 | char buff[64]; 14 | encode_convert_ctx conv={}; 15 | conv.in.src=ENC_UTF16; 16 | conv.in.dst=ENC_UTF8; 17 | conv.in.src_ptr=(void*)g_st->firmware_vendor; 18 | conv.in.src_size=40*sizeof(char16); 19 | conv.in.dst_ptr=buff; 20 | conv.in.dst_size=sizeof(buff); 21 | conv.in.allow_invalid=true; 22 | encode_convert(&conv); 23 | if(conv.out.dst_wrote==0)return; 24 | APPENDF( 25 | FIRMWARE,"%s %u.%u",buff, 26 | (g_st->firmware_revision>>0x10)&0xFFFF, 27 | (g_st->firmware_revision>>0x00)&0xFFFF 28 | ); 29 | } 30 | 31 | static void efifetch_load_info_sys_secureboot(efifetch*ctx){ 32 | uintn_t var_size; 33 | efi_status st; 34 | uint8_t secureboot=0,setup=0; 35 | if(!IS_EMPTY(SECURE_BOOT))return; 36 | var_size=sizeof(secureboot); 37 | st=g_rt->get_var( 38 | L"SecureBoot", 39 | &gEfiGlobalVariableGuid, 40 | NULL, 41 | &var_size, 42 | &secureboot 43 | ); 44 | if(efi_error(st)){ 45 | dbg_printf("variable get secure boot failed: %m\n",st); 46 | SET(SECURE_BOOT,"unsupported"); 47 | return; 48 | } 49 | if(secureboot==0)SET(SECURE_BOOT,"disabled"); 50 | if(secureboot==1)SET(SECURE_BOOT,"enabled"); 51 | var_size=sizeof(setup); 52 | st=g_rt->get_var( 53 | L"SetupMode", 54 | &gEfiGlobalVariableGuid, 55 | NULL, 56 | &var_size, 57 | &setup 58 | ); 59 | if(efi_error(st)){ 60 | dbg_printf("variable get setup mode failed: %m\n",st); 61 | return; 62 | } 63 | if(setup==0)APPEND(SECURE_BOOT," (user)"); 64 | if(setup==1)APPEND(SECURE_BOOT," (setup)"); 65 | } 66 | 67 | void efifetch_load_info_sys(efifetch*ctx){ 68 | efifetch_load_info_sys_firmware(ctx); 69 | efifetch_load_info_sys_secureboot(ctx); 70 | SETF( 71 | SPEC,"UEFI v%u.%u", 72 | g_st->header.rev_major, 73 | g_st->header.rev_minor 74 | ); 75 | } 76 | -------------------------------------------------------------------------------- /efifetch/entry/efi-x86_64.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") 2 | OUTPUT_ARCH(i386:x86-64) 3 | ENTRY(_start) 4 | SECTIONS { 5 | . = 0; 6 | ImageBase = .; 7 | .hash : { *(.hash) } 8 | .gnu.hash : { *(.gnu.hash) } 9 | . = ALIGN(4096); 10 | .eh_frame : { *(.eh_frame) } 11 | .gcc_except_table : { *(.gcc_except_table*) } 12 | . = ALIGN(4096); 13 | .text : { 14 | _text = .; 15 | *(.text) 16 | *(.text.*) 17 | *(.gnu.linkonce.t.*) 18 | *(.plt) 19 | . = ALIGN(16); 20 | } 21 | _etext = .; 22 | _text_size = _etext - _text; 23 | . = ALIGN(4096); 24 | .reloc : { 25 | KEEP (*(.reloc)) 26 | } 27 | . = ALIGN(4096); 28 | .data : { 29 | _data = .; 30 | *(.got.plt) 31 | *(.got) 32 | *(.data*) 33 | *(.sdata) 34 | . = ALIGN(16); 35 | __init_array_start = .; 36 | *(SORT(.init_array.*)) 37 | *(.init_array) 38 | __init_array_end = .; 39 | . = ALIGN(16); 40 | __CTOR_LIST__ = .; 41 | *(SORT(.ctors.*)) 42 | *(.ctors) 43 | __CTOR_END__ = .; 44 | . = ALIGN(16); 45 | __DTOR_LIST__ = .; 46 | *(SORT(.dtors.*)) 47 | *(.dtors) 48 | __DTOR_END__ = .; 49 | . = ALIGN(16); 50 | __fini_array_start = .; 51 | *(SORT(.fini_array.*)) 52 | *(.fini_array) 53 | __fini_array_end = .; 54 | *(.sbss) 55 | *(.scommon) 56 | *(.dynbss) 57 | *(.bss*) 58 | *(COMMON) 59 | *(.rel.local) 60 | } 61 | .note.gnu.build-id : { *(.note.gnu.build-id) } 62 | _edata = .; 63 | _data_size = _edata - _etext; 64 | . = ALIGN(4096); 65 | .dynamic : { *(.dynamic) } 66 | . = ALIGN(4096); 67 | .rela : { 68 | *(.rela.text*) 69 | *(.rela.data*) 70 | *(.rela.got) 71 | *(.rela.dyn) 72 | *(.rela.stab) 73 | *(.rela.init_array*) 74 | *(.rela.fini_array*) 75 | *(.rela.ctors*) 76 | *(.rela.dtors*) 77 | } 78 | . = ALIGN(4096); 79 | .rela.plt : { *(.rela.plt) } 80 | . = ALIGN(4096); 81 | .rodata : { *(.rodata*) } 82 | . = ALIGN(4096); 83 | .dynsym : { *(.dynsym) } 84 | . = ALIGN(4096); 85 | .dynstr : { *(.dynstr) } 86 | . = ALIGN(4096); 87 | .ignored.reloc : { 88 | *(.rela.reloc) 89 | *(.note.GNU-stack) 90 | } 91 | .comment 0 : { *(.comment) } 92 | } 93 | -------------------------------------------------------------------------------- /efifetch/lib/mem.c: -------------------------------------------------------------------------------- 1 | #include"str.h" 2 | 3 | __weak void*memset(void*dest,int c,size_t n){ 4 | uint8_t*d=dest; 5 | if(!dest)return NULL; 6 | for(;n;n--)*d++=c; 7 | return dest; 8 | } 9 | 10 | __weak void*memchr(const void*src,int c,size_t n){ 11 | const unsigned char*s=src; 12 | if(!src)return NULL; 13 | c=(unsigned char)c; 14 | for(;n&&*s!=c;s++,n--); 15 | return n?(void*)s:NULL; 16 | } 17 | 18 | __weak void*memrchr(const void*m,int c,size_t n){ 19 | const unsigned char*s=m; 20 | if(!m)return NULL; 21 | c=(unsigned char)c; 22 | while(n--)if(s[n]==c)return(void*)(s+n); 23 | return 0; 24 | } 25 | 26 | __weak void*memmem(const void*h,size_t hl,const void*n,size_t nl){ 27 | char*s=(void*)h,*p=(void*)n; 28 | if(!h||!n)return NULL; 29 | if(nl==0)return s; 30 | if(hl=base)break; 22 | if(any<0)continue; 23 | if(acc>cutoff||(acc==cutoff&&c>cutlim)){ 24 | if(end)*end=(char*)str; 25 | return UINT64_MAX; 26 | }else any=1,acc*=(uint64_t)base,acc+=c; 27 | } 28 | if(neg&&any>0)acc=(uint64_t)(-((int64_t)acc)); 29 | if(end)*end=(char*)(any?s-1:str); 30 | return acc; 31 | } 32 | 33 | __weak long long strtoll(const char*str,char**end,int base){ 34 | const char *s=str; 35 | uint64_t acc,cutoff,xo; 36 | int neg,any,cutlim,c; 37 | if(!str)return 0; 38 | do{c=(unsigned char)*s++;}while(isspace(c)); 39 | if(c=='-'||c=='+')c=*s++; 40 | neg=c=='-'?1:0; 41 | if((base==0||base==16)&&c=='0'&&(*s=='x'||*s=='X')) 42 | c=s[1],s+=2,base=16; 43 | if(base==0)base=c=='0'?8:10; 44 | xo=(uint64_t)base; 45 | cutoff=UINT64_MAX/xo; 46 | cutlim=UINT64_MAX%xo; 47 | for(acc=0,any=0;;c=(unsigned char)*s++){ 48 | if(isdigit(c))c-='0'; 49 | else if(isalpha(c))c=toupper(c)-'A'+10; 50 | else break; 51 | if(c>=base)break; 52 | if(any<0)continue; 53 | if(acc>cutoff||(acc==cutoff&&c>cutlim)){ 54 | if(end)*end=(char*)str; 55 | return INT64_MAX; 56 | }else any=1,acc*=(uint64_t)base,acc+=c; 57 | } 58 | if(neg&&any>0)acc=(uint64_t)(-((int64_t)acc)); 59 | if(end)*end=(char*)(any?s-1:str); 60 | return acc; 61 | } 62 | 63 | __weak unsigned long strtoul(const char*str,char**end,int base){ 64 | return strtoull(str,end,base); 65 | } 66 | 67 | __weak long strtol(const char*str,char**end,int base){ 68 | return strtoll(str,end,base); 69 | } 70 | -------------------------------------------------------------------------------- /efifetch/main.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"efifetch.h" 3 | #include"str.h" 4 | #include"init.h" 5 | #include"print.h" 6 | #include"utils.h" 7 | #include"logo.h" 8 | 9 | static efifetch ctx; 10 | 11 | static logo_desc*logo_find_firmware(void){ 12 | char buff[512]; 13 | logo_desc*d; 14 | memset(buff,0,sizeof(buff)); 15 | const char*firm=ctx.fields[EFIFETCH_FIELD_FIRMWARE].value; 16 | if(firm[0]){ 17 | dbg_printf("find logo by %s\n",firm); 18 | if((d=logo_find(firm))){ 19 | dbg_printf("found logo %p\n",d); 20 | return d; 21 | } 22 | dbg_printf("no logo match with %s\n",firm); 23 | } 24 | if(g_st&&g_st->firmware_vendor){ 25 | encode_convert_ctx conv={}; 26 | conv.in.src=ENC_UTF16; 27 | conv.in.dst=ENC_UTF8; 28 | conv.in.src_ptr=(void*)g_st->firmware_vendor; 29 | conv.in.src_size=80*sizeof(char16); 30 | conv.in.dst_ptr=buff; 31 | conv.in.dst_size=sizeof(buff); 32 | conv.in.allow_invalid=true; 33 | encode_convert(&conv); 34 | } 35 | if(buff[0]){ 36 | dbg_printf("find logo by %s\n",buff); 37 | if((d=logo_find(buff))){ 38 | dbg_printf("found logo %p\n",d); 39 | return d; 40 | } 41 | dbg_printf("no logo match with %s\n",buff); 42 | } 43 | dbg_print("using fallback default logo\n"); 44 | return &logo_uefi; 45 | } 46 | 47 | static void load_options(void){ 48 | char options[512]={}; 49 | efi_loaded_image_protocol*li=NULL; 50 | li=efi_get_loaded_image(); 51 | if(!li||!li->load_options)return; 52 | encode_convert_ctx ctx={}; 53 | ctx.in.src=ENC_UTF16; 54 | ctx.in.dst=ENC_UTF8; 55 | ctx.in.src_ptr=li->load_options; 56 | ctx.in.src_size=li->load_options_size; 57 | ctx.in.dst_ptr=options; 58 | ctx.in.dst_size=sizeof(options); 59 | ctx.in.allow_invalid=true; 60 | encode_convert(&ctx); 61 | if(!options[0])return; 62 | if(strcasestr(options,"--debug")) 63 | debug_output=stderr; 64 | } 65 | 66 | efi_status efiapi uefi_main( 67 | efi_handle image_handle, 68 | efi_system_table*system_table 69 | ){ 70 | memset(&ctx,0,sizeof(ctx)); 71 | load_options(); 72 | efifetch_load_info(&ctx); 73 | logo_desc*logo=logo_find_firmware(); 74 | logo_ctx_init(&ctx.logo,stdout,logo,2); 75 | efifetch_print_all(&ctx); 76 | out_resetattr(); 77 | err_resetattr(); 78 | return efi_success; 79 | } 80 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build efifetch 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Install dependencies 17 | run: | 18 | sudo apt update 19 | sudo apt install -y make gcc gcc-aarch64-linux-gnu 20 | sudo apt install -y lib32gcc-$(gcc -dumpversion)-dev 21 | sudo apt install -y efi-shell-aa64 efi-shell-ia32 efi-shell-x64 22 | 23 | - name: Build x86_64 efifetch 24 | run: make ARCH=x86_64 O=build-x86_64 -j$(nproc) 25 | 26 | - name: Build i386 efifetch 27 | run: make ARCH=i386 O=build-i386 -j$(nproc) 28 | 29 | - name: Build aarch64 efifetch 30 | run: make ARCH=aarch64 O=build-aarch64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) 31 | 32 | - name: Package files 33 | run: | 34 | mkdir -p package/efifetch 35 | cp build-i386/efifetch.efi package/efifetch/efifetch-i386.efi 36 | cp build-x86_64/efifetch.efi package/efifetch/efifetch-x86_64.efi 37 | cp build-aarch64/efifetch.efi package/efifetch/efifetch-aarch64.efi 38 | cp /usr/share/efi-shell-ia32/shellia32.efi package/efifetch/shell-i386.efi 39 | cp /usr/share/efi-shell-x64/shellx64.efi package/efifetch/shell-x64.efi 40 | cp /usr/share/efi-shell-aa64/shellaa64.efi package/efifetch/shell-aarch64.efi 41 | mkdir -p package/efifetch-debug 42 | cp build-i386/efifetch.so package/efifetch-debug/efifetch-i386.debug 43 | cp build-x86_64/efifetch.so package/efifetch-debug/efifetch-x86_64.debug 44 | cp build-aarch64/efifetch.so package/efifetch-debug/efifetch-aarch64.debug 45 | find package -type f -exec chmod 644 {} \; 46 | find package -type d -exec chmod 755 {} \; 47 | 48 | - name: Upload efifetch artifacts 49 | uses: actions/upload-artifact@v4 50 | with: 51 | name: efifetch 52 | path: package/efifetch 53 | 54 | - name: Upload efifetch-debug artifacts 55 | uses: actions/upload-artifact@v4 56 | with: 57 | name: efifetch-debug 58 | path: package/efifetch-debug 59 | -------------------------------------------------------------------------------- /efifetch/logo/uboot.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | 3 | static const char*logo_uboot_data[]={ 4 | " ......::...... ", 5 | " ...::::::::::::::::::... ", 6 | " ..::::::::::::::::::::::::::.. ", 7 | " .::::.:::::::::::::::...::::.::::. ", 8 | " .::::::::::::::::::::..::::::::::::::. ", 9 | " .::.:::::::::::::::::::=*%#*::::::::::.::. ", 10 | " .:::::::::::::::::.....*%%*-:....::::::::::. ", 11 | " .:.:::...:::::::::.:-===##*---==-::::::::::.:. ", 12 | " .::::..::::........-***#****###****-...::::::.:. ", 13 | " ::.:.-+***+=::-=+**#%%%%%%%%%%%%###*= -::...::::. ", 14 | ".:.::-*****###%%%%%%%%%%%%%%%%%%%%%%%%%%#*=:..:::: ", 15 | ".::##:***#%%%%%%#####%%%%%%%####%%%%%####%%%*-.::. ", 16 | ":.:#%::*%%%%%%%#*****##%%%#*****##%%##*****#%%+.::.", 17 | ".::**==#%%%%%%%##****#%%%%##****#%%%%#****###%%:.. ", 18 | "..:#%::*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#%%%%%+ .:.", 19 | " ::##:+**#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* -.:: ", 20 | " ..::-#****#%#%%%%%%%%%%%%%%%%%%%%%%%%%%#*=-..::. ", 21 | " ...:=*****=::-=+**###%%%%%%%%###**+= --:...::: ", 22 | " .::.::--:........::::::--::::::......::::::. ", 23 | " .::.....::::::::::...........:::::::::.::. ", 24 | " .::::::::::::::::::::::::::::::::::::. ", 25 | " .::::.::::::::::::::::::::::.::::. ", 26 | " ..::::::::::::::::::::::::::.. ", 27 | " ...::::::::::::::::::... ", 28 | " ......::...... ", 29 | NULL 30 | }; 31 | 32 | static attr_map logo_uboot_attr_map[]={ 33 | {'.', EFI_BLUE}, 34 | {':', EFI_BLUE}, 35 | {'%', EFI_YELLOW}, 36 | {'*', EFI_YELLOW}, 37 | {'#', EFI_YELLOW}, 38 | {'+', EFI_YELLOW}, 39 | {0,0} 40 | }; 41 | 42 | static const char*logo_uboot_matchs[]={ 43 | "Das U-Boot", 44 | "@U-Boot", 45 | NULL, 46 | }; 47 | 48 | logo_desc logo_uboot={ 49 | .main_color=EFI_BLUE, 50 | .width=51, 51 | .lines=logo_uboot_data, 52 | .lines_count=sizeof(logo_uboot_data)/sizeof(logo_uboot_data[0])-1, 53 | .attr_map=logo_uboot_attr_map, 54 | .attr_map_count=sizeof(logo_uboot_attr_map)/sizeof(logo_uboot_attr_map[0])-1, 55 | .matchs=logo_uboot_matchs, 56 | }; 57 | 58 | -------------------------------------------------------------------------------- /efifetch/entry/efi-i386.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") 2 | OUTPUT_ARCH(i386) 3 | ENTRY(_start) 4 | SECTIONS { 5 | . = 0; 6 | ImageBase = .; 7 | .hash : { *(.hash) } 8 | .gnu.hash : { *(.gnu.hash) } 9 | .eh_frame : { *(.eh_frame) } 10 | .eh_frame_hdr : { *(.eh_frame_hdr) } 11 | .gcc_except_table : { *(.gcc_except_table*) } 12 | . = ALIGN(4096); 13 | .text : { 14 | _text = .; 15 | *(.text) 16 | *(.text.*) 17 | *(.gnu.linkonce.t.*) 18 | *(.plt) 19 | . = ALIGN(16); 20 | } 21 | _etext = .; 22 | _text_size = _etext - _text; 23 | . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); 24 | .data : { 25 | _data = .; 26 | *(.got.plt) 27 | *(.got) 28 | *(.data) 29 | *(.data1) 30 | *(.data.*) 31 | . = ALIGN(16); 32 | __init_array_start = .; 33 | *(SORT(.init_array.*)) 34 | *(.init_array) 35 | __init_array_end = .; 36 | . = ALIGN(16); 37 | __CTOR_LIST__ = .; 38 | *(SORT(.ctors.*)) 39 | *(.ctors) 40 | __CTOR_END__ = .; 41 | . = ALIGN(16); 42 | __DTOR_LIST__ = .; 43 | *(SORT(.dtors.*)) 44 | *(.dtors) 45 | __DTOR_END__ = .; 46 | . = ALIGN(16); 47 | __fini_array_start = .; 48 | *(SORT(.fini_array.*)) 49 | *(.fini_array) 50 | __fini_array_end = .; 51 | *(.dynbss) 52 | *(.bss*) 53 | *(COMMON) 54 | } 55 | .note.gnu.build-id : { *(.note.gnu.build-id) } 56 | . = ALIGN(4096); 57 | _DYNAMIC = .; 58 | .dynamic : { *(.dynamic) } 59 | . = ALIGN(4096); 60 | .rel : { 61 | *(.rel.text*) 62 | *(.rel.data*) 63 | *(.rel.got) 64 | *(.rel.dyn) 65 | *(.rel.stab) 66 | *(.rel.init_array*) 67 | *(.rel.fini_array*) 68 | *(.rel.ctors*) 69 | *(.rel.dtors*) 70 | *(.data.rel.ro.local) 71 | *(.data.rel.local) 72 | *(.data.rel.ro) 73 | *(.data.rel*) 74 | } 75 | . = ALIGN(4096); 76 | .rel.plt : { *(.rel.plt) } 77 | . = ALIGN(4096); 78 | .rodata : { *(.rodata*) } 79 | _edata = .; 80 | _data_size = _edata - _etext; 81 | . = ALIGN(4096); 82 | .reloc : { 83 | KEEP (*(.reloc)) 84 | } 85 | . = ALIGN(4096); 86 | .dynsym : { *(.dynsym) } 87 | . = ALIGN(4096); 88 | .dynstr : { *(.dynstr) } 89 | . = ALIGN(4096); 90 | . = DATA_SEGMENT_END (.); 91 | /DISCARD/ : { 92 | *(.rel.reloc) 93 | *(.note.GNU-stack) 94 | } 95 | .comment 0 : { *(.comment) } 96 | } 97 | -------------------------------------------------------------------------------- /efifetch/libfdt/fdt_check.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include "fdt.h" 9 | #include "libfdt.h" 10 | 11 | #include "libfdt_internal.h" 12 | 13 | int fdt_check_full(const void *fdt, size_t bufsize) 14 | { 15 | int err; 16 | int num_memrsv; 17 | int offset, nextoffset = 0; 18 | uint32_t tag; 19 | unsigned int depth = 0; 20 | const void *prop; 21 | const char *propname; 22 | bool expect_end = false; 23 | 24 | if (bufsize < FDT_V1_SIZE) 25 | return -FDT_ERR_TRUNCATED; 26 | if (bufsize < fdt_header_size(fdt)) 27 | return -FDT_ERR_TRUNCATED; 28 | err = fdt_check_header(fdt); 29 | if (err != 0) 30 | return err; 31 | if (bufsize < fdt_totalsize(fdt)) 32 | return -FDT_ERR_TRUNCATED; 33 | 34 | num_memrsv = fdt_num_mem_rsv(fdt); 35 | if (num_memrsv < 0) 36 | return num_memrsv; 37 | 38 | while (1) { 39 | offset = nextoffset; 40 | tag = fdt_next_tag(fdt, offset, &nextoffset); 41 | 42 | if (nextoffset < 0) 43 | return nextoffset; 44 | 45 | /* If we see two root nodes, something is wrong */ 46 | if (expect_end && tag != FDT_END) 47 | return -FDT_ERR_BADSTRUCTURE; 48 | 49 | switch (tag) { 50 | case FDT_NOP: 51 | break; 52 | 53 | case FDT_END: 54 | if (depth != 0) 55 | return -FDT_ERR_BADSTRUCTURE; 56 | return 0; 57 | 58 | case FDT_BEGIN_NODE: 59 | depth++; 60 | if (depth > INT_MAX) 61 | return -FDT_ERR_BADSTRUCTURE; 62 | 63 | /* The root node must have an empty name */ 64 | if (depth == 1) { 65 | const char *name; 66 | int len; 67 | 68 | name = fdt_get_name(fdt, offset, &len); 69 | if (!name) 70 | return len; 71 | 72 | if (*name || len) 73 | return -FDT_ERR_BADSTRUCTURE; 74 | } 75 | break; 76 | 77 | case FDT_END_NODE: 78 | if (depth == 0) 79 | return -FDT_ERR_BADSTRUCTURE; 80 | depth--; 81 | if (depth == 0) 82 | expect_end = true; 83 | break; 84 | 85 | case FDT_PROP: 86 | prop = fdt_getprop_by_offset(fdt, offset, &propname, 87 | &err); 88 | if (!prop) 89 | return err; 90 | break; 91 | 92 | default: 93 | return -FDT_ERR_INTERNAL; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /efifetch/libfdt/fdt_wip.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include "fdt.h" 9 | #include "libfdt.h" 10 | 11 | #include "libfdt_internal.h" 12 | 13 | int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, 14 | const char *name, int namelen, 15 | uint32_t idx, const void *val, 16 | int len) 17 | { 18 | void *propval; 19 | int proplen; 20 | 21 | propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, 22 | &proplen); 23 | if (!propval) 24 | return proplen; 25 | 26 | if ((unsigned)proplen < (len + idx)) 27 | return -FDT_ERR_NOSPACE; 28 | 29 | memcpy((char *)propval + idx, val, len); 30 | return 0; 31 | } 32 | 33 | int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, 34 | const void *val, int len) 35 | { 36 | const void *propval; 37 | int proplen; 38 | 39 | propval = fdt_getprop(fdt, nodeoffset, name, &proplen); 40 | if (!propval) 41 | return proplen; 42 | 43 | if (proplen != len) 44 | return -FDT_ERR_NOSPACE; 45 | 46 | return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, 47 | strlen(name), 0, 48 | val, len); 49 | } 50 | 51 | static void fdt_nop_region_(void *start, int len) 52 | { 53 | fdt32_t *p; 54 | 55 | for (p = start; (char *)p < ((char *)start + len); p++) 56 | *p = cpu_to_fdt32(FDT_NOP); 57 | } 58 | 59 | int fdt_nop_property(void *fdt, int nodeoffset, const char *name) 60 | { 61 | struct fdt_property *prop; 62 | int len; 63 | 64 | prop = fdt_get_property_w(fdt, nodeoffset, name, &len); 65 | if (!prop) 66 | return len; 67 | 68 | fdt_nop_region_(prop, len + sizeof(*prop)); 69 | 70 | return 0; 71 | } 72 | 73 | int fdt_node_end_offset_(void *fdt, int offset) 74 | { 75 | int depth = 0; 76 | 77 | while ((offset >= 0) && (depth >= 0)) 78 | offset = fdt_next_node(fdt, offset, &depth); 79 | 80 | return offset; 81 | } 82 | 83 | int fdt_nop_node(void *fdt, int nodeoffset) 84 | { 85 | int endoffset; 86 | 87 | endoffset = fdt_node_end_offset_(fdt, nodeoffset); 88 | if (endoffset < 0) 89 | return endoffset; 90 | 91 | fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0), 92 | endoffset - nodeoffset); 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # efifetch 2 | 3 | **efifetch** is a UEFI application that displays system information and vendor logos in the UEFI environment. It is lightweight, portable, and compatible with various platforms. 4 | 5 | ![efifetch running on VMware](assets/efifetch-vmware.png) 6 | 7 | ## Run 8 | 9 | ### Get efifetch 10 | 11 | You can either [build efifetch from source](#build-from-source) or download it from the [release page](https://github.com/BigfootACA/efifetch/releases). 12 | 13 | ### Determine your device architecture 14 | 15 | - AMD and Intel computers (most): x86_64 / X64 16 | - Older Intel Atom with 32-bit UEFI: i386 / IA32 17 | - Raspberry Pi or U-Boot based EFI: aarch64 / ARM64 18 | - Snapdragon tablets/laptops, WoA phones: aarch64 / ARM64 19 | - ARM SBSA-based servers and computers (Ampere, Hisilicon): aarch64 / ARM64 20 | 21 | ### Install efifetch 22 | 23 | 1. Prepare a USB drive formatted with FAT32. 24 | 2. Copy the efifetch binary (e.g., `efifetch-x86_64.efi`) to the FAT32 volume. 25 | 3. Copy the EFI Shell binary (e.g., `shell-x86_64.efi`) to the FAT32 volume. 26 | 27 | **Note:** To make the USB drive boot directly into the EFI Shell, rename `shell-x86_64.efi` as follows: 28 | - x86_64: `EFI\BOOT\BOOTX64.EFI` 29 | - i386: `EFI\BOOT\BOOTIA32.EFI` 30 | - aarch64: `EFI\BOOT\BOOTAA64.EFI` 31 | 32 | ### Run efifetch 33 | 34 | 1. Boot your device into the EFI shell. 35 | 2. Locate your USB drive's FAT32 volume using the `map` command. 36 | 3. Switch to the target volume (e.g., `FS0:`). 37 | 4. Execute the efifetch binary (e.g., `efifetch-x86_64`). 38 | 39 | ## Build from source 40 | 41 | There are multiple ways to build efifetch. Choose the method that best fits your environment. 42 | 43 | ### Build directly under Linux (Recommended) 44 | 45 | ```sh 46 | make -j $(nproc) 47 | ``` 48 | 49 | The output binary will be located at `build/efifetch.efi` 50 | 51 | ### Build with Tianocore EDK II 52 | 53 | ```bash 54 | git clone https://github.com/tianocore/edk2 55 | make -C edk2/BaseTools 56 | export PACKAGES_PATH="$PWD:$PWD/edk2" 57 | export EDK_TOOLS_PATH="$PWD/edk2/BaseTools" 58 | source edk2/edksetup.sh 59 | build -a X64 -t GCC5 -b RELEASE -p efifetch/efifetch.dsc 60 | ``` 61 | 62 | or 63 | 64 | ```bash 65 | git clone https://github.com/tianocore/edk2 66 | make build-edk2 67 | ``` 68 | 69 | The output binary will be located at `Build/efifetch/RELEASE_GCC5/X64/efifetch.efi` 70 | -------------------------------------------------------------------------------- /efifetch/entry/efi-riscv64.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv") 2 | OUTPUT_ARCH(riscv) 3 | ENTRY(_start) 4 | SECTIONS { 5 | . = 0; 6 | ImageBase = .; 7 | .hash : { *(.hash) } 8 | .gnu.hash : { *(.gnu.hash) } 9 | . = ALIGN(4096); 10 | .eh_frame : { *(.eh_frame) } 11 | .eh_frame_hdr : { *(.eh_frame_hdr) } 12 | .gcc_except_table : { *(.gcc_except_table*) } 13 | . = ALIGN(4096); 14 | .text : { 15 | _text = .; 16 | *(.text) 17 | *(.text.*) 18 | *(.gnu.linkonce.t.*) 19 | *(.plt) 20 | . = ALIGN(16); 21 | } 22 | _etext = .; 23 | _text_size = _etext - _text; 24 | . = ALIGN(65536); 25 | _DYNAMIC = .; 26 | .dynamic : { *(.dynamic) } 27 | . = ALIGN(4096); 28 | .data : { 29 | _data = .; 30 | *(.sdata) 31 | *(.data) 32 | *(.data1) 33 | *(.data.*) 34 | *(.got.plt) 35 | *(.got) 36 | . = ALIGN(16); 37 | __init_array_start = .; 38 | *(SORT(.init_array.*)) 39 | *(.init_array) 40 | __init_array_end = .; 41 | . = ALIGN(16); 42 | __CTOR_LIST__ = .; 43 | *(SORT(.ctors.*)) 44 | *(.ctors) 45 | __CTOR_END__ = .; 46 | . = ALIGN(16); 47 | __DTOR_LIST__ = .; 48 | *(SORT(.dtors.*)) 49 | *(.dtors) 50 | __DTOR_END__ = .; 51 | . = ALIGN(16); 52 | __fini_array_start = .; 53 | *(SORT(.fini_array.*)) 54 | *(.fini_array) 55 | __fini_array_end = .; 56 | . = ALIGN(16); 57 | _bss = .; 58 | *(.sbss) 59 | *(.scommon) 60 | *(.dynbss) 61 | *(.bss*) 62 | *(COMMON) 63 | *(.rel.local) 64 | . = ALIGN(16); 65 | _bss_end = .; 66 | } 67 | . = ALIGN(4096); 68 | .reloc : { 69 | KEEP (*(.reloc)) 70 | } 71 | . = ALIGN(4096); 72 | .rela : { 73 | *(.rela.text*) 74 | *(.rela.data*) 75 | *(.rela.got) 76 | *(.rela.dyn) 77 | *(.rela.stab) 78 | *(.rela.init_array*) 79 | *(.rela.fini_array*) 80 | *(.rela.ctors*) 81 | *(.rela.dtors*) 82 | } 83 | . = ALIGN(4096); 84 | .rela.plt : { *(.rela.plt) } 85 | . = ALIGN(4096); 86 | .rodata : { *(.rodata*) } 87 | . = ALIGN(512); 88 | _edata = .; 89 | _data_size = _edata - _data; 90 | . = ALIGN(4096); 91 | .dynsym : { *(.dynsym) } 92 | . = ALIGN(4096); 93 | .dynstr : { *(.dynstr) } 94 | . = ALIGN(4096); 95 | .note.gnu.build-id : { *(.note.gnu.build-id) } 96 | .ignored.reloc : { 97 | *(.rela.reloc) 98 | *(.note.GNU-stack) 99 | } 100 | .comment 0 : { *(.comment) } 101 | } 102 | -------------------------------------------------------------------------------- /efifetch/entry/efi-aarch64.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") 2 | OUTPUT_ARCH(aarch64) 3 | ENTRY(_start) 4 | SECTIONS 5 | { 6 | . = 0; 7 | ImageBase = .; 8 | .hash : { *(.hash) } 9 | .gnu.hash : { *(.gnu.hash) } 10 | . = ALIGN(4096); 11 | .eh_frame : { *(.eh_frame) } 12 | .eh_frame_hdr : { *(.eh_frame_hdr) } 13 | .gcc_except_table : { *(.gcc_except_table*) } 14 | . = ALIGN(4096); 15 | .text : { 16 | _text = .; 17 | *(.text) 18 | *(.text.*) 19 | *(.gnu.linkonce.t.*) 20 | *(.plt) 21 | . = ALIGN(16); 22 | } 23 | _etext = .; 24 | _text_size = _etext - _text; 25 | . = ALIGN(65536); 26 | .data : { 27 | _data = .; 28 | *(.sdata) 29 | *(.data) 30 | *(.data1) 31 | *(.data.*) 32 | *(.got.plt) 33 | *(.got) 34 | . = ALIGN(16); 35 | __init_array_start = .; 36 | *(SORT(.init_array.*)) 37 | *(.init_array) 38 | __init_array_end = .; 39 | . = ALIGN(16); 40 | __CTOR_LIST__ = .; 41 | *(SORT(.ctors.*)) 42 | *(.ctors) 43 | __CTOR_END__ = .; 44 | . = ALIGN(16); 45 | __DTOR_LIST__ = .; 46 | *(SORT(.dtors.*)) 47 | *(.dtors) 48 | __DTOR_END__ = .; 49 | . = ALIGN(16); 50 | __fini_array_start = .; 51 | *(SORT(.fini_array.*)) 52 | *(.fini_array) 53 | __fini_array_end = .; 54 | . = ALIGN(16); 55 | _bss = .; 56 | *(.sbss) 57 | *(.scommon) 58 | *(.dynbss) 59 | *(.bss*) 60 | *(COMMON) 61 | *(.rel.local) 62 | . = ALIGN(16); 63 | _bss_end = .; 64 | } 65 | . = ALIGN(4096); 66 | .reloc : { 67 | KEEP (*(.reloc)) 68 | } 69 | . = ALIGN(4096); 70 | _DYNAMIC = .; 71 | .dynamic : { *(.dynamic) } 72 | . = ALIGN(4096); 73 | .rela : { 74 | *(.rela.text*) 75 | *(.rela.data*) 76 | *(.rela.got) 77 | *(.rela.dyn) 78 | *(.rela.stab) 79 | *(.rela.init_array*) 80 | *(.rela.fini_array*) 81 | *(.rela.ctors*) 82 | *(.rela.dtors*) 83 | } 84 | . = ALIGN(4096); 85 | .rela.plt : { *(.rela.plt) } 86 | . = ALIGN(4096); 87 | .rodata : { *(.rodata*) } 88 | . = ALIGN(512); 89 | _edata = .; 90 | _data_size = _edata - _data; 91 | . = ALIGN(4096); 92 | .dynsym : { *(.dynsym) } 93 | . = ALIGN(4096); 94 | .dynstr : { *(.dynstr) } 95 | . = ALIGN(4096); 96 | .note.gnu.build-id : { *(.note.gnu.build-id) } 97 | .ignored.reloc : { 98 | *(.rela.reloc) 99 | *(.note.GNU-stack) 100 | } 101 | .comment 0 : { *(.comment) } 102 | } -------------------------------------------------------------------------------- /efifetch/info/mem.c: -------------------------------------------------------------------------------- 1 | #include"info.h" 2 | #include"str.h" 3 | #include"init.h" 4 | #include"print.h" 5 | #include"readable.h" 6 | 7 | static void load_from_memmap(efifetch*ctx){ 8 | uint32_t dv=0; 9 | char buff[32]; 10 | efi_status st; 11 | efi_memory_descriptor*mm=NULL,*md; 12 | uintn_t ms=0,mk=0,ds=sizeof(efi_memory_descriptor),size; 13 | if(!IS_EMPTY(MEMORY))return; 14 | do{ 15 | ms+=ds; 16 | if(mm)g_bs->free_pool(mm),mm=NULL; 17 | size=ms+(2*ds); 18 | st=g_bs->alloc_pool(efi_loader_data,size,(void**)&mm); 19 | if(efi_error(st)){ 20 | dbg_printf("alloc memmap failed: %m\n",st); 21 | break; 22 | } 23 | memset(mm,0,size); 24 | st=g_bs->get_mem_map(&ms,mm,&mk,&ds,&dv); 25 | }while(st==EFI_BUFFER_TOO_SMALL); 26 | if(efi_error(st)){ 27 | dbg_printf("get memmap failed: %m\n",st); 28 | return; 29 | } 30 | dbg_printf("memmap size %zu ptr %p key %zu desc size %zu desc ver %u\n",ms,mm,mk,ds,dv); 31 | if(ds!=sizeof(efi_memory_descriptor)){ 32 | dbg_printf("memmap desc size mismatch: %zu != %zu\n",ds,sizeof(efi_memory_descriptor)); 33 | } 34 | uint64_t total=0,avail=0; 35 | for(md=mm;(void*)md<(void*)mm+ms;md=(void*)md+ds)switch(md->type){ 36 | case efi_conventional_memory: 37 | avail+=md->pages*EFI_PAGE_SIZE; 38 | //fallthrough 39 | case efi_loader_code: 40 | case efi_loader_data: 41 | case efi_bs_code: 42 | case efi_bs_data: 43 | case efi_rs_code: 44 | case efi_rs_data: 45 | case efi_acpi_reclaim_memory: 46 | case efi_acpi_memory_nvs: 47 | case efi_pal_code: 48 | total+=md->pages*EFI_PAGE_SIZE; 49 | //fallthrough 50 | default:dbg_printf( 51 | "memmap item phy 0x%012zx virt 0x%012zx " 52 | "size %llu pages (%s) type %s attrs 0x%llx\n", 53 | md->physical_start.uintn,md->virtual_start.uintn,md->pages, 54 | format_size_float(buff,md->pages*EFI_PAGE_SIZE), 55 | efi_memory_type_to_string(md->type),md->attribute 56 | ); 57 | } 58 | g_bs->free_pool(mm); 59 | if(total==0){ 60 | dbg_print("skip empty memmap\n"); 61 | return; 62 | } 63 | uint64_t used=total-avail; 64 | char buf_used[32],buf_total[32]; 65 | if(!format_size_float(buf_used,used)){ 66 | dbg_print("memmap format size used failed\n"); 67 | return; 68 | } 69 | if(!format_size_float(buf_total,total)){ 70 | dbg_print("memmap format size total failed\n"); 71 | return; 72 | } 73 | uint64_t percent=used*100/total; 74 | if(percent>100)percent=100; 75 | SETF( 76 | MEMORY, 77 | "%s / %s (%llu%c)", 78 | buf_used,buf_total,percent,'%' 79 | ); 80 | } 81 | 82 | void efifetch_load_info_mem(efifetch*ctx){ 83 | load_from_memmap(ctx); 84 | } 85 | -------------------------------------------------------------------------------- /efifetch/info/fs.c: -------------------------------------------------------------------------------- 1 | #include"info.h" 2 | #include"init.h" 3 | #include"print.h" 4 | #include"str.h" 5 | #include"utils.h" 6 | #include"readable.h" 7 | 8 | static efi_file_system_info*find_cur_fs_info(void){ 9 | return efi_get_fs_info(efi_get_current_fs()); 10 | } 11 | 12 | static efi_file_system_info*find_largest_fs_info(void){ 13 | efi_status st; 14 | uintn_t hand_cnt=0,max=0; 15 | efi_handle*hands=NULL; 16 | efi_file_system_info**infos=NULL,*ret=NULL; 17 | st=g_bs->locate_handle_buffer( 18 | search_by_protocol, 19 | &gEfiSimpleFileSystemProtocolGuid, 20 | NULL,&hand_cnt,&hands 21 | ); 22 | if(efi_error(st)||!hands){ 23 | dbg_printf("locate fs handle failed: %m\n",st); 24 | return NULL; 25 | } 26 | for(uintn_t i=0;ihandle_proto(hands[i],&gEfiSimpleFileSystemProtocolGuid,(void**)&fs); 29 | if(efi_error(st)||!fs){ 30 | dbg_printf("handle fs %p failed: %m\n",hands[i],st); 31 | continue; 32 | } 33 | infos[i]=efi_get_fs_info(fs); 34 | if(!infos[i])continue; 35 | max=MAX(max,infos[i]->vol_size); 36 | } 37 | for(uintn_t i=0;ivol_size!=max)continue; 40 | ret=infos[i]; 41 | infos[i]=NULL; 42 | break; 43 | } 44 | if(infos){ 45 | if(hand_cnt>0)for(uintn_t i=0;ifree_pool(infos[i]); 48 | g_bs->free_pool(infos); 49 | } 50 | if(hands)g_bs->free_pool(hands); 51 | return ret; 52 | } 53 | 54 | static efi_file_system_info*find_first_fs_info(void){ 55 | efi_status st; 56 | efi_simple_file_system_protocol*fs=NULL; 57 | st=g_bs->locate_proto(&gEfiSimpleFileSystemProtocolGuid,NULL,(void**)&fs); 58 | if(efi_error(st)||!fs){ 59 | dbg_printf("locate first fs failed: %m\n",st); 60 | return NULL; 61 | } 62 | return efi_get_fs_info(fs); 63 | } 64 | 65 | void efifetch_load_info_fs(efifetch*ctx){ 66 | efi_file_system_info*info; 67 | if(!IS_EMPTY(FILESYSTEM))return; 68 | info=find_cur_fs_info(); 69 | if(!info)info=find_largest_fs_info(); 70 | if(!info)info=find_first_fs_info(); 71 | char buf_used[32],buf_total[32]; 72 | uint64_t total=info->vol_size; 73 | uint64_t avail=info->free_space; 74 | g_bs->free_pool(info); 75 | uint64_t used=total-avail; 76 | if(!format_size_float(buf_used,used)){ 77 | dbg_print("filesystem format size used failed\n"); 78 | return; 79 | } 80 | if(!format_size_float(buf_total,total)){ 81 | dbg_print("filesystem format size used failed\n"); 82 | return; 83 | } 84 | uint64_t percent=used*100/total; 85 | if(percent>100)percent=100; 86 | SETF( 87 | FILESYSTEM, 88 | "%s / %s (%llu%c)", 89 | buf_used,buf_total,percent,'%' 90 | ); 91 | } 92 | -------------------------------------------------------------------------------- /efifetch/libfdt/fdt_addresses.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2014 David Gibson 5 | * Copyright (C) 2018 embedded brains GmbH 6 | */ 7 | #include "libfdt_env.h" 8 | 9 | #include "fdt.h" 10 | #include "libfdt.h" 11 | 12 | #include "libfdt_internal.h" 13 | 14 | static int fdt_cells(const void *fdt, int nodeoffset, const char *name) 15 | { 16 | const fdt32_t *c; 17 | uint32_t val; 18 | int len; 19 | 20 | c = fdt_getprop(fdt, nodeoffset, name, &len); 21 | if (!c) 22 | return len; 23 | 24 | if (len != sizeof(*c)) 25 | return -FDT_ERR_BADNCELLS; 26 | 27 | val = fdt32_to_cpu(*c); 28 | if (val > FDT_MAX_NCELLS) 29 | return -FDT_ERR_BADNCELLS; 30 | 31 | return (int)val; 32 | } 33 | 34 | int fdt_address_cells(const void *fdt, int nodeoffset) 35 | { 36 | int val; 37 | 38 | val = fdt_cells(fdt, nodeoffset, "#address-cells"); 39 | if (val == 0) 40 | return -FDT_ERR_BADNCELLS; 41 | if (val == -FDT_ERR_NOTFOUND) 42 | return 2; 43 | return val; 44 | } 45 | 46 | int fdt_size_cells(const void *fdt, int nodeoffset) 47 | { 48 | int val; 49 | 50 | val = fdt_cells(fdt, nodeoffset, "#size-cells"); 51 | if (val == -FDT_ERR_NOTFOUND) 52 | return 1; 53 | return val; 54 | } 55 | 56 | /* This function assumes that [address|size]_cells is 1 or 2 */ 57 | int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, 58 | const char *name, uint64_t addr, uint64_t size) 59 | { 60 | int addr_cells, size_cells, ret; 61 | uint8_t data[sizeof(fdt64_t) * 2], *prop; 62 | 63 | ret = fdt_address_cells(fdt, parent); 64 | if (ret < 0) 65 | return ret; 66 | addr_cells = ret; 67 | 68 | ret = fdt_size_cells(fdt, parent); 69 | if (ret < 0) 70 | return ret; 71 | size_cells = ret; 72 | 73 | /* check validity of address */ 74 | prop = data; 75 | if (addr_cells == 1) { 76 | if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size)) 77 | return -FDT_ERR_BADVALUE; 78 | 79 | fdt32_st(prop, (uint32_t)addr); 80 | } else if (addr_cells == 2) { 81 | fdt64_st(prop, addr); 82 | } else { 83 | return -FDT_ERR_BADNCELLS; 84 | } 85 | 86 | /* check validity of size */ 87 | prop += addr_cells * sizeof(fdt32_t); 88 | if (size_cells == 1) { 89 | if (size > UINT32_MAX) 90 | return -FDT_ERR_BADVALUE; 91 | 92 | fdt32_st(prop, (uint32_t)size); 93 | } else if (size_cells == 2) { 94 | fdt64_st(prop, size); 95 | } else { 96 | return -FDT_ERR_BADNCELLS; 97 | } 98 | 99 | return fdt_appendprop(fdt, nodeoffset, name, data, 100 | (addr_cells + size_cells) * sizeof(fdt32_t)); 101 | } 102 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | O ?= build 2 | ARCH ?= $(shell $(CC) -dumpmachine | cut -d- -f1) 3 | EDK2_PATH ?= edk2 4 | EDK2_TARGET ?= RELEASE 5 | EDK2_TOOLCHAIN ?= GCC5 6 | EDK_TOOLS_PATH ?= $(EDK2_PATH)/BaseTools 7 | PACKAGES_PATH ?= $(EDK2_PATH)/edk2:$(PWD) 8 | X_CCFLAGS = \ 9 | -g -Iefifetch/include \ 10 | -nostdlib -nodefaultlibs -nolibc -nostdinc \ 11 | -O3 -Wall -Wextra -Werror -Werror=stack-usage=4096 \ 12 | -fpic -ffreestanding -fstack-protector -fno-stack-check \ 13 | -fshort-wchar -fno-builtin -fno-common -fno-strict-aliasing \ 14 | -fdata-sections -ffunction-sections -mgeneral-regs-only \ 15 | -fno-jump-tables \ 16 | -mstack-protector-guard=global \ 17 | -Wno-sign-compare -Wno-unused-parameter 18 | X_LDFLAGS = \ 19 | -g -shared -Bsymbolic --no-undefined \ 20 | -Tefifetch/entry/efi-$(ARCH).lds 21 | X_LIBS = 22 | X_COPYFLAGS = \ 23 | -j .text -j .sdata -j .data -j .rodata -j .dynamic -j .dynsym \ 24 | -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc \ 25 | --subsystem=10 26 | ifeq ($(CROSS_COMPILE),) 27 | CC ?= gcc 28 | LD ?= ld 29 | OBJCOPY ?= objcopy 30 | STRIP ?= strip 31 | else 32 | CC := $(CROSS_COMPILE)gcc 33 | LD := $(CROSS_COMPILE)ld 34 | OBJCOPY := $(CROSS_COMPILE)objcopy 35 | STRIP := $(CROSS_COMPILE)strip 36 | endif 37 | ifeq ($(ARCH),x86_64) 38 | X_COPYFLAGS += --target pei-x86-64 39 | X_CCFLAGS += -mno-red-zone -maccumulate-outgoing-args -mcmodel=small 40 | EDK2_ARCH = X64 41 | else ifeq ($(ARCH),aarch64) 42 | X_COPYFLAGS += --target pei-aarch64-little 43 | X_CCFLAGS += -ffixed-x18 -mstrict-align -mcmodel=small 44 | EDK2_ARCH = AARCH64 45 | else ifeq ($(ARCH),riscv64) 46 | X_COPYFLAGS += --target pei-riscv64-little 47 | EDK2_ARCH = RISCV64 48 | else ifeq ($(ARCH),i386) 49 | X_COPYFLAGS += --target pei-i386 50 | X_CCFLAGS += -m32 -malign-double 51 | X_LDFLAGS += -m elf_i386 52 | X_LIBS += $(shell $(CC) $(X_CCFLAGS) -print-libgcc-file-name) 53 | EDK2_ARCH = IA32 54 | else 55 | $(error Unsupported architecture: $(ARCH)) 56 | endif 57 | 58 | include efifetch/objs.mk 59 | 60 | all: $(O)/efifetch.efi 61 | 62 | -include $(O)/*.deps 63 | -include $(O)/*/*.deps 64 | 65 | $(O)/%.c.o: efifetch/%.c 66 | @mkdir -p $(@D) 67 | $(CC) -MMD -MF $@.deps $(X_CCFLAGS) -c $< -o $@ 68 | 69 | $(O)/%.S.o: efifetch/%.S 70 | @mkdir -p $(@D) 71 | $(CC) -MMD -MF $@.deps -DASM $(X_CCFLAGS) -c $< -o $@ 72 | 73 | $(O)/efifetch.so: $(OBJS) 74 | @mkdir -p $(@D) 75 | $(LD) $(X_LDFLAGS) $^ $(X_LIBS) -o $@ 76 | 77 | $(O)/efifetch.efi: $(O)/efifetch.so 78 | @mkdir -p $(@D) 79 | $(OBJCOPY) $(X_COPYFLAGS) $^ $@ 80 | $(STRIP) $@ 81 | 82 | clean: 83 | find $(O) -type f -name '*.o' -delete 84 | find $(O) -type f -name '*.deps' -delete 85 | rm -f $(O)/efifetch.so 86 | rm -f $(O)/efifetch.efi 87 | 88 | build-edk2: 89 | source $(EDK2_PATH)/edksetup.sh; \ 90 | $(MAKE) -C $(EDK_TOOLS_PATH); \ 91 | build \ 92 | -a $(EDK2_ARCH) \ 93 | -t $(EDK2_TOOLCHAIN) \ 94 | -b $(EDK2_TARGET) \ 95 | -p efifetch/efifetch.dsc 96 | 97 | .PHONY: all clean build-edk2 98 | -------------------------------------------------------------------------------- /efifetch/lib/print.c: -------------------------------------------------------------------------------- 1 | #define STB_SPRINTF_NOFLOAT 2 | #include"efi.h" 3 | #include"str.h" 4 | #include"init.h" 5 | #include"print.h" 6 | #include"stb_sprintf.h" 7 | 8 | efi_status text_printn( 9 | efi_simple_text_output_protocol*con, 10 | const char*str,size_t len 11 | ){ 12 | if(!con||!str)return efi_invalid_parameter; 13 | efi_status st=efi_success; 14 | char16 buffer[128]={}; 15 | while(len>0){ 16 | encode_convert_ctx ctx={}; 17 | ctx.in.src=ENC_UTF8; 18 | ctx.in.dst=ENC_UTF16; 19 | ctx.in.src_ptr=(void*)str; 20 | ctx.in.src_size=len; 21 | ctx.in.dst_ptr=buffer; 22 | ctx.in.dst_size=sizeof(buffer)-2; 23 | ctx.in.allow_invalid=true; 24 | ctx.in.transfers=NULL; 25 | st=encode_convert(&ctx); 26 | if(efi_error(st))break; 27 | if(ctx.out.dst_wrote==0)break; 28 | buffer[sizeof(buffer)/sizeof(char16)-1]=0; 29 | st=con->output_string(con,buffer); 30 | if(efi_error(st))break; 31 | str=(const char*)ctx.out.src_end; 32 | len-=ctx.out.src_used; 33 | } 34 | return st; 35 | } 36 | 37 | efi_status text_print( 38 | efi_simple_text_output_protocol*con, 39 | const char*str 40 | ){ 41 | if(!con||!str)return efi_invalid_parameter; 42 | return text_printn(con,str,strlen(str)+1); 43 | } 44 | 45 | efi_status text_print_repeat( 46 | efi_simple_text_output_protocol*con, 47 | char ch,uintn_t cnt 48 | ){ 49 | uintn_t i; 50 | efi_status status=efi_success; 51 | char16 buffer[128]; 52 | if(!con)return efi_invalid_parameter; 53 | if(cnt>0)do{ 54 | for(i=0;cnt>0&&ioutput_string(con,buffer); 58 | }while(cnt>0&&!efi_error(status)); 59 | return status; 60 | } 61 | 62 | struct printf_context{ 63 | char buff[STB_SPRINTF_MIN*3/2]; 64 | efi_simple_text_output_protocol*con; 65 | efi_status status; 66 | }; 67 | 68 | static char*printf_callback(const char*buf,void*user,int len){ 69 | struct printf_context*ctx=user; 70 | ctx->status=text_print(ctx->con,buf); 71 | return efi_error(ctx->status)?NULL:ctx->buff; 72 | } 73 | 74 | efi_status text_vprintf( 75 | efi_simple_text_output_protocol*con, 76 | const char*str,va_list va 77 | ){ 78 | struct printf_context ctx={ 79 | .con=con, 80 | .status=efi_success, 81 | }; 82 | if(!con||!str)return efi_invalid_parameter; 83 | stbsp_vsprintfcb(printf_callback,&ctx,ctx.buff,str,va); 84 | return ctx.status; 85 | } 86 | 87 | efi_status text_printf( 88 | efi_simple_text_output_protocol*con, 89 | const char*str, 90 | ... 91 | ){ 92 | va_list va; 93 | va_start(va,str); 94 | efi_status st=text_vprintf(con,str,va); 95 | va_end(va); 96 | return st; 97 | } 98 | 99 | void print_init(){ 100 | if(!g_st)return; 101 | extern uintn_t con_stdout_def_attr; 102 | extern uintn_t con_stderr_def_attr; 103 | if(stdout) 104 | con_stdout_def_attr=stdout->mode->attribute.num; 105 | if(stderr) 106 | con_stderr_def_attr=stderr->mode->attribute.num; 107 | } 108 | -------------------------------------------------------------------------------- /efifetch/info/cpuid.c: -------------------------------------------------------------------------------- 1 | #include"info.h" 2 | #include"data.h" 3 | #include"arm64.h" 4 | #include"print.h" 5 | #include"str.h" 6 | 7 | #if defined (__aarch64__) 8 | static void efifetch_load_info_cpuid_arch(efifetch*ctx){ 9 | midr_data midr={}; 10 | current_el_data el={}; 11 | asm volatile("mrs %0,midr_el1":"=r"(midr.value)); 12 | asm volatile("mrs %0,CurrentEL":"=r"(el.value)); 13 | dbg_printf("midr: 0x%016llx\n",midr.value); 14 | const arm_cpuid_item*impl=NULL,*part=NULL; 15 | for(uintn_t i=0;arm_cpuid_items[i].name;i++){ 16 | if(arm_cpuid_items[i].implementer!=midr.Implementer)continue; 17 | if(arm_cpuid_items[i].part==0xFFFF){ 18 | impl=&arm_cpuid_items[i]; 19 | dbg_printf("found arm64 cpuid implementer %s\n",impl->name); 20 | }else if(arm_cpuid_items[i].part==midr.PartNum){ 21 | part=&arm_cpuid_items[i]; 22 | dbg_printf("found arm64 cpuid part %s\n",part->name); 23 | } 24 | if(impl&&part)break; 25 | } 26 | if(impl)SET(CPUID,impl->name); 27 | else SETF(CPUID,"implementer 0x%02x",midr.Implementer); 28 | if(!IS_EMPTY(CPUID))APPEND(CPUID," "); 29 | if(part)APPEND(CPUID,part->name); 30 | else APPENDF(CPUID,"part 0x%04x",midr.PartNum); 31 | if(midr.Revision>0){ 32 | if(!IS_EMPTY(CPUID))APPEND(CPUID," "); 33 | APPENDF(CPUID,"rev %u",midr.Revision); 34 | } 35 | if(!IS_EMPTY(CPUID))APPEND(CPUID," "); 36 | APPENDF(CPUID,"(EL%u)",el.EL); 37 | } 38 | 39 | #elif defined(__x86_64__) || defined(__i386__) 40 | 41 | static void read_cpuid_brand(char*buff,size_t len){ 42 | if(!buff||len<64)return; 43 | memset(buff,0,len); 44 | uint32_t cmd=0x80000002; 45 | for(uint32_t i=0;i<3;i++){ 46 | uint32_t eax=0,ebx=0,ecx=0,edx=0; 47 | asm volatile( 48 | "cpuid":"=a"(eax),"=b"(ebx), 49 | "=c"(ecx),"=d"(edx):"a"(cmd) 50 | ); 51 | memcpy(&buff[i*16+0],&eax,4); 52 | memcpy(&buff[i*16+4],&ebx,4); 53 | memcpy(&buff[i*16+8],&ecx,4); 54 | memcpy(&buff[i*16+12],&edx,4); 55 | cmd++; 56 | } 57 | } 58 | 59 | static void efifetch_load_info_cpuid_arch(efifetch*ctx){ 60 | char buff[64]={}; 61 | read_cpuid_brand(buff,sizeof(buff)); 62 | if(buff[0]){ 63 | if(!IS_EMPTY(CPUID))APPEND(CPUID," "); 64 | trim(buff); 65 | APPENDN(CPUID,buff,sizeof(buff)); 66 | } 67 | } 68 | 69 | #else 70 | 71 | static void efifetch_load_info_cpuid_arch(efifetch*ctx){} 72 | 73 | #endif 74 | 75 | static void efifetch_load_info_arch(efifetch*ctx){ 76 | const char*arch=NULL; 77 | #if defined(__i386__) 78 | arch="x86"; 79 | #elif defined(__x86_64__) 80 | arch="x86_64"; 81 | #elif defined(__aarch64__) 82 | arch="ARM64"; 83 | #elif defined(__arm__) 84 | arch="ARM32"; 85 | #elif defined(__riscv__) 86 | arch="RISC-V"; 87 | #elif defined(__mips__) 88 | arch="MIPS"; 89 | #elif defined(__loongarch__) 90 | arch="LoongArch"; 91 | #else 92 | arch="Unknown"; 93 | #endif 94 | SETF(ARCH,"%s (%ubits)",arch,sizeof(void*)*8); 95 | } 96 | 97 | void efifetch_load_info_cpuid(efifetch*ctx){ 98 | if(IS_EMPTY(CPUID)){ 99 | RESET(CPUID); 100 | efifetch_load_info_cpuid_arch(ctx); 101 | } 102 | if(IS_EMPTY(ARCH)){ 103 | RESET(ARCH); 104 | efifetch_load_info_arch(ctx); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /efifetch/include/info.h: -------------------------------------------------------------------------------- 1 | #ifndef INFO_H 2 | #define INFO_H 3 | #include"efi.h" 4 | #include"efifetch.h" 5 | extern void efifetch_init_info_fdt(efifetch*ctx); 6 | extern void efifetch_init_info_smbios(efifetch*ctx); 7 | extern void efifetch_load_info(efifetch*ctx); 8 | extern void efifetch_load_info_gpu(efifetch*ctx); 9 | extern void efifetch_load_info_mem(efifetch*ctx); 10 | extern void efifetch_load_info_smbios(efifetch*ctx); 11 | extern void efifetch_load_info_sys(efifetch*ctx); 12 | extern void efifetch_load_info_fdt(efifetch*ctx); 13 | extern void efifetch_load_info_net(efifetch*ctx); 14 | extern void efifetch_load_info_fs(efifetch*ctx); 15 | extern void efifetch_load_info_time(efifetch*ctx); 16 | extern void efifetch_load_info_disk(efifetch*ctx); 17 | extern void efifetch_load_info_cpuid(efifetch*ctx); 18 | extern smbios_structure_pointer efifetch_get_smbios_by_type(efifetch*ctx,uint8_t type,smbios_handle handle); 19 | extern smbios_structure_pointer efifetch_get_smbios_by_handle(efifetch*ctx,smbios_handle handle); 20 | extern const char*efifetch_get_smbios_string(efifetch*ctx,smbios_structure_pointer p,smbios_table_string id); 21 | extern bool efifetch_load_smbios_string(efifetch*ctx,smbios_structure_pointer p,smbios_table_string id,char*buff,size_t size); 22 | extern bool efifetch_field_is_empty(efifetch*ctx,enum efifetch_field field); 23 | extern void efifetch_field_reset(efifetch*ctx,enum efifetch_field field); 24 | extern void efifetch_field_set(efifetch*ctx,enum efifetch_field field,const char*value); 25 | extern void efifetch_field_setn(efifetch*ctx,enum efifetch_field field,const char*value,size_t len); 26 | extern void efifetch_field_setf(efifetch*ctx,enum efifetch_field field,const char*fmt,...); 27 | extern void efifetch_field_append(efifetch*ctx,enum efifetch_field field,const char*value); 28 | extern void efifetch_field_appendn(efifetch*ctx,enum efifetch_field field,const char*value,size_t len); 29 | extern void efifetch_field_appendf(efifetch*ctx,enum efifetch_field field,const char*fmt,...); 30 | #define SMBIOS_GET(_ptr,_type,_field,_def)({\ 31 | smbios_structure_pointer _p=(_ptr);\ 32 | uintn_t _min_len=offsetof(smbios_table_type##_type,_field)+sizeof(_p.type##_type->_field);\ 33 | _p.header->length>_min_len?_p.type##_type->_field:(_def);\ 34 | }) 35 | #define SMBIOS_VARX(_name,_ptr,_type,_field,_def)\ 36 | typeof((_ptr).type##_type->_field) _name=SMBIOS_GET(_ptr,_type,_field,_def) 37 | #define SMBIOS_VAR(_ptr,_type,_field,_def) SMBIOS_VARX(_field,_ptr,_type,_field,_def) 38 | #define IS_EMPTY(_type) efifetch_field_is_empty(ctx,EFIFETCH_FIELD_##_type) 39 | #define SET(_type,_value) efifetch_field_set(ctx,EFIFETCH_FIELD_##_type,_value) 40 | #define SETN(_type,_value,_len) efifetch_field_setn(ctx,EFIFETCH_FIELD_##_type,_value,_len) 41 | #define SETF(_type,_value...) efifetch_field_setf(ctx,EFIFETCH_FIELD_##_type,_value) 42 | #define APPEND(_type,_value) efifetch_field_append(ctx,EFIFETCH_FIELD_##_type,_value) 43 | #define APPENDN(_type,_value,_len) efifetch_field_appendn(ctx,EFIFETCH_FIELD_##_type,_value,_len) 44 | #define APPENDF(_type,_value...) efifetch_field_appendf(ctx,EFIFETCH_FIELD_##_type,_value) 45 | #define RESET(_type) efifetch_field_reset(ctx,EFIFETCH_FIELD_##_type) 46 | #endif 47 | -------------------------------------------------------------------------------- /efifetch/lib/utils.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"init.h" 3 | #include"print.h" 4 | #include"utils.h" 5 | #include"str.h" 6 | 7 | efi_loaded_image_protocol*efi_get_loaded_image(void){ 8 | efi_status st; 9 | efi_loaded_image_protocol*li=NULL; 10 | st=g_bs->handle_proto(g_ih,&gEfiLoadedImageProtocolGuid,(void**)&li); 11 | if(efi_error(st))return NULL; 12 | return li; 13 | } 14 | 15 | efi_handle efi_get_current_device(void){ 16 | efi_loaded_image_protocol*li=efi_get_loaded_image(); 17 | return li?li->device_handle:NULL; 18 | } 19 | 20 | efi_device_path_protocol*efi_device_path_next(efi_device_path_protocol*dp){ 21 | if(!dp||dp->length==0)return NULL; 22 | efi_device_path_protocol*next_dp=(void*)dp+dp->length; 23 | if(next_dp->length==0)return NULL; 24 | return next_dp; 25 | } 26 | 27 | uintn_t efi_device_path_len(efi_device_path_protocol*dp){ 28 | uintn_t dp_len=0; 29 | if(dp)do{ 30 | dp_len+=dp->length; 31 | if(dp->type==0x7f)break; 32 | }while((dp=efi_device_path_next(dp))); 33 | return dp_len; 34 | } 35 | 36 | uintn_t efi_device_path_count(efi_device_path_protocol*dp){ 37 | uintn_t cnt=0; 38 | if(dp)do{ 39 | if(dp->type==0x7f)break; 40 | cnt++; 41 | }while((dp=efi_device_path_next(dp))); 42 | return cnt; 43 | } 44 | 45 | efi_handle efi_get_parent_device(efi_handle handle){ 46 | efi_status st; 47 | efi_device_path_protocol*dp=NULL; 48 | if(!handle)return NULL; 49 | st=g_bs->handle_proto(handle,&gEfiDevicePathProtocolGuid,(void**)&dp); 50 | if(efi_error(st)||!dp)return NULL; 51 | uintn_t dp_len=0,cnt=0; 52 | dp_len=efi_device_path_len(dp); 53 | cnt=efi_device_path_count(dp); 54 | if(cnt<=1)return NULL; 55 | efi_device_path_protocol*par_dp=NULL; 56 | if(!(par_dp=memdup(dp,dp_len)))return NULL; 57 | efi_device_path_protocol*last_dp=NULL,*next_dp=NULL; 58 | last_dp=par_dp; 59 | while(true){ 60 | next_dp=efi_device_path_next(last_dp); 61 | if(!next_dp||next_dp->type==0x7f){ 62 | last_dp->type=0x7f; 63 | last_dp->sub_type=0xff; 64 | last_dp->length=sizeof(efi_device_path_protocol); 65 | break; 66 | } 67 | last_dp=next_dp; 68 | } 69 | efi_handle parent=NULL; 70 | efi_device_path_protocol*loc_dp=par_dp; 71 | st=g_bs->locate_device_path(&gEfiDevicePathProtocolGuid,&loc_dp,&parent); 72 | free(par_dp); 73 | if(efi_error(st)||!parent)return NULL; 74 | if(parent==handle)return NULL; 75 | return parent; 76 | } 77 | 78 | void*efi_file_get_info_by(efi_file_protocol*f,const efi_guid*guid){ 79 | void*info=NULL; 80 | uintn_t size=0; 81 | efi_status st; 82 | if(!f||!guid)return NULL; 83 | st=f->get_info(f,guid,&size,NULL); 84 | if(st!=EFI_BUFFER_TOO_SMALL||size==0)return NULL; 85 | st=g_bs->alloc_pool(efi_loader_data,size,(void**)&info); 86 | if(efi_error(st)||!info)return NULL; 87 | st=f->get_info(f,guid,&size,info); 88 | if(efi_error(st)){ 89 | g_bs->free_pool(info); 90 | return NULL; 91 | } 92 | return info; 93 | } 94 | 95 | efi_file_system_info*efi_get_fs_info(efi_simple_file_system_protocol*fs){ 96 | efi_status st; 97 | efi_file_protocol*root=NULL; 98 | efi_file_system_info*info=NULL; 99 | if(!fs)return NULL; 100 | st=fs->open_volume(fs,&root); 101 | if(efi_error(st)||!root)return NULL; 102 | info=efi_file_get_info_by(root,&gEfiFileSystemInfoGuid); 103 | if(root)root->close(root); 104 | return info; 105 | } 106 | 107 | efi_simple_file_system_protocol*efi_get_current_fs(void){ 108 | efi_status st; 109 | efi_simple_file_system_protocol*fs=NULL; 110 | efi_handle dev=efi_get_current_device(); 111 | if(!dev)return NULL; 112 | st=g_bs->handle_proto(dev,&gEfiSimpleFileSystemProtocolGuid,(void**)&fs); 113 | if(efi_error(st)||!fs)return NULL; 114 | return fs; 115 | } 116 | -------------------------------------------------------------------------------- /efifetch/info/time.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"info.h" 3 | #include"print.h" 4 | #include"init.h" 5 | 6 | static void fill_seconds(efifetch*ctx,uint64_t uptime_sec){ 7 | uint64_t uptime_xsec=uptime_sec%60; 8 | uint64_t uptime_min=uptime_sec/60,uptime_xmin=uptime_min%60; 9 | uint64_t uptime_hour=uptime_min/60,uptime_xhour=uptime_hour%24; 10 | uint64_t uptime_day=uptime_hour/24,uptime_xday=uptime_day%30; 11 | uint64_t uptime_month=uptime_day/30,uptime_xmonth=uptime_month%12; 12 | uint64_t uptime_year=uptime_month/12,uptime_xyear=uptime_year; 13 | RESET(UPTIME); 14 | if(uptime_xsec>0)SETF(UPTIME,"%llu secs",uptime_xsec); 15 | if(uptime_xmin>0){ 16 | if(!IS_EMPTY(UPTIME))APPEND(UPTIME,", "); 17 | APPENDF(UPTIME,"%llu mins",uptime_xmin); 18 | } 19 | if(uptime_xhour>0){ 20 | if(!IS_EMPTY(UPTIME))APPEND(UPTIME,", "); 21 | APPENDF(UPTIME,"%llu hours",uptime_xhour); 22 | } 23 | if(uptime_xday>0){ 24 | if(!IS_EMPTY(UPTIME))APPEND(UPTIME,", "); 25 | APPENDF(UPTIME,"%llu days",uptime_xday); 26 | } 27 | if(uptime_xmonth>0){ 28 | if(!IS_EMPTY(UPTIME))APPEND(UPTIME,", "); 29 | APPENDF(UPTIME,"%llu months",uptime_xmonth); 30 | } 31 | if(uptime_xyear>0){ 32 | if(!IS_EMPTY(UPTIME))APPEND(UPTIME,", "); 33 | APPENDF(UPTIME,"%llu years",uptime_xyear); 34 | } 35 | } 36 | 37 | #if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) 38 | static inline uint64_t rd_timer(void){ 39 | uint64_t val=0; 40 | #if defined(__x86_64__) || defined(__i386__) 41 | uint32_t hi=0,lo=0; 42 | asm volatile("rdtsc":"=a"(lo),"=d"(hi)); 43 | val=((uint64_t)lo)|(((uint64_t)hi)<<32); 44 | #define TIMER_TYPE "x86 tsc" 45 | #elif defined(__aarch64__) 46 | asm volatile("mrs %0, cntvct_el0":"=r"(val)); 47 | #define TIMER_TYPE "arm64 cntvct" 48 | #else 49 | #error no timer backend found 50 | #endif 51 | return val; 52 | } 53 | 54 | static uint64_t timer_calc_ms(uint64_t period){ 55 | uint64_t start,end,ret; 56 | start=rd_timer(); 57 | g_bs->stall(period*1000); 58 | end=rd_timer(); 59 | ret=(end-start)/period; 60 | dbg_printf( 61 | TIMER_TYPE" calib %llu ms: %llu MHz\n", 62 | (unsigned long long)period, 63 | (unsigned long long)ret/1000 64 | ); 65 | return ret; 66 | } 67 | 68 | static uint64_t timer_calib(){ 69 | uint64_t ct=0,calib=0; 70 | dbg_printf("starting calibrate "TIMER_TYPE" timer\n"); 71 | ct++,calib+=timer_calc_ms(50); 72 | ct++,calib+=timer_calc_ms(20); 73 | ct++,calib+=timer_calc_ms(100); 74 | ct++,calib+=timer_calc_ms(10); 75 | ct++,calib+=timer_calc_ms(80); 76 | calib/=ct; 77 | dbg_printf( 78 | TIMER_TYPE" calib freq: %llu MHz\n", 79 | (unsigned long long)calib/1000 80 | ); 81 | if(calib<=0)dbg_printf("bad timer "TIMER_TYPE"\n"); 82 | return calib; 83 | } 84 | 85 | static uint64_t tick_get_ms(void){ 86 | static bool inited=false; 87 | static uint64_t calib=0; 88 | if(!inited)inited=true,calib=timer_calib(); 89 | if(calib<=0)return 0; 90 | return rd_timer()/calib; 91 | } 92 | 93 | static void fill_arch_timer(efifetch*ctx){ 94 | if(!IS_EMPTY(UPTIME))return; 95 | uint64_t ms=tick_get_ms(); 96 | if(ms<=0)return; 97 | fill_seconds(ctx,ms/1000); 98 | } 99 | 100 | #else 101 | 102 | static void fill_arch_timer(efifetch*ctx){} 103 | 104 | #endif 105 | 106 | static void fill_timestamp_proto(efifetch*ctx){ 107 | efi_status st; 108 | efi_timestamp_protocol*ts=NULL; 109 | efi_timestamp_properties prop={}; 110 | if(!IS_EMPTY(UPTIME))return; 111 | st=g_bs->locate_proto( 112 | &gEfiTimestampProtocolGuid, 113 | NULL,(void**)&ts 114 | ); 115 | if(efi_error(st)){ 116 | dbg_printf("locate timestamp protocol failed: %m\n",st); 117 | return; 118 | } 119 | st=ts->get_properties(&prop); 120 | if(efi_error(st)){ 121 | dbg_printf("get timestamp properties failed: %m\n",st); 122 | return; 123 | } 124 | uint64_t uptime_tick=ts->get_timestamp(); 125 | fill_seconds(ctx,uptime_tick/prop.frequency); 126 | } 127 | 128 | void efifetch_load_info_time(efifetch*ctx){ 129 | if(!IS_EMPTY(UPTIME))return; 130 | fill_timestamp_proto(ctx); 131 | fill_arch_timer(ctx); 132 | } 133 | -------------------------------------------------------------------------------- /efifetch/info/gpu.c: -------------------------------------------------------------------------------- 1 | #include"data.h" 2 | #include"info.h" 3 | #include"init.h" 4 | #include"str.h" 5 | #include"print.h" 6 | #include"pci.h" 7 | #include"utils.h" 8 | 9 | static void load_display(efifetch*ctx,efi_handle hand){ 10 | efi_status st; 11 | efi_graphics_output_protocol*gop=NULL; 12 | if(!IS_EMPTY(DISPLAY))return; 13 | st=hand?g_bs->handle_proto( 14 | hand,&gEfiGraphicsOutputProtocolGuid,(void**)&gop 15 | ):g_bs->locate_proto( 16 | &gEfiGraphicsOutputProtocolGuid,NULL,(void**)&gop 17 | ); 18 | if(efi_error(st)){ 19 | dbg_printf("get gop failed: %m\n",st); 20 | return; 21 | } 22 | if(!gop||!gop->mode||!gop->mode->info){ 23 | dbg_print("invalid gop\n"); 24 | return; 25 | } 26 | SETF( 27 | DISPLAY,"%ux%u", 28 | gop->mode->info->width, 29 | gop->mode->info->height 30 | ); 31 | if(gop->mode->fb_base.ptr) 32 | APPENDF(DISPLAY," at 0x%llx",gop->mode->fb_base.uint64); 33 | else if(gop->mode->info->format==PIXEL_BLT_ONLY) 34 | APPEND(DISPLAY," blt-only"); 35 | 36 | } 37 | 38 | static bool find_pci_gpu(efi_handle*orig,efi_handle*pci){ 39 | efi_status st; 40 | efi_handle*hands=NULL; 41 | uintn_t hand_cnt=0; 42 | st=g_bs->locate_handle_buffer( 43 | search_by_protocol, 44 | &gEfiGraphicsOutputProtocolGuid, 45 | NULL,&hand_cnt,&hands 46 | ); 47 | if(efi_error(st)||!hands){ 48 | dbg_printf("locate gpu handle failed: %m\n",st); 49 | return false; 50 | } 51 | dbg_printf("found %zu gpu handles\n",hand_cnt); 52 | for(uintn_t i=0;ihandle_proto(hand,&gEfiPciIoProtocolGuid,(void**)&pci_io); 59 | if(!efi_error(st)&&pci_io){ 60 | *pci=hand; 61 | *orig=hands[i]; 62 | dbg_printf("found gpu handle %p\n",*pci); 63 | g_bs->free_pool(hands); 64 | return true; 65 | } 66 | dbg_printf("handle %p pci io failed: %m\n",hand,st); 67 | dbg_printf("try handle %p parent\n",hand); 68 | }while((hand=efi_get_parent_device(hand))); 69 | } 70 | dbg_print("no gpu handle found\n"); 71 | g_bs->free_pool(hands); 72 | return false; 73 | } 74 | 75 | static void load_gpu_pci_id(efifetch*ctx,uint16_t vendor_id,uint16_t device_id){ 76 | const gpu_item*ven_item=NULL,*dev_item=NULL; 77 | dbg_printf( 78 | "found gpu vendor 0x%04x device 0x%04x\n", 79 | vendor_id,device_id 80 | ); 81 | if(!vendor_id||!device_id)return; 82 | for(uintn_t i=0;gpu_db[i].name;i++){ 83 | if(gpu_db[i].vendor!=vendor_id)continue; 84 | if(gpu_db[i].device==device_id){ 85 | dev_item=&gpu_db[i]; 86 | dbg_printf("found gpu device in database: %s\n",gpu_db[i].name); 87 | } 88 | if(gpu_db[i].device==0xFFFF){ 89 | ven_item=&gpu_db[i]; 90 | dbg_printf("found gpu vendor in database: %s\n",gpu_db[i].name); 91 | } 92 | if(ven_item&&dev_item)break; 93 | } 94 | SET(GPU,"PCIe /"); 95 | if(ven_item||dev_item){ 96 | if(ven_item){ 97 | if(!IS_EMPTY(GPU))APPEND(GPU," "); 98 | APPEND(GPU,ven_item->name); 99 | } 100 | if(dev_item){ 101 | if(!IS_EMPTY(GPU))APPEND(GPU," "); 102 | APPEND(GPU,dev_item->name); 103 | } 104 | }else APPENDF(GPU," %04x:%04x",vendor_id,device_id); 105 | } 106 | 107 | static void load_gpu(efifetch*ctx,efi_handle gpu,efi_handle pci){ 108 | efi_status st; 109 | efi_pci_io_protocol*pci_io=NULL; 110 | struct{ 111 | uint16_t vendor_id; 112 | uint16_t device_id; 113 | }dir; 114 | if(!pci||!IS_EMPTY(GPU))return; 115 | memset(&dir,0,sizeof(dir)); 116 | st=g_bs->handle_proto(pci,&gEfiPciIoProtocolGuid,(void**)&pci_io); 117 | if(efi_error(st)||!pci_io){ 118 | dbg_printf("handle %p pci io failed: %m\n",pci,st); 119 | return; 120 | } 121 | dbg_printf("gpu pci io protocol %p\n",pci_io); 122 | st=pci_io->pci.read(pci_io,pciw_u16,0,sizeof(dir),&dir); 123 | if(efi_error(st)){ 124 | dbg_printf("read pci config failed: %m\n",st); 125 | return; 126 | } 127 | load_gpu_pci_id(ctx,dir.vendor_id,dir.device_id); 128 | } 129 | 130 | void efifetch_load_info_gpu(efifetch*ctx){ 131 | efi_handle gpu=NULL,pci=NULL; 132 | find_pci_gpu(&gpu,&pci); 133 | load_display(ctx,gpu); 134 | load_gpu(ctx,gpu,pci); 135 | } 136 | -------------------------------------------------------------------------------- /efifetch/info/info.c: -------------------------------------------------------------------------------- 1 | #include"info.h" 2 | #include"efifetch.h" 3 | #include"print.h" 4 | #include"str.h" 5 | 6 | void efifetch_load_info(efifetch*ctx){ 7 | efifetch_init_info_fdt(ctx); 8 | efifetch_init_info_smbios(ctx); 9 | efifetch_load_info_gpu(ctx); 10 | efifetch_load_info_mem(ctx); 11 | efifetch_load_info_net(ctx); 12 | efifetch_load_info_fs(ctx); 13 | efifetch_load_info_disk(ctx); 14 | efifetch_load_info_fdt(ctx); 15 | efifetch_load_info_smbios(ctx); 16 | efifetch_load_info_sys(ctx); 17 | efifetch_load_info_cpuid(ctx); 18 | efifetch_load_info_time(ctx); 19 | } 20 | 21 | static const char*fields_key[]={ 22 | [EFIFETCH_FIELD_NAME] = NULL, 23 | [EFIFETCH_FIELD_FIRMWARE] = "Firmware", 24 | [EFIFETCH_FIELD_HOST] = "Host", 25 | [EFIFETCH_FIELD_SPEC] = "Specification", 26 | [EFIFETCH_FIELD_UPTIME] = "Uptime", 27 | [EFIFETCH_FIELD_DISPLAY] = "Display", 28 | [EFIFETCH_FIELD_ARCH] = "Architecture", 29 | [EFIFETCH_FIELD_CPUID] = "CPUID", 30 | [EFIFETCH_FIELD_CPU] = "CPU", 31 | [EFIFETCH_FIELD_GPU] = "GPU", 32 | [EFIFETCH_FIELD_MEMORY] = "Memory", 33 | [EFIFETCH_FIELD_FILESYSTEM] = "Filesystem", 34 | [EFIFETCH_FIELD_DISK] = "Disk", 35 | [EFIFETCH_FIELD_IP4] = "IPv4", 36 | [EFIFETCH_FIELD_IP6] = "IPv6", 37 | [EFIFETCH_FIELD_SECURE_BOOT] = "Secure Boot", 38 | }; 39 | 40 | void efifetch_print_all(efifetch*ctx){ 41 | if(IS_EMPTY(NAME))SET(NAME,"efifetch"); 42 | logo_ctx_print_line(&ctx->logo); 43 | const char*name=ctx->fields[EFIFETCH_FIELD_NAME].value; 44 | text_printf(ctx->logo.con,"%s\r\n",name); 45 | logo_ctx_print_line(&ctx->logo); 46 | text_print_repeat(ctx->logo.con,'-',strlen(name)); 47 | out_print("\r\n"); 48 | for(int i=EFIFETCH_FIELD_MIN;ilogo); 52 | } 53 | 54 | void efifetch_print_field(efifetch*ctx,enum efifetch_field field){ 55 | if(!fields_key[field]||efifetch_field_is_empty(ctx,field))return; 56 | efi_simple_text_output_protocol*con=ctx->logo.con; 57 | logo_ctx_print_line(&ctx->logo); 58 | uintn_t orig_attr=ctx->logo.con->mode->attribute.num; 59 | con->set_attribute(con,ctx->logo.target_logo->main_color); 60 | text_print(con,fields_key[field]); 61 | con->set_attribute(con,orig_attr); 62 | text_printf(con,": %s\r\n",ctx->fields[field].value); 63 | } 64 | 65 | bool efifetch_field_is_empty(efifetch*ctx,enum efifetch_field field){ 66 | if(field=EFIFETCH_FIELD_MAX)return true; 67 | return !ctx->fields[field].value[0]; 68 | } 69 | 70 | void efifetch_field_reset(efifetch*ctx,enum efifetch_field field){ 71 | if(field=EFIFETCH_FIELD_MAX)return; 72 | memset(ctx->fields[field].value,0,sizeof(ctx->fields[field].value)); 73 | } 74 | 75 | void efifetch_field_set(efifetch*ctx,enum efifetch_field field,const char*value){ 76 | efifetch_field_setn(ctx,field,value,UINT32_MAX); 77 | } 78 | 79 | void efifetch_field_setn(efifetch*ctx,enum efifetch_field field,const char*value,size_t len){ 80 | if(field=EFIFETCH_FIELD_MAX)return; 81 | efifetch_field_reset(ctx,field); 82 | size_t l=strnlen(value,MIN(sizeof(ctx->fields[field].value),len)); 83 | strncpy(ctx->fields[field].value,value,l); 84 | } 85 | 86 | void efifetch_field_setf(efifetch*ctx,enum efifetch_field field,const char*fmt,...){ 87 | va_list va; 88 | if(field=EFIFETCH_FIELD_MAX)return; 89 | efifetch_field_reset(ctx,field); 90 | va_start(va,fmt); 91 | vsnprintf(ctx->fields[field].value,sizeof(ctx->fields[field].value),fmt,va); 92 | va_end(va); 93 | } 94 | 95 | void efifetch_field_appendn(efifetch*ctx,enum efifetch_field field,const char*value,size_t len){ 96 | if(field=EFIFETCH_FIELD_MAX)return; 97 | size_t origlen=strlen(ctx->fields[field].value); 98 | size_t remain=sizeof(ctx->fields[field].value)-origlen; 99 | size_t l=strnlen(value,MIN(remain,len)); 100 | strncpy(ctx->fields[field].value+origlen,value,l); 101 | } 102 | 103 | void efifetch_field_append(efifetch*ctx,enum efifetch_field field,const char*value){ 104 | efifetch_field_appendn(ctx,field,value,UINT32_MAX); 105 | } 106 | 107 | void efifetch_field_appendf(efifetch*ctx,enum efifetch_field field,const char*fmt,...){ 108 | va_list va; 109 | if(field=EFIFETCH_FIELD_MAX)return; 110 | va_start(va,fmt); 111 | vscprintf(ctx->fields[field].value,sizeof(ctx->fields[field].value),fmt,va); 112 | va_end(va); 113 | } 114 | -------------------------------------------------------------------------------- /efifetch/info/net.c: -------------------------------------------------------------------------------- 1 | #include"info.h" 2 | #include"network.h" 3 | #include"print.h" 4 | #include"net.h" 5 | #include"init.h" 6 | #include"str.h" 7 | 8 | void efifetch_load_info_net_ipv4(efifetch*ctx){ 9 | efi_status st; 10 | efi_handle*hands=NULL; 11 | uintn_t data_size=0,hand_cnt=0; 12 | efi_ip4_config2_protocol*cfg=NULL; 13 | efi_ip4_config2_interface_info*info=NULL; 14 | if(!IS_EMPTY(IP4))return; 15 | st=g_bs->locate_handle_buffer( 16 | search_by_protocol, 17 | &gEfiIp4ServiceBindingProtocolGuid, 18 | NULL,&hand_cnt,&hands 19 | ); 20 | if(efi_error(st)||!hands){ 21 | dbg_printf("locate ip4 handles failed: %m\n",st); 22 | return; 23 | } 24 | dbg_printf("found %zu ip4 handles\n",hand_cnt); 25 | for(uintn_t i=0;ihandle_proto(hands[i],&gEfiIp4Config2ProtocolGuid,(void**)&cfg); 27 | if(efi_error(st)||!cfg){ 28 | dbg_printf("handle %p ip4 cfg failed: %m\n",hands[i],st); 29 | continue; 30 | } 31 | st=cfg->get_data(cfg,ip4cfg2_type_int_info,&data_size,NULL); 32 | if(st!=efi_buffer_too_small){ 33 | dbg_printf("handle %p ip4 cfg get size failed: %m\n",hands[i],st); 34 | continue; 35 | } 36 | if(data_sizealloc_pool(efi_loader_data,data_size,(void**)&info); 41 | if(efi_error(st)||!info){ 42 | dbg_printf("handle %p ip4 cfg alloc data %zu failed: %m\n",hands[i],data_size,st); 43 | continue; 44 | } 45 | memset(info,0,data_size); 46 | st=cfg->get_data(cfg,ip4cfg2_type_int_info,&data_size,info); 47 | if(!efi_error(st)&&info->station_addr.raw!=0){ 48 | char buff[64]={}; 49 | int prefix=ipv4_to_prefix(&info->subnet_mask); 50 | int ret=ipv4_to_string(&info->station_addr,buff,sizeof(buff)); 51 | if(prefix>=0&&ret>=0){ 52 | SETF(IP4,"%s/%u",buff,prefix); 53 | encode_convert_ctx conv={}; 54 | conv.in.src=ENC_UTF16; 55 | conv.in.dst=ENC_UTF8; 56 | conv.in.src_ptr=info->name; 57 | conv.in.src_size=sizeof(info->name); 58 | conv.in.dst_ptr=buff; 59 | conv.in.dst_size=sizeof(buff); 60 | conv.in.allow_invalid=true; 61 | encode_convert(&conv); 62 | if(conv.out.dst_wrote>0)APPENDF(IP4," (%s)",buff); 63 | } 64 | }else dbg_printf( 65 | "handle %p ip4 cfg get interface failed or no address: %m\n", 66 | hands[i],st 67 | ); 68 | g_bs->free_pool(info); 69 | } 70 | g_bs->free_pool(hands); 71 | } 72 | 73 | void efifetch_load_info_net_ipv6(efifetch*ctx){ 74 | efi_status st; 75 | efi_handle*hands=NULL; 76 | uintn_t data_size=0,hand_cnt=0; 77 | efi_ip6_config_protocol*cfg=NULL; 78 | efi_ip6_config_interface_info*info=NULL; 79 | if(!IS_EMPTY(IP6))return; 80 | st=g_bs->locate_handle_buffer( 81 | search_by_protocol, 82 | &gEfiIp4ServiceBindingProtocolGuid, 83 | NULL,&hand_cnt,&hands 84 | ); 85 | if(efi_error(st)||!hands){ 86 | dbg_printf("locate ip6 handles failed: %m\n",st); 87 | return; 88 | } 89 | for(uintn_t i=0;ihandle_proto(hands[i],&gEfiIp6ConfigProtocolGuid,(void**)&cfg); 91 | if(efi_error(st)||!cfg){ 92 | dbg_printf("handle %p ip6 cfg failed: %m\n",hands[i],st); 93 | continue; 94 | } 95 | st=cfg->get_data(cfg,ip6cfg_type_int_info,&data_size,NULL); 96 | if(st!=efi_buffer_too_small){ 97 | dbg_printf("handle %p ip6 cfg get size failed: %m\n",hands[i],st); 98 | continue; 99 | } 100 | if(data_sizealloc_pool(efi_loader_data,data_size,(void**)&info); 105 | if(efi_error(st)||!info){ 106 | dbg_printf("handle %p ip6 cfg alloc data %llu failed: %m\n",hands[i],data_size,st); 107 | continue; 108 | } 109 | memset(info,0,data_size); 110 | st=cfg->get_data(cfg,ip6cfg_type_int_info,&data_size,info); 111 | if(!efi_error(st)&&info->addr_info_count>0){ 112 | char buff[64]={}; 113 | if(ipv6_to_string(&info->addr_info[0].addr,buff,sizeof(buff))>0) 114 | SET(IP6,buff); 115 | encode_convert_ctx conv={}; 116 | conv.in.src=ENC_UTF16; 117 | conv.in.dst=ENC_UTF8; 118 | conv.in.src_ptr=info->name; 119 | conv.in.src_size=sizeof(info->name); 120 | conv.in.dst_ptr=buff; 121 | conv.in.dst_size=sizeof(buff); 122 | conv.in.allow_invalid=true; 123 | encode_convert(&conv); 124 | if(conv.out.dst_wrote>0)APPENDF(IP6," (%s)",buff); 125 | }else dbg_printf( 126 | "handle %p ip6 cfg get interface failed or no address: %m\n", 127 | hands[i],st 128 | ); 129 | g_bs->free_pool(info); 130 | } 131 | g_bs->free_pool(hands); 132 | } 133 | 134 | void efifetch_load_info_net(efifetch*ctx){ 135 | efifetch_load_info_net_ipv4(ctx); 136 | efifetch_load_info_net_ipv6(ctx); 137 | } 138 | -------------------------------------------------------------------------------- /efifetch/logo/logo.c: -------------------------------------------------------------------------------- 1 | #include"logo.h" 2 | #include"str.h" 3 | #include"regexp.h" 4 | #include"print.h" 5 | 6 | static bool logo_desc_lookup_attr(logo_desc*logo,char ch,uintn_t*attr){ 7 | if(!logo||!logo->attr_map||!attr)return false; 8 | for(uintn_t i=0;iattr_map_count;i++){ 9 | if(logo->attr_map[i].ch!=ch)continue; 10 | *attr=logo->attr_map[i].attr; 11 | return true; 12 | } 13 | return false; 14 | } 15 | 16 | efi_status logo_desc_print_line( 17 | efi_simple_text_output_protocol*con, 18 | logo_desc*logo, 19 | uintn_t line 20 | ){ 21 | efi_status status=efi_success; 22 | if(!con||!logo)return efi_invalid_parameter; 23 | if(line>=logo->lines_count)return efi_invalid_parameter; 24 | if(!logo->lines[line])return efi_invalid_parameter; 25 | uintn_t orig_attr=con->mode->attribute.num; 26 | uintn_t cur_attr=orig_attr; 27 | char buff[128],ch; 28 | uintn_t buff_pos=0,total=0; 29 | con->set_attribute(con,orig_attr); 30 | for(uintn_t ch_id=0;(ch=logo->lines[line][ch_id]);ch_id++){ 31 | bool have_ch_attr=false; 32 | uintn_t ch_attr=0; 33 | have_ch_attr=logo_desc_lookup_attr(logo,ch,&ch_attr); 34 | if( 35 | (have_ch_attr&&ch_attr!=cur_attr)|| 36 | buff_pos>=sizeof(buff)-1 37 | ){ 38 | if(buff_pos>0){ 39 | buff[buff_pos]=0; 40 | status=text_print(con,buff); 41 | if(efi_error(status))goto fail; 42 | buff_pos=0; 43 | } 44 | status=con->set_attribute(con,ch_attr); 45 | if(efi_error(status))goto fail; 46 | cur_attr=ch_attr; 47 | } 48 | buff[buff_pos++]=ch; 49 | total++; 50 | } 51 | if(buff_pos>0){ 52 | buff[buff_pos]=0; 53 | status=text_print(con,buff); 54 | if(efi_error(status))goto fail; 55 | } 56 | if(totalwidth){ 57 | status=text_print_repeat(con,' ',logo->width-total); 58 | if(efi_error(status))goto fail; 59 | } 60 | fail: 61 | con->set_attribute(con,orig_attr); 62 | return status; 63 | } 64 | 65 | efi_status logo_desc_print( 66 | efi_simple_text_output_protocol*con, 67 | logo_desc*logo 68 | ){ 69 | efi_status status; 70 | if(!con||!logo)return efi_invalid_parameter; 71 | if(!logo->lines)return efi_invalid_parameter; 72 | for(uintn_t line=0;linelines_count;line++){ 73 | status=logo_desc_print_line(con,logo,line); 74 | if(efi_error(status))return status; 75 | status=text_print(con,"\n"); 76 | if(efi_error(status))return status; 77 | } 78 | return efi_success; 79 | } 80 | 81 | efi_status logo_ctx_init( 82 | logo_context*ctx, 83 | efi_simple_text_output_protocol*con, 84 | logo_desc*logo, 85 | uintn_t margin 86 | ){ 87 | if(!ctx||!con||!logo)return efi_invalid_parameter; 88 | if(!logo->lines)return efi_invalid_parameter; 89 | if(!logo->attr_map)return efi_invalid_parameter; 90 | memset(ctx,0,sizeof(logo_context)); 91 | ctx->con=con; 92 | ctx->target_logo=logo; 93 | ctx->cur_line=0; 94 | ctx->margin=margin; 95 | return efi_success; 96 | } 97 | 98 | efi_status logo_ctx_print_line(logo_context*ctx){ 99 | if(!ctx)return efi_invalid_parameter; 100 | // uintn_t attr=ctx->con->mode->attribute.num; 101 | // uintn_t row=ctx->con->mode->cursor_row; 102 | // ctx->con->set_attribute(ctx->con,attr); 103 | // ctx->con->set_cursor_position(ctx->con,0,row); 104 | // text_print_repeat(ctx->con,' ',80); 105 | // ctx->con->set_cursor_position(ctx->con,0,row); 106 | if(ctx->cur_line>=ctx->target_logo->lines_count){ 107 | uintn_t orig_attr=ctx->con->mode->attribute.num,ch_attr=0; 108 | bool have_attr=logo_desc_lookup_attr(ctx->target_logo,' ',&ch_attr); 109 | if(have_attr)ctx->con->set_attribute(ctx->con,ch_attr); 110 | text_print_repeat(ctx->con,' ',ctx->target_logo->width+ctx->margin); 111 | if(have_attr)ctx->con->set_attribute(ctx->con,orig_attr); 112 | return efi_success; 113 | } 114 | efi_status status=logo_desc_print_line( 115 | ctx->con,ctx->target_logo,ctx->cur_line 116 | ); 117 | if(efi_error(status))return status; 118 | ctx->cur_line++; 119 | if(ctx->margin>0)text_print_repeat(ctx->con,' ',ctx->margin); 120 | return efi_success; 121 | } 122 | 123 | efi_status logo_ctx_print_remain(logo_context*ctx){ 124 | if(!ctx)return efi_invalid_parameter; 125 | while(ctx->cur_linetarget_logo->lines_count){ 126 | efi_status status=logo_ctx_print_line(ctx); 127 | if(efi_error(status))return status; 128 | status=text_print(ctx->con,"\r\n"); 129 | if(efi_error(status))return status; 130 | } 131 | return efi_success; 132 | } 133 | 134 | logo_desc*logo_find(const char*name){ 135 | if(!name||!name[0])return NULL; 136 | for(uintn_t i=0;logos[i];i++){ 137 | if(!logos[i]->matchs)continue; 138 | for(uintn_t m=0;logos[i]->matchs[m];m++){ 139 | const char*s=logos[i]->matchs[m]; 140 | if(!s[0])continue; 141 | switch(s[0]){ 142 | case '$':if(regexp_match(s+1,name,REG_ICASE))continue;break; 143 | case '@':if(!strcasestr(name,s+1))continue;break; 144 | default:if(strcasecmp(name,s)!=0)continue;break; 145 | } 146 | return logos[i]; 147 | } 148 | } 149 | return NULL; 150 | } 151 | -------------------------------------------------------------------------------- /efifetch/include/str.h: -------------------------------------------------------------------------------- 1 | #ifndef STR_H 2 | #define STR_H 3 | #include"efi.h" 4 | extern void*memset(void*dest,int c,size_t n); 5 | extern void*memchr(const void*src,int c,size_t n); 6 | extern void*memrchr(const void*m,int c,size_t n); 7 | extern void*memmem(const void*h,size_t hl,const void*n,size_t nl); 8 | extern void*memcpy(void*dest,const void*src,size_t n); 9 | extern void*memmove(void*dest,const void*src,size_t n); 10 | extern int memcmp(const void*vl,const void*vr,size_t n); 11 | extern int strcmp(const char*l,const char*r); 12 | extern int strncmp(const char*_l,const char*_r,size_t n); 13 | extern char*stpcpy(char*d,const char*s); 14 | extern char*stpncpy(char*d,const char*s,size_t n); 15 | extern char*strcpy(char*d,const char*s); 16 | extern char*strncpy(char*d,const char*s,size_t n); 17 | extern size_t strlen(const char*s); 18 | extern size_t strnlen(const char*s,size_t n); 19 | extern char*strchrnul(const char*s,int c); 20 | extern char*strchr(const char*s,int c); 21 | extern char*strrchr(const char*s,int c); 22 | extern size_t strlcat(char*d,const char*s,size_t n); 23 | extern size_t strlcpy(char*d,const char*s,size_t n); 24 | extern size_t strlncat(char*d,const char*s,size_t n,size_t c); 25 | extern int strcasecmp(const char*_l,const char*_r); 26 | extern char*strcasestr(const char*h,const char*n); 27 | extern char*strcat(char*dest,const char*src); 28 | extern int strcoll(const char*l,const char*r); 29 | extern size_t strcspn(const char*s,const char*c); 30 | extern int strncasecmp(const char*_l,const char*_r,size_t n); 31 | extern char*strpbrk(const char*s,const char*b); 32 | extern char*strsep(char**str,const char*sep); 33 | extern size_t strspn(const char*s,const char*c); 34 | extern char*strstr(const char*h,const char*n); 35 | extern char*strtok(char*s,const char*sep); 36 | extern bool startwith(const char*str,char c); 37 | extern bool startwiths(const char*str,const char*s); 38 | extern bool startnwith(const char*str,size_t len,char c); 39 | extern bool startnwiths(const char*str,size_t len,const char*s); 40 | extern bool endwith(const char*str,char c); 41 | extern bool endwiths(const char*str,const char*s); 42 | extern bool endnwith(const char*str,size_t len,char c); 43 | extern bool endnwiths(const char*str,size_t len,const char*s); 44 | extern bool removeend(char*str,char c); 45 | extern bool removeends(char*str,const char*s); 46 | extern void trimleft(char*str); 47 | extern void trimright(char*str); 48 | extern void trim(char*str); 49 | extern void*realloc(void*old,size_t size); 50 | extern void*malloc(size_t size); 51 | extern void free(void*buffer); 52 | extern char*strdup(const char*str); 53 | extern char*strndup(const char*str,size_t max); 54 | extern void*memdup(const void*mem,size_t len); 55 | extern void*zalloc(size_t size); 56 | extern void*calloc(size_t nmemb,size_t size); 57 | extern int isspace(int c); 58 | extern int isalpha(int c); 59 | extern int islower(int c); 60 | extern int isupper(int c); 61 | extern int tolower(int c); 62 | extern int toupper(int c); 63 | extern int isdigit(int c); 64 | extern int isprint(int c); 65 | extern unsigned long long strtoull(const char*str,char**end,int base); 66 | extern long long strtoll(const char*str,char**end,int base); 67 | extern unsigned long strtoul(const char*str,char**end,int base); 68 | extern long strtol(const char*str,char**end,int base); 69 | extern int puts(const char*str); 70 | extern int putchar(int ch); 71 | extern int printf(const char*fmt,...); 72 | extern int asprintf(char**buf,const char*fmt,...); 73 | extern int sprintf(char*buf,const char*fmt,...); 74 | extern int snprintf(char*buf,size_t size,const char*fmt,...); 75 | extern int scprintf(char*buf,size_t size,const char*fmt,...); 76 | extern int vprintf(const char*fmt,va_list va); 77 | extern int vasprintf(char**buf,const char*fmt,va_list va); 78 | extern int vsprintf(char*buf,const char*fmt,va_list va); 79 | extern int vsnprintf(char*buf,size_t size,const char*fmt,va_list va); 80 | extern int vscprintf(char*buf,size_t size,const char*fmt,va_list va); 81 | extern const char*efi_status_to_string(efi_status st); 82 | extern const char*efi_status_to_short_string(efi_status st); 83 | extern const char*efi_memory_type_to_string(efi_memory_type type); 84 | extern const char*efi_guid_to_string(const efi_guid*guid,char*buff,size_t len); 85 | #define efi_strerr efi_status_to_string 86 | typedef enum encoding{ 87 | ENC_NONE, 88 | ENC_UTF8, 89 | ENC_UTF16, 90 | }encoding; 91 | typedef struct convert_transfer{ 92 | const void*match; 93 | size_t match_size; 94 | const void*replace; 95 | size_t replace_size; 96 | }convert_transfer; 97 | typedef struct encode_convert_ctx{ 98 | struct{ 99 | encoding src; 100 | encoding dst; 101 | const void*src_ptr; 102 | void*dst_ptr; 103 | size_t src_size; 104 | size_t dst_size; 105 | convert_transfer**transfers; 106 | bool allow_invalid; 107 | }in; 108 | struct{ 109 | void*src_end; 110 | void*dst_end; 111 | size_t src_used; 112 | size_t dst_wrote; 113 | bool have_invalid; 114 | }out; 115 | }encode_convert_ctx; 116 | extern efi_status encode_convert(encode_convert_ctx*ctx); 117 | #endif 118 | -------------------------------------------------------------------------------- /efifetch/info/smbios.c: -------------------------------------------------------------------------------- 1 | #include"info.h" 2 | #include"str.h" 3 | #include"print.h" 4 | #include"readable.h" 5 | 6 | static void efifetch_load_info_smbios_firmware(efifetch*ctx){ 7 | if(!IS_EMPTY(FIRMWARE))return; 8 | smbios_structure_pointer ptr; 9 | char str_vendor[64]={}; 10 | char str_version[64]={}; 11 | char str_date[64]={}; 12 | ptr=efifetch_get_smbios_by_type(ctx,0,0xFFFF); 13 | if(!ptr.value){ 14 | dbg_print("smbios type0 not found\n"); 15 | return; 16 | } 17 | SMBIOS_VAR(ptr,0,vendor,0); 18 | SMBIOS_VAR(ptr,0,bios_release_date,0); 19 | SMBIOS_VAR(ptr,0,bios_version,0); 20 | efifetch_load_smbios_string( 21 | ctx,ptr,vendor, 22 | str_vendor,sizeof(str_vendor) 23 | ); 24 | efifetch_load_smbios_string( 25 | ctx,ptr,bios_version, 26 | str_version,sizeof(str_version) 27 | ); 28 | efifetch_load_smbios_string( 29 | ctx,ptr,bios_release_date, 30 | str_date,sizeof(str_date) 31 | ); 32 | if(!str_vendor[0]&&!str_date[0]&&!str_version[0]){ 33 | dbg_print("smbios type0 no vendor,version,date\n"); 34 | return; 35 | } 36 | if(str_vendor[0]){ 37 | if(!IS_EMPTY(FIRMWARE))APPEND(FIRMWARE," "); 38 | APPEND(FIRMWARE,str_vendor); 39 | } 40 | if(str_version[0]){ 41 | if(!IS_EMPTY(FIRMWARE))APPEND(FIRMWARE," "); 42 | APPEND(FIRMWARE,str_version); 43 | } 44 | if(str_date[0]){ 45 | if(!IS_EMPTY(FIRMWARE))APPEND(FIRMWARE," "); 46 | APPEND(FIRMWARE,str_date); 47 | } 48 | } 49 | 50 | static void efifetch_load_info_smbios_cpu(efifetch*ctx){ 51 | if(!IS_EMPTY(CPU))return; 52 | smbios_handle handle; 53 | smbios_structure_pointer ptr; 54 | char version[64]={}; 55 | uint64_t cpus=0,cores=0,threads=0,max_freq=0; 56 | handle=0xFFFF; 57 | while((ptr=efifetch_get_smbios_by_type(ctx,4,handle)).value){ 58 | SMBIOS_VAR(ptr,4,core_count,0); 59 | SMBIOS_VAR(ptr,4,core_count2,0); 60 | SMBIOS_VAR(ptr,4,enabled_core_count,0); 61 | SMBIOS_VAR(ptr,4,enabled_core_count2,0); 62 | SMBIOS_VAR(ptr,4,thread_count,0); 63 | SMBIOS_VAR(ptr,4,thread_count2,0); 64 | SMBIOS_VAR(ptr,4,thread_enabled,0); 65 | SMBIOS_VAR(ptr,4,max_speed,0); 66 | SMBIOS_VAR(ptr,4,current_speed,0); 67 | SMBIOS_VAR(ptr,4,processor_version,0); 68 | uint32_t real_cores=0,real_threads=0; 69 | if(core_count!=0xFF) 70 | real_cores=MAX(real_cores,core_count); 71 | else if(core_count2!=0xFFFF) 72 | real_cores=MAX(real_cores,core_count2); 73 | if(enabled_core_count!=0xFF) 74 | real_cores=MAX(real_cores,enabled_core_count); 75 | else if(enabled_core_count2!=0xFFFF) 76 | real_cores=MAX(real_cores,enabled_core_count2); 77 | if(thread_count!=0xFF) 78 | real_threads=MAX(real_threads,thread_count); 79 | else if(thread_count2!=0xFFFF) 80 | real_threads=MAX(real_threads,thread_count2); 81 | if(thread_enabled!=0xFFFF) 82 | real_threads=MAX(real_threads,thread_enabled); 83 | cores+=real_cores,threads+=real_threads; 84 | max_freq=MAX(max_freq,MAX(current_speed,max_speed)); 85 | if(processor_version!=0)efifetch_load_smbios_string( 86 | ctx,ptr,processor_version,version,sizeof(version) 87 | ); 88 | cpus++; 89 | handle=ptr.header->handle; 90 | } 91 | if(cpus==0||!version[0]){ 92 | dbg_print("smbios type4 no cpus\n"); 93 | return; 94 | } 95 | RESET(CPU); 96 | if(cpus>1)APPENDF(CPU,"%llu x ",cpus); 97 | APPEND(CPU,version); 98 | if(cores>0&&cores!=0xFFFF){ 99 | if(cores==threads||threads==0)APPENDF(CPU," (%llu)",cores); 100 | else APPENDF(CPU," (%lluC%lluT)",cores,threads); 101 | } 102 | if(max_freq>0&&max_freq!=0xFFFF){ 103 | char buf_freq[32]; 104 | format_size_float_hz(buf_freq,max_freq*1000000); 105 | APPENDF(CPU," @ %s",buf_freq); 106 | } 107 | } 108 | 109 | static void efifetch_load_info_smbios_sys(efifetch*ctx){ 110 | if(!IS_EMPTY(HOST))return; 111 | smbios_structure_pointer ptr; 112 | char str_manufacturer[64]={}; 113 | char str_product[64]={}; 114 | char str_version[64]={}; 115 | ptr=efifetch_get_smbios_by_type(ctx,1,0xFFFF); 116 | if(!ptr.value){ 117 | dbg_print("smbios type1 not found\n"); 118 | return; 119 | } 120 | SMBIOS_VAR(ptr,1,manufacturer,0); 121 | SMBIOS_VAR(ptr,1,product,0); 122 | SMBIOS_VAR(ptr,1,version,0); 123 | efifetch_load_smbios_string( 124 | ctx,ptr,manufacturer, 125 | str_manufacturer,sizeof(str_manufacturer) 126 | ); 127 | efifetch_load_smbios_string( 128 | ctx,ptr,product, 129 | str_product,sizeof(str_product) 130 | ); 131 | efifetch_load_smbios_string( 132 | ctx,ptr,version, 133 | str_version,sizeof(str_version) 134 | ); 135 | if(!str_manufacturer[0]&&!str_product[0]&&!str_version[0]){ 136 | dbg_print("smbios type1 no manufacturer,product,version\n"); 137 | return; 138 | } 139 | if(str_manufacturer[0]){ 140 | if(!IS_EMPTY(HOST))APPEND(HOST," "); 141 | APPEND(HOST,str_manufacturer); 142 | } 143 | if(str_product[0]){ 144 | if(!IS_EMPTY(HOST))APPEND(HOST," "); 145 | APPEND(HOST,str_product); 146 | } 147 | if(str_version[0]){ 148 | if(!IS_EMPTY(HOST))APPEND(HOST," "); 149 | APPEND(HOST,str_version); 150 | } 151 | } 152 | 153 | void efifetch_load_info_smbios(efifetch*ctx){ 154 | efifetch_load_info_smbios_firmware(ctx); 155 | efifetch_load_info_smbios_cpu(ctx); 156 | efifetch_load_info_smbios_sys(ctx); 157 | } 158 | -------------------------------------------------------------------------------- /efifetch/info/smbios_base.c: -------------------------------------------------------------------------------- 1 | #include"info.h" 2 | #include"init.h" 3 | #include"print.h" 4 | #include"str.h" 5 | 6 | static uint8_t sum8(const void*data,uintn_t size){ 7 | uint8_t sum=0; 8 | const uint8_t*buff=data; 9 | for(uintn_t i=0;imagic,SMBIOS_MAGIC, 18 | sizeof(smbios->magic))!=0 19 | ){ 20 | dbg_print("smbios2 magic mismatch\n"); 21 | return false; 22 | } 23 | if( 24 | smbios->entry_point_length!=0x1E&& 25 | smbios->entry_point_length!=sizeof(smbios_table2_entry_point) 26 | ){ 27 | dbg_printf( 28 | "smbios2 entry point length mismatch %u\n", 29 | smbios->entry_point_length 30 | ); 31 | return false; 32 | } 33 | if(smbios->major_version<2){ 34 | dbg_printf("smbios2 major invalid %u\n",smbios->major_version); 35 | return false; 36 | } 37 | if(memcmp( 38 | smbios->intermediate_magic,"_DMI_", 39 | sizeof(smbios->intermediate_magic) 40 | )!=0){ 41 | dbg_print("smbios2 intermediate magic mismatch\n"); 42 | return false; 43 | } 44 | if(sum8(smbios,smbios->entry_point_length)!=0){ 45 | dbg_print("smbios2 checksum mismatch\n"); 46 | return false; 47 | } 48 | uintn_t xs=offsetof(smbios_table2_entry_point,intermediate_magic); 49 | if(sum8((void*)smbios+xs,smbios->entry_point_length-xs)!=0){ 50 | dbg_print("smbios2 intermediate checksum mismatch\n"); 51 | return false; 52 | } 53 | return true; 54 | } 55 | 56 | static bool check_smbios3(smbios_table3_entry_point*smbios){ 57 | if(!smbios)return false; 58 | if(memcmp(smbios->magic,SMBIOS3_MAGIC,sizeof(smbios->magic))!=0){ 59 | dbg_print("smbios3 magic mismatch\n"); 60 | return false; 61 | } 62 | if(smbios->entry_point_lengthentry_point_length 66 | ); 67 | return false; 68 | } 69 | if(smbios->major_version<3){ 70 | dbg_printf("smbios3 major invalid %u\n",smbios->major_version); 71 | return false; 72 | } 73 | if(sum8(smbios,sizeof(smbios_table3_entry_point))!=0){ 74 | dbg_print("smbios3 checksum mismatch\n"); 75 | return false; 76 | } 77 | return true; 78 | } 79 | 80 | void efifetch_init_info_smbios(efifetch*ctx){ 81 | smbios_table2_entry_point*smbios2=NULL; 82 | smbios_table3_entry_point*smbios3=NULL; 83 | ctx->smbios2=NULL; 84 | ctx->smbios3=NULL; 85 | for(uintn_t i=0;ientries;i++){ 86 | efi_guid*g=&g_st->cfg_table[i].guid; 87 | void*t=g_st->cfg_table[i].table; 88 | if(memcmp(g,&gEfiSmbiosTableGuid,sizeof(efi_guid))==0)smbios2=t; 89 | if(memcmp(g,&gEfiSmbios3TableGuid,sizeof(efi_guid))==0)smbios3=t; 90 | } 91 | if(smbios2&&check_smbios2(smbios2))ctx->smbios2=smbios2; 92 | if(smbios3&&check_smbios3(smbios3))ctx->smbios3=smbios3; 93 | } 94 | 95 | static bool smbios_get_range(efifetch*ctx,uintn_t*start,uintn_t*end){ 96 | if(!ctx||!start||!end)return false; 97 | if(ctx->smbios2)*start=ctx->smbios2->table_address,*end=*start+ctx->smbios2->table_length; 98 | if(ctx->smbios3)*start=ctx->smbios3->table_address,*end=*start+ctx->smbios3->table_max_size; 99 | if(!*start||!*end||*start>=*end)return false; 100 | return true; 101 | } 102 | 103 | static bool smbios_walk(efifetch*ctx,smbios_structure_pointer*p){ 104 | uintn_t start=0,end=0; 105 | if(!p||!smbios_get_range(ctx,&start,&end))return false; 106 | if(!p->value){ 107 | p->value=start; 108 | if(p->header->lengthheader->type==127)return false; 112 | if(p->value+p->header->length>end)return false; 113 | if(p->header->lengthheader->length; 116 | do{ 117 | for(;*next.raw;next.raw++); 118 | next.raw++; 119 | }while(*next.raw); 120 | next.raw++; 121 | if(next.value+p->header->length>end)return false; 122 | if(next.header->lengthtype!=type)continue; 131 | if(handle==0xFFFF)return smbios; 132 | if(smbios.header->handle>handle)return smbios; 133 | } 134 | return nil; 135 | } 136 | 137 | smbios_structure_pointer efifetch_get_smbios_by_handle(efifetch*ctx,smbios_handle handle){ 138 | smbios_structure_pointer smbios={},nil={}; 139 | while(smbios_walk(ctx,&smbios)) 140 | if(smbios.header->handle==handle)return smbios; 141 | return nil; 142 | } 143 | 144 | const char*efifetch_get_smbios_string( 145 | efifetch*ctx, 146 | smbios_structure_pointer p, 147 | smbios_table_string id 148 | ){ 149 | uintn_t start=0,end=0; 150 | if(id==0||!p.value||!smbios_get_range(ctx,&start,&end))return NULL; 151 | if(p.header->type==127)return NULL; 152 | if(p.value+p.header->length>end)return NULL; 153 | if(p.header->lengthlength; 155 | for(smbios_table_string cur_id=1;*str&&cur_id<=id;cur_id++){ 156 | if(cur_id==id)return str; 157 | for(;*str;str++); 158 | str++; 159 | } 160 | return NULL; 161 | } 162 | 163 | bool efifetch_load_smbios_string( 164 | efifetch*ctx, 165 | smbios_structure_pointer p, 166 | smbios_table_string id, 167 | char*buff, 168 | size_t size 169 | ){ 170 | memset(buff,0,size); 171 | if(!ctx||!buff||size==0)return false; 172 | const char*v=efifetch_get_smbios_string(ctx,p,id); 173 | if( 174 | !v||!v[0]|| 175 | strcasestr(v,"unknown")|| 176 | strcasestr(v,"to be filled by") 177 | )return false; 178 | strncpy(buff,v,size-1); 179 | trim(buff); 180 | return true; 181 | } 182 | -------------------------------------------------------------------------------- /efifetch/lib/dump.c: -------------------------------------------------------------------------------- 1 | #include"dump.h" 2 | #include"print.h" 3 | #include"str.h" 4 | 5 | const char*unicode_fat_table_char[]={ 6 | "═","║", 7 | "╔","╦","╗", 8 | "╠","╬","╣", 9 | "╚","╩","╝", 10 | }; 11 | 12 | const char*unicode_table_char[]={ 13 | "─","│", 14 | "┌","┬","┐", 15 | "├","┼","┤", 16 | "└","┴","┘", 17 | }; 18 | 19 | const char*ascii_table_char[]={ 20 | "-","|", 21 | "+","+","+", 22 | "+","+","+", 23 | "+","+","+", 24 | }; 25 | 26 | static void dump_finish(mem_dump*dump){ 27 | if(!dump||!dump->write)return; 28 | if(!dump->buffered||!dump->buffer)return; 29 | if(dump->buf_pos>0){ 30 | dump->buffer[dump->buf_pos+1]=0; 31 | dump->write(dump,dump->buffer,dump->buf_pos+1); 32 | dump->buf_pos=0; 33 | } 34 | free(dump->buffer); 35 | dump->buffer=NULL; 36 | dump->buf_size=0; 37 | } 38 | 39 | static int dump_print(mem_dump*dump,const char*str){ 40 | void*buf; 41 | size_t len,size,i; 42 | if(!dump||!dump->write||!str)return -1; 43 | if((len=strlen(str))<=0)return 0; 44 | if(!dump->buffered)return dump->write(dump,str,len); 45 | if(len+dump->buf_pos>=dump->buf_size||!dump->buffer){ 46 | size=dump->buf_size; 47 | while(len+dump->buf_pos>=size)size+=4096; 48 | buf=dump->buffer?realloc(dump->buffer,size):malloc(size); 49 | if(!buf)return -1; 50 | memset(buf,0,size); 51 | dump->buf_size=size; 52 | dump->buffer=buf; 53 | } 54 | for(i=0;ibuffer[dump->buf_pos]=str[i]; 56 | if(str[i]=='\n'){ 57 | dump->buffer[dump->buf_pos+1]=0; 58 | dump->write(dump,dump->buffer,dump->buf_pos+1); 59 | dump->buf_pos=0; 60 | }else dump->buf_pos++; 61 | } 62 | return 0; 63 | } 64 | 65 | static int dump_putchar(mem_dump*dump,const char ch){ 66 | char buff[2]={ch,0}; 67 | if(!dump||!dump->print)return -1; 68 | return dump->print(dump,buff); 69 | } 70 | 71 | static int dump_printf(mem_dump*dump,const char*fmt,...){ 72 | int r; 73 | va_list va; 74 | bool alloc=false; 75 | char buff[256]; 76 | char*str=buff; 77 | if(!dump||!dump->print)return -1; 78 | va_start(va,fmt); 79 | r=vsnprintf(buff,sizeof(buff)-1,fmt,va); 80 | if(r>=0&&(size_t)r>=sizeof(buff)){ 81 | alloc=true,str=NULL; 82 | r=vasprintf(&str,fmt,va); 83 | if(r<0||!str)return -1; 84 | } 85 | va_end(va); 86 | if(!str)return 0; 87 | dump->print(dump,str); 88 | if(alloc)free(str); 89 | return 0; 90 | } 91 | 92 | static int dump_stdio_write(mem_dump*dump,const char*str,size_t len){ 93 | (void)dump; 94 | out_print(str); 95 | return 0; 96 | } 97 | 98 | mem_dump mem_dump_def={ 99 | .step=0x8, 100 | .addr_len=4, 101 | .table=unicode_table_char, 102 | .write=dump_stdio_write, 103 | .show_header=true, 104 | .print_ascii=true, 105 | }; 106 | 107 | void mem_dump_with(void*addr,size_t len,mem_dump*dump){ 108 | char*u=addr; 109 | char buff[256]; 110 | size_t i,a,b,s=0; 111 | if(!dump)dump=&mem_dump_def; 112 | if(!dump->write||dump->step<=0||len<=0)return; 113 | if(!dump->finish)dump->finish=dump_finish; 114 | if(!dump->putchar)dump->putchar=dump_putchar; 115 | if(!dump->printf)dump->printf=dump_printf; 116 | if(!dump->print)dump->print=dump_print; 117 | if(dump->show_header){ 118 | if(dump->addr_len>0) 119 | for(i=0;i<(size_t)dump->addr_len+1;i++) 120 | dump->putchar(dump,' '); 121 | if(dump->table)dump->print(dump," "); 122 | for(i=0;i<(size_t)dump->step;i++) 123 | dump->printf(dump,"%02zX ",i); 124 | if(dump->print_ascii){ 125 | if(dump->table)dump->print(dump," "); 126 | dump->print(dump,"ASCII"); 127 | } 128 | dump->putchar(dump,'\n'); 129 | } 130 | if(dump->table){ 131 | if(dump->addr_len>0) 132 | for(i=0;i<(size_t)dump->addr_len+1;i++) 133 | dump->putchar(dump,' '); 134 | dump->print(dump,dump->table[2]); 135 | for(i=0;i<(size_t)dump->step*3+1;i++) 136 | dump->print(dump,dump->table[0]); 137 | if(dump->print_ascii){ 138 | dump->print(dump,dump->table[3]); 139 | for(i=0;i<(size_t)dump->step+2;i++) 140 | dump->print(dump,dump->table[0]); 141 | } 142 | dump->print(dump,dump->table[4]); 143 | } 144 | for(a=0;astep==0){ 146 | if(dump->table&&a!=0){ 147 | dump->printf(dump,dump->table[1]); 148 | dump->putchar(dump,' '); 149 | } 150 | if(dump->print_ascii){ 151 | for(b=a-dump->step;bputchar(dump,isprint(u[b])?u[b]:'.'); 153 | if(dump->table&&a!=0){ 154 | dump->putchar(dump,' '); 155 | dump->printf(dump,dump->table[1]); 156 | dump->putchar(dump,' '); 157 | } 158 | } 159 | if(dump->table||a!=0)dump->putchar(dump,'\n'); 160 | if(dump->addr_len>0){ 161 | snprintf(buff,sizeof(buff),"%%0%dzX ",dump->addr_len); 162 | dump->printf(dump,buff,a+(dump->real_address?(size_t)addr:0)); 163 | } 164 | if(dump->table){ 165 | dump->printf(dump,dump->table[1]); 166 | dump->putchar(dump,' '); 167 | } 168 | s=a; 169 | } 170 | dump->printf(dump,"%02X ",(unsigned char)(u[a]%0xFF)); 171 | } 172 | if(s!=len)for(b=0;bstep-len;b++) 173 | dump->print(dump," "); 174 | if(dump->table){ 175 | dump->print(dump,dump->table[1]); 176 | dump->putchar(dump,' '); 177 | } 178 | if(dump->print_ascii){ 179 | for(b=s;bprintf(dump,"%c",isprint(u[b])?u[b]:'.'); 180 | for(b=0;bstep-len;b++) 181 | dump->putchar(dump,' '); 182 | if(dump->table){ 183 | dump->putchar(dump,' '); 184 | dump->print(dump,dump->table[1]); 185 | } 186 | } 187 | if(dump->table)dump->putchar(dump,'\n'); 188 | if(dump->addr_len>0) 189 | for(i=0;i<(size_t)dump->addr_len+1;i++) 190 | dump->putchar(dump,' '); 191 | if(dump->table){ 192 | dump->print(dump,dump->table[8]); 193 | for(i=0;i<(size_t)dump->step*3+1;i++) 194 | dump->print(dump,dump->table[0]); 195 | if(dump->print_ascii){ 196 | dump->print(dump,dump->table[9]); 197 | for(i=0;i<(size_t)dump->step+2;i++) 198 | dump->print(dump,dump->table[0]); 199 | } 200 | dump->print(dump,dump->table[10]); 201 | dump->putchar(dump,'\n'); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /scripts/gpu-list.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | 4 | allowed_vendors = { 5 | '0014': 'Loongson', 6 | '0731': 'Jingjia Microelectronics', 7 | '1002': 'AMD', 8 | '1013': 'Cirrus', 9 | '1014': 'IBM', 10 | '102B': 'Matrox', 11 | '1033': 'NEC', 12 | '1039': 'SiS', 13 | '1091': 'Intergraph', 14 | '10DE': 'NVIDIA', 15 | '1106': 'VIA', 16 | '121A': '3dFX', 17 | '1414': 'Microsoft', 18 | '15AD': 'VMware', 19 | '19E5': 'Huawei', 20 | '1A03': 'Aspeed', 21 | '1AF4': 'Virtio', 22 | '1B36': 'RedHat', 23 | '1CAD': 'Apeed', 24 | '1D17': 'Zhaoxin', 25 | '1ED5': 'Moore Threads', 26 | '1FB0': 'ICube', 27 | '8086': 'Intel', 28 | '80EE': 'Innotek', 29 | 'FFFE': 'VMware', 30 | } 31 | 32 | gpu_keywords = [ 33 | 'Radeon', 'GeForce', 'Quadro', 'Tesla', 'GRID', 'RTX', 'GTX', 'VGA', 34 | 'Arc', 'Iris', 'UHD Graphics', 'HD Graphics', 'FirePro', 'Instinct', 35 | 'Voodoo', 'Matrox', 'G200', 'G400', 'G450', 'G550', 'GD', 'graphic', 36 | 'MTT', 'Moore Threads', 'Apeed', 'SVGA', 'Virtio', 'GPU', 'QXL', 'JM', 37 | 'Display', 'AGP', 38 | ] 39 | 40 | gpu_blacklist = [ 41 | 'Alpine', 'Nordic', 'Viking', 'Nordic', 'CLM', 'iBMC', 42 | 'Intel Graphics', 'UHD Graphics', 'HD Graphics', 'Xe Graphics', 43 | ] 44 | 45 | device_blacklist = [ 46 | {"vendor_id": "8086", "device_id": "A70D"}, 47 | ] 48 | 49 | addition_devices = [ 50 | { 51 | "vendor_id": "1234", 52 | "device_id": "1111", 53 | "name": "QEMU Bochs VGA", 54 | } 55 | ] 56 | 57 | def patch_item(item: dict) -> bool: 58 | blacklist = [ 59 | "QuickPath Architecture", 60 | "High Definition Audio", 61 | "switch", "bridge", "Dummy", "JPEG", 62 | ] 63 | vid: str = item["vendor_id"] 64 | name: str = item["name"] 65 | lname = name.lower() 66 | if vid == "102B": 67 | if name.startswith("Integrated Matrox"): 68 | name = name[11:] 69 | if vid in allowed_vendors: 70 | vendor = allowed_vendors[vid] 71 | if lname.startswith(vendor.lower() + " "): 72 | name = name[len(vendor) + 1:] 73 | if " and " in name: 74 | name = name.split(" and ")[0] 75 | if " / " in name: 76 | name = name.split(" / ")[0] 77 | if "/" in name: 78 | name = name.split("/")[0] 79 | if " (customized " in name: 80 | name = name.split(" (customized ")[0] 81 | if " Rev." in name: 82 | name = name.split(" Rev.")[0] 83 | if "Engineering Sample" in name: 84 | name = name.replace("Engineering Sample", "ES") 85 | if "All-In-Wonder " in name: 86 | name = name.replace("All-In-Wonder ", "") 87 | if "All-in-Wonder " in name: 88 | name = name.replace("All-in-Wonder ", "") 89 | if " Mac Edition" in name: 90 | name = name.replace(" Mac Edition", "") 91 | if " Green Edition" in name: 92 | name = name.replace(" Green Edition", "") 93 | if " Graphics Controller" in name: 94 | name = name.replace(" Graphics Controller", "") 95 | if " Ada Generation" in name: 96 | name = name.replace(" Ada Generation", "") 97 | if " Platinum Edition" in name: 98 | name = name.replace(" Platinum Edition", "") 99 | if " Graphics Adapter" in name: 100 | name = name.replace(" Graphics Adapter", "") 101 | if " Graphics" in name: 102 | name = name.replace(" Graphics", "") 103 | if any(black.lower() in lname for black in blacklist): 104 | return False 105 | if len(name) > 32: 106 | print(f"too long {len(name)} {name} / {item["name"]}") 107 | item["orig_name"] = item["name"] 108 | item["name"] = name 109 | return True 110 | 111 | def process(input: str, output: str): 112 | gpu_devices = [] 113 | with open(input, 'r', encoding='utf-8', errors='ignore') as f: 114 | current_vendor_id = None 115 | for line in f: 116 | if line.startswith('#') or not line.strip(): 117 | continue 118 | vendor_match = re.match(r'^([0-9a-fA-F]{4})\s+(.*)', line) 119 | if vendor_match and not line.startswith('\t'): 120 | vendor_id = vendor_match.group(1).lower() 121 | if vendor_id.upper() in allowed_vendors: 122 | current_vendor_id = vendor_id.upper() 123 | else: 124 | current_vendor_id = None 125 | continue 126 | if current_vendor_id and line.startswith('\t') and not line.startswith('\t\t'): 127 | device_match = re.match(r'^\t([0-9a-fA-F]{4})\s+(.*)', line) 128 | if device_match: 129 | device_id = device_match.group(1).upper() 130 | device_name = device_match.group(2).strip() 131 | bracket_match = re.search(r'\[(.*?)\]', device_name) 132 | if any(device_id == item["device_id"] and current_vendor_id == item["vendor_id"] for item in device_blacklist): 133 | continue 134 | if not any(keyword.lower() in device_name.lower() for keyword in gpu_keywords): 135 | continue 136 | if bracket_match: 137 | new_name = bracket_match.group(1).strip() 138 | if any(keyword.lower() in new_name.lower() for keyword in gpu_blacklist): 139 | d = f"[{new_name}]" 140 | if device_name.endswith(d): 141 | device_name = device_name[:-len(d)].strip() 142 | else: 143 | device_name = new_name 144 | item = { 145 | "vendor_id": current_vendor_id, 146 | "device_id": device_id, 147 | "name": device_name 148 | } 149 | if patch_item(item): 150 | gpu_devices.append(item) 151 | gpu_devices.extend(addition_devices) 152 | gpu_devices.sort(key=lambda x: (x['vendor_id'], x['device_id'])) 153 | with open(output, 'w', encoding='utf-8') as f_out: 154 | f_out.write("#include\"data.h\"\n") 155 | f_out.write("// Automatically generated by gpu-list.py\n") 156 | f_out.write("// From pci.ids\n") 157 | f_out.write("GPU_DB_START\n") 158 | for item in allowed_vendors: 159 | f_out.write(f"GPU_DB_VENDOR(0x{item},\"{allowed_vendors[item]}\")\n") 160 | for item in gpu_devices: 161 | f_out.write(f"GPU_DB_ITEM(0x{item["vendor_id"]},0x{item["device_id"]},\"{item["name"]}\")\n") 162 | f_out.write("GPU_DB_END\n") 163 | 164 | def main(): 165 | if len(sys.argv) != 3: 166 | print("Usage: python gpu-list.py ") 167 | sys.exit(1) 168 | process(sys.argv[1], sys.argv[2]) 169 | 170 | if __name__ == "__main__": 171 | main() 172 | -------------------------------------------------------------------------------- /efifetch/lib/encode.c: -------------------------------------------------------------------------------- 1 | #include"str.h" 2 | 3 | static efi_status proc_transfer(encode_convert_ctx*ctx,size_t*s,size_t*d){ 4 | const convert_transfer*tr; 5 | uint8_t*dst=(uint8_t*)ctx->in.dst_ptr; 6 | const uint8_t*src=(const uint8_t*)ctx->in.src_ptr; 7 | for(int t=0;(tr=ctx->in.transfers[t]);t++)if( 8 | tr->match_size>0&&tr->replace_size>0&& 9 | *s+tr->match_size<=ctx->in.src_size&& 10 | memcmp(src+*s,tr->match,tr->match_size)==0 11 | ){ 12 | if(!tr->replace||tr->replace_size==0) 13 | return efi_out_of_resources; 14 | if(*d+tr->replace_size>ctx->in.dst_size) 15 | return efi_out_of_resources; 16 | memcpy(dst+*d,tr->replace,tr->replace_size); 17 | *s+=tr->match_size,*d+=tr->replace_size; 18 | return efi_success; 19 | } 20 | return efi_not_found; 21 | } 22 | 23 | static efi_status utf8_to_utf16_convert(encode_convert_ctx*ctx){ 24 | efi_status st,ret=efi_success; 25 | if(!ctx||!ctx->in.src_ptr||!ctx->in.dst_ptr) 26 | return efi_invalid_parameter; 27 | const uint8_t*src=(const uint8_t*)ctx->in.src_ptr; 28 | size_t src_size=ctx->in.src_size; 29 | char16*dst=(char16*)ctx->in.dst_ptr; 30 | size_t dst_size=ctx->in.dst_size/sizeof(char16); 31 | size_t i=0,j=0; 32 | while(iin.transfers){ 34 | size_t si=i, dj=j*sizeof(char16); 35 | st=proc_transfer(ctx,&si,&dj); 36 | if(st==efi_out_of_resources){ 37 | ret=efi_out_of_resources; 38 | break; 39 | }else if(st==efi_success){ 40 | i=si,j=dj/sizeof(char16); 41 | continue; 42 | } 43 | } 44 | uint8_t c=src[i]; 45 | if(c<0x80){ 46 | dst[j++]=c; 47 | i++; 48 | }else if((c&0xE0)==0xC0&&i+1in.allow_invalid){ 55 | ctx->out.have_invalid=true; 56 | dst[j++]='?'; 57 | i++; 58 | }else{ 59 | ctx->out.have_invalid=true; 60 | ret=efi_warn_unknown_glyph; 61 | break; 62 | } 63 | } 64 | dst[j]=0; 65 | ctx->out.src_used=i; 66 | ctx->out.dst_wrote=j*sizeof(char16); 67 | ctx->out.src_end=(void*)(src+i); 68 | ctx->out.dst_end=(void*)(dst+j); 69 | return ret; 70 | } 71 | 72 | static efi_status utf16_to_utf8_convert(encode_convert_ctx*ctx){ 73 | efi_status st,ret=efi_success; 74 | const char16*src=(const char16*)ctx->in.src_ptr; 75 | size_t src_size=ctx->in.src_size/sizeof(char16); 76 | uint8_t*dst=(uint8_t*)ctx->in.dst_ptr; 77 | size_t dst_size=ctx->in.dst_size; 78 | size_t i=0,j=0; 79 | while(iin.transfers){ 81 | size_t si=i*sizeof(char16),dj=j; 82 | st=proc_transfer(ctx,&si,&dj); 83 | if(st==efi_out_of_resources){ 84 | ret=efi_out_of_resources; 85 | break; 86 | }else if(st==efi_success){ 87 | i=si/sizeof(char16),j=dj; 88 | continue; 89 | } 90 | } 91 | char16 wc=src[i]; 92 | if(wc<0x80){ 93 | if(j+1>dst_size)break; 94 | dst[j++]=(uint8_t)wc; 95 | }else if(wc<0x800){ 96 | if(j+2>dst_size)break; 97 | dst[j++]=0xC0|(wc>>6); 98 | dst[j++]=0x80|(wc&0x3F); 99 | }else if(wc>=0xD800&&wc<=0xDFFF){ 100 | ctx->out.have_invalid=true; 101 | if(ctx->in.allow_invalid){ 102 | dst[j++]='?'; 103 | }else{ 104 | ret=efi_warn_unknown_glyph; 105 | break; 106 | } 107 | }else{ 108 | if(j+3>dst_size)break; 109 | dst[j++]=0xE0|(wc>>12); 110 | dst[j++]=0x80|((wc>>6)&0x3F); 111 | dst[j++]=0x80|(wc&0x3F); 112 | } 113 | i++; 114 | } 115 | if(jout.src_used=i*sizeof(char16); 117 | ctx->out.dst_wrote=j; 118 | ctx->out.src_end=(void*)(src+i); 119 | ctx->out.dst_end=(void*)(dst+j); 120 | return ret; 121 | } 122 | 123 | static struct encoding_convert{ 124 | encoding src; 125 | encoding dst; 126 | efi_status(*convert)(encode_convert_ctx*ctx); 127 | }converts[]={ 128 | {ENC_UTF8,ENC_UTF16,utf8_to_utf16_convert}, 129 | {ENC_UTF16,ENC_UTF8,utf16_to_utf8_convert}, 130 | {ENC_NONE,ENC_NONE,NULL}, 131 | }; 132 | 133 | static efi_status copy_convert(encode_convert_ctx*ctx){ 134 | size_t i=0,j=0; 135 | efi_status st,ret=efi_success; 136 | if(ctx->in.transfers){ 137 | uint8_t*dst=(uint8_t*)ctx->in.dst_ptr; 138 | const uint8_t*src=(const uint8_t*)ctx->in.src_ptr; 139 | while(iin.src_size&&jin.dst_size&&!efi_error(ret)){ 140 | st=proc_transfer(ctx,&i,&j); 141 | if(st==efi_out_of_resources)break; 142 | else if(st==efi_not_found)dst[j++]=src[i++]; 143 | else if(st==efi_success)continue; 144 | else ret=st; 145 | } 146 | }else{ 147 | size_t size=MIN(ctx->in.src_size,ctx->in.dst_size); 148 | memcpy(ctx->in.dst_ptr,ctx->in.src_ptr,size); 149 | i=size,j=size; 150 | } 151 | ctx->out.src_used=i; 152 | ctx->out.dst_wrote=j; 153 | ctx->out.src_end=(void*)ctx->in.src_ptr+i; 154 | ctx->out.dst_end=(void*)ctx->in.dst_ptr+j; 155 | return ret; 156 | } 157 | 158 | static efi_status center_convert(encode_convert_ctx*ctx){ 159 | if(ctx->in.transfers)return efi_unsupported; 160 | size_t tmp_buf_size=ctx->in.src_size*4; 161 | uint8_t*tmp_buf=(uint8_t*)malloc(tmp_buf_size); 162 | if(!tmp_buf)return efi_out_of_resources; 163 | encode_convert_ctx src_ctx=*ctx; 164 | src_ctx.in.dst=ENC_UTF8; 165 | src_ctx.in.dst_ptr=tmp_buf; 166 | src_ctx.in.dst_size=tmp_buf_size; 167 | memset(&src_ctx.out,0,sizeof(src_ctx.out)); 168 | efi_status ret=encode_convert(&src_ctx); 169 | if(ret!=efi_success&&ret!=efi_warn_unknown_glyph){ 170 | free(tmp_buf); 171 | return ret; 172 | } 173 | encode_convert_ctx dst_ctx=*ctx; 174 | dst_ctx.in.src=ENC_UTF8; 175 | dst_ctx.in.src_ptr=tmp_buf; 176 | dst_ctx.in.src_size=src_ctx.out.dst_wrote; 177 | memset(&dst_ctx.out,0,sizeof(dst_ctx.out)); 178 | ret=encode_convert(&dst_ctx); 179 | ctx->out=dst_ctx.out; 180 | ctx->out.src_used=src_ctx.out.src_used; 181 | ctx->out.have_invalid=src_ctx.out.have_invalid||dst_ctx.out.have_invalid; 182 | free(tmp_buf); 183 | return ret; 184 | } 185 | 186 | efi_status encode_convert(encode_convert_ctx*ctx){ 187 | if(!ctx||!ctx->in.src_ptr||!ctx->in.dst_ptr) 188 | return efi_invalid_parameter; 189 | if(ctx->in.src==ENC_NONE||ctx->in.dst==ENC_NONE) 190 | return efi_invalid_parameter; 191 | memset(&ctx->out,0,sizeof(ctx->out)); 192 | if(ctx->in.src==ctx->in.dst) 193 | return copy_convert(ctx); 194 | for(int i=0;converts[i].src!=ENC_NONE;i++) 195 | if(ctx->in.src==converts[i].src&&ctx->in.dst==converts[i].dst) 196 | return converts[i].convert(ctx); 197 | if(ctx->in.src!=ENC_UTF8&&ctx->in.dst!=ENC_UTF8) 198 | return center_convert(ctx); 199 | return efi_unsupported; 200 | } 201 | -------------------------------------------------------------------------------- /efifetch/data/string.c: -------------------------------------------------------------------------------- 1 | #include"efi.h" 2 | #include"str.h" 3 | #include"data.h" 4 | 5 | const char*efi_status_to_string(efi_status st){ 6 | switch(st){ 7 | case efi_success: return "Success"; 8 | case efi_warn_unknown_glyph: return "Unknown Glyph"; 9 | case efi_warn_delete_failure: return "Delete Failure"; 10 | case efi_warn_write_failure: return "Write Failure"; 11 | case efi_warn_buffer_too_small: return "Buffer Too Small"; 12 | case efi_warn_stale_data: return "Stale Data"; 13 | case efi_load_error: return "Load Error"; 14 | case efi_invalid_parameter: return "Invalid Parameter"; 15 | case efi_unsupported: return "Unsupported"; 16 | case efi_bad_buffer_size: return "Bad Buffer Size"; 17 | case efi_buffer_too_small: return "Buffer Too Small"; 18 | case efi_not_ready: return "Not Ready"; 19 | case efi_device_error: return "Device Error"; 20 | case efi_write_protected: return "Write Protected"; 21 | case efi_out_of_resources: return "Out of Resources"; 22 | case efi_volume_corrupted: return "Volume Corrupt"; 23 | case efi_volume_full: return "Volume Full"; 24 | case efi_no_media: return "No Media"; 25 | case efi_media_changed: return "Media changed"; 26 | case efi_not_found: return "Not Found"; 27 | case efi_access_denied: return "Access Denied"; 28 | case efi_no_response: return "No Response"; 29 | case efi_no_mapping: return "No mapping"; 30 | case efi_timeout: return "Time out"; 31 | case efi_not_started: return "Not started"; 32 | case efi_already_started: return "Already started"; 33 | case efi_aborted: return "Aborted"; 34 | case efi_icmp_error: return "ICMP Error"; 35 | case efi_tftp_error: return "TFTP Error"; 36 | case efi_protocol_error: return "Protocol Error"; 37 | case efi_incompatible_version: return "Incompatible Version"; 38 | case efi_security_violation: return "Security Violation"; 39 | case efi_crc_error: return "CRC Error"; 40 | case efi_end_of_media: return "End of Media"; 41 | case efi_end_of_file: return "End of File"; 42 | case efi_invalid_language: return "Invalid Language"; 43 | case efi_compromised_data: return "Compromised Data"; 44 | default: return "Unknown"; 45 | } 46 | } 47 | 48 | const char*efi_status_to_short_string(efi_status st){ 49 | switch(st){ 50 | case efi_success: return "success"; 51 | case efi_warn_unknown_glyph: return "warn-unknown-glyph"; 52 | case efi_warn_delete_failure: return "warn-delete-failure"; 53 | case efi_warn_write_failure: return "warn-write-failure"; 54 | case efi_warn_buffer_too_small: return "warn-buffer-too-small"; 55 | case efi_warn_stale_data: return "warn-stale-data"; 56 | case efi_load_error: return "load-error"; 57 | case efi_invalid_parameter: return "invalid-parameter"; 58 | case efi_unsupported: return "unsupported"; 59 | case efi_bad_buffer_size: return "bad-buffer-size"; 60 | case efi_buffer_too_small: return "buffer-too-small"; 61 | case efi_not_ready: return "not-ready"; 62 | case efi_device_error: return "device-error"; 63 | case efi_write_protected: return "write-protected"; 64 | case efi_out_of_resources: return "out-of-resources"; 65 | case efi_volume_corrupted: return "volume-corrupted"; 66 | case efi_volume_full: return "volume-full"; 67 | case efi_no_media: return "no-media"; 68 | case efi_media_changed: return "media-changed"; 69 | case efi_not_found: return "not-found"; 70 | case efi_access_denied: return "access-denied"; 71 | case efi_no_response: return "no-response"; 72 | case efi_no_mapping: return "no-mapping"; 73 | case efi_timeout: return "timeout"; 74 | case efi_not_started: return "not-started"; 75 | case efi_already_started: return "already-started"; 76 | case efi_aborted: return "aborted"; 77 | case efi_icmp_error: return "icmp-error"; 78 | case efi_tftp_error: return "tftp-error"; 79 | case efi_protocol_error: return "protocol-error"; 80 | case efi_incompatible_version: return "incompatible-version"; 81 | case efi_security_violation: return "security-violation"; 82 | case efi_crc_error: return "crc-error"; 83 | case efi_end_of_media: return "end-of-media"; 84 | case efi_end_of_file: return "end-of-file"; 85 | case efi_invalid_language: return "invalid-language"; 86 | case efi_compromised_data: return "compromised-data"; 87 | default: return "unknown"; 88 | } 89 | } 90 | 91 | const char*efi_memory_type_to_string(efi_memory_type type){ 92 | switch(type){ 93 | case efi_reserved_memory_type: return "Reserved"; 94 | case efi_loader_code: return "Loader Code"; 95 | case efi_loader_data: return "Loader Data"; 96 | case efi_bs_code: return "Boot Services Code"; 97 | case efi_bs_data: return "Boot Services Data"; 98 | case efi_rs_code: return "Runtime Services Code"; 99 | case efi_rs_data: return "Runtime Services Data"; 100 | case efi_conventional_memory: return "Conventional"; 101 | case efi_unusable_memory: return "Unusable"; 102 | case efi_acpi_reclaim_memory: return "ACPI Reclaim"; 103 | case efi_acpi_memory_nvs: return "ACPI Memory NVS"; 104 | case efi_mmio: return "MMIO"; 105 | case efi_mmio_port_space: return "MMIO Port Space"; 106 | case efi_pal_code: return "Pal Code"; 107 | case efi_persistent_memory: return "Persistent"; 108 | case efi_max_memory_type: return "Max"; 109 | default: return "Unknown"; 110 | } 111 | } 112 | 113 | const char*efi_guid_to_string(const efi_guid*guid,char*buff,size_t len){ 114 | if(!guid||!buff||len<=0)return NULL; 115 | memset(buff,0,len); 116 | struct guid*g=(struct guid*)guid; 117 | snprintf(buff,len-1, 118 | "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 119 | g->data1,g->data2,g->data3, 120 | g->data4[0],g->data4[1],g->data4[2],g->data4[3], 121 | g->data4[4],g->data4[5],g->data4[6],g->data4[7] 122 | ); 123 | return buff; 124 | } 125 | 126 | const char*efi_guid_to_readable_string(const efi_guid*guid,char*buff,size_t len){ 127 | if(!guid||!buff||len<=0)return NULL; 128 | memset(buff,0,len); 129 | for(size_t i=0;efi_guid_table[i].guid;i++){ 130 | if(memcmp(guid,efi_guid_table[i].guid,sizeof(efi_guid))!=0)continue; 131 | if(!efi_guid_table[i].name||!efi_guid_table[i].name[0])continue; 132 | strncpy(buff,efi_guid_table[i].name,len-1); 133 | return buff; 134 | } 135 | return efi_guid_to_string(guid,buff,len); 136 | } 137 | -------------------------------------------------------------------------------- /efifetch/lib/str.c: -------------------------------------------------------------------------------- 1 | #include"str.h" 2 | 3 | __weak char*stpcpy(char*d,const char*s){ 4 | if(!d||!s)return NULL; 5 | for(;(*d=*s);s++,d++); 6 | *d=0; 7 | return d; 8 | } 9 | 10 | __weak char*stpncpy(char*d,const char*s,size_t n){ 11 | if(!d||!s)return NULL; 12 | for(;n&&(*d=*s);n--,s++,d++); 13 | memset(d,0,n); 14 | return d; 15 | } 16 | 17 | __weak char*strcpy(char*d,const char*s){ 18 | stpcpy(d,s); 19 | return d; 20 | } 21 | 22 | __weak char*strncpy(char*d,const char*s,size_t n){ 23 | stpncpy(d,s,n); 24 | return d; 25 | } 26 | 27 | __weak size_t strlen(const char*s){ 28 | const char*a=s; 29 | if(!s)return 0; 30 | for(;*s;s++); 31 | return s-a; 32 | } 33 | 34 | __weak size_t strnlen(const char*s,size_t n){ 35 | if(!s)return 0; 36 | const char*p=memchr(s,0,n); 37 | return p?(size_t)(p-s):n; 38 | } 39 | 40 | __weak char*strchrnul(const char*s,int c){ 41 | if(!s)return NULL; 42 | c=(unsigned char)c; 43 | if(!c)return (char*)s+strlen(s); 44 | for(;*s&&*(unsigned char*)s!=c;s++); 45 | return (char*)s; 46 | } 47 | 48 | __weak char*strchr(const char*s,int c){ 49 | if(!s)return NULL; 50 | char*r=strchrnul(s,c); 51 | return*(unsigned char*)r==(unsigned char)c?r:0; 52 | } 53 | 54 | __weak char*strrchr(const char*s,int c){ 55 | if(!s)return NULL; 56 | return memrchr(s,c,strlen(s)+1); 57 | } 58 | 59 | __weak size_t strlcat(char*d,const char*s,size_t n){ 60 | if(!d||!s)return 0; 61 | size_t l=strnlen(d,n); 62 | if(l==n)return l+strlen(s); 63 | return l+strlcpy(d+l,s,n-l); 64 | } 65 | 66 | __weak size_t strlcpy(char*d,const char*s,size_t n){ 67 | if(!d||!s)return 0; 68 | char*d0=d; 69 | if(n--)strncpy(d,s,n); 70 | return d-d0+strlen(s); 71 | } 72 | 73 | __weak size_t strlncat(char*d,const char*s,size_t n,size_t c){ 74 | if(!d||!s)return 0; 75 | size_t l=strnlen(d,n); 76 | size_t x=strnlen(s,c); 77 | if(l==n)return l+x; 78 | return l+strlcpy(d+l,s,MIN(n-l,x+1)); 79 | } 80 | 81 | __weak int strcasecmp(const char*_l,const char*_r){ 82 | const unsigned char*l=(void*)_l,*r=(void*)_r; 83 | if(l==r)return 0; 84 | if(!l||!r)return 1; 85 | for(;*l&&*r&&(*l==*r||tolower(*l)==tolower(*r));l++,r++); 86 | return tolower(*l)-tolower(*r); 87 | } 88 | 89 | __weak char*strcasestr(const char*h,const char*n){ 90 | if(!h||!n)return NULL; 91 | size_t l=strlen(n); 92 | for(;*h;h++)if(!strncasecmp(h,n,l))return (char*)h; 93 | return 0; 94 | } 95 | 96 | __weak char*strcat(char*dest,const char*src){ 97 | if(!dest||!src)return NULL; 98 | strcpy(dest+strlen(dest),src); 99 | return dest; 100 | } 101 | 102 | __weak int strcoll(const char*l,const char*r){ 103 | return strcmp(l,r); 104 | } 105 | 106 | __weak size_t strcspn(const char*s,const char*c){ 107 | if(!s||!c)return 0; 108 | const char*a=s; 109 | size_t byteset[32/sizeof(size_t)]; 110 | if(!c[0]||!c[1])return strchrnul(s,*c)-a; 111 | memset(byteset,0,sizeof(byteset)); 112 | #define BITOP(a,b,op)((a)[(size_t)(b)/(8*sizeof*(a))] op(size_t)1<<((size_t)(b)%(8*sizeof*(a)))) 113 | for(;*c&&BITOP(byteset,*(unsigned char*)c,|=);c++); 114 | for(;*s&&!BITOP(byteset,*(unsigned char*)s,&);s++); 115 | #undef BITOP 116 | return s-a; 117 | } 118 | 119 | __weak int strncasecmp(const char*_l,const char*_r,size_t n){ 120 | const unsigned char*l=(void*)_l,*r=(void*)_r; 121 | if(l==r)return 0; 122 | if(!l||!r)return 1; 123 | if(!n--)return 0; 124 | for(;*l&&*r&&n&&(*l==*r||tolower(*l)==tolower(*r));l++,r++,n--); 125 | return tolower(*l)-tolower(*r); 126 | } 127 | 128 | __weak char*strpbrk(const char*s,const char*b){ 129 | if(!s)return NULL; 130 | s+=strcspn(s,b); 131 | return *s?(char*)s:0; 132 | } 133 | 134 | __weak char*strsep(char**str,const char*sep){ 135 | char *s=*str,*end; 136 | if(!s)return NULL; 137 | end=s+strcspn(s,sep); 138 | if(*end)*end++=0; 139 | else end=0; 140 | *str=end; 141 | return s; 142 | } 143 | 144 | __weak size_t strspn(const char*s,const char*c){ 145 | const char *a=s; 146 | size_t byteset[32/sizeof(size_t)]={0}; 147 | if(!s||!c)return 0; 148 | if(!c[0])return 0; 149 | if(!c[1]){ 150 | for(;*s==*c;s++); 151 | return s-a; 152 | } 153 | #define BITOP(a,b,op) ((a)[(size_t)(b)/(8*sizeof*(a))]op(size_t)1<<((size_t)(b)%(8*sizeof*(a)))) 154 | for(;*c&&BITOP(byteset,*(unsigned char*)c,|=);c++); 155 | for(;*s&&BITOP(byteset,*(unsigned char*)s,&);s++); 156 | #undef BITOP 157 | return s-a; 158 | } 159 | 160 | __weak char*strstr(const char*h,const char*n){ 161 | if(!h||!n||!*n)return (char*)h; 162 | size_t hl=strlen(h),nl=strlen(n); 163 | return memmem(h,hl,n,nl); 164 | } 165 | 166 | __weak char*strtok(char*s,const char*sep){ 167 | static char *p; 168 | if(!s&&!(s=p))return NULL; 169 | s+=strspn(s,sep); 170 | if(!*s)return p=0; 171 | p=s+strcspn(s,sep); 172 | if(*p)*p++=0; 173 | else p=0; 174 | return s; 175 | } 176 | 177 | __weak bool startwith(const char*str,char c){ 178 | if(!str)return false; 179 | return str[0]==c; 180 | } 181 | 182 | __weak bool startwiths(const char*str,const char*s){ 183 | if(!str||!s)return false; 184 | return strncmp(str,s,strlen(s))==0; 185 | } 186 | 187 | __weak bool startnwith(const char*str,size_t len,char c){ 188 | if(!str||len<=0)return false; 189 | return str[0]==c; 190 | } 191 | 192 | __weak bool startnwiths(const char*str,size_t len,const char*s){ 193 | if(!str||len<=0)return false; 194 | return strncmp(str,s,strnlen(s,len))==0; 195 | } 196 | 197 | __weak bool endwith(const char*str,char c){ 198 | if(!str)return false; 199 | size_t l=strlen(str); 200 | return l>0&&str[l-1]==c; 201 | } 202 | 203 | __weak bool endwiths(const char*str,const char*s){ 204 | if(!str||!s)return false; 205 | size_t ll=strlen(str),rl=strlen(s); 206 | if(rl==0)return true; 207 | if(rl>ll)return false; 208 | return strncmp(str+ll-rl,s,rl)==0; 209 | } 210 | 211 | __weak bool endnwith(const char*str,size_t len,char c){ 212 | if(!str||len<=0)return false; 213 | size_t l=strnlen(str,len); 214 | return l>0&&str[l-1]==c; 215 | } 216 | 217 | __weak bool endnwiths(const char*str,size_t len,const char*s){ 218 | if(!str||len<=0)return false; 219 | size_t ll=strnlen(str,len),rl=strlen(s); 220 | if(rl==0)return true; 221 | if(rl>ll)return false; 222 | return strncmp(str+ll-rl,s,rl)==0; 223 | } 224 | 225 | __weak bool removeend(char*str,char c){ 226 | if(!str)return false; 227 | size_t l=strlen(str); 228 | bool r=(l>0&&str[l-1]==c); 229 | if(r)str[l-1]=0; 230 | return r; 231 | } 232 | 233 | __weak bool removeends(char*str,const char*s){ 234 | if(!str||!s)return false; 235 | size_t ll=strlen(str),rl=strlen(s); 236 | if(rl==0)return true; 237 | if(rl>ll)return false; 238 | bool r=strncmp(str+ll-rl,s,rl)==0; 239 | if(r)memset(str+ll-rl,0,rl); 240 | return r; 241 | } 242 | 243 | __weak void trimleft(char*str){ 244 | if(!str||!str[0])return; 245 | char*start=str; 246 | while(*start&&isspace(*start))start++; 247 | if(start!=str){ 248 | if(!*start)str[0]=0; 249 | memmove(str,start,strlen(start)+1); 250 | } 251 | } 252 | 253 | __weak void trimright(char*str){ 254 | if(!str||!str[0])return; 255 | char*end=str+strlen(str); 256 | while(end>str&&isspace(end[-1]))end--; 257 | *end=0; 258 | } 259 | 260 | __weak void trim(char*str){ 261 | if(!str||!str[0])return; 262 | trimright(str); 263 | trimleft(str); 264 | } 265 | -------------------------------------------------------------------------------- /efifetch/include/libfdt_internal.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ 2 | #ifndef LIBFDT_INTERNAL_H 3 | #define LIBFDT_INTERNAL_H 4 | /* 5 | * libfdt - Flat Device Tree manipulation 6 | * Copyright (C) 2006 David Gibson, IBM Corporation. 7 | */ 8 | #include "fdt.h" 9 | #include "libfdt_env.h" 10 | 11 | #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) 12 | #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) 13 | 14 | int32_t fdt_ro_probe_(const void *fdt); 15 | #define FDT_RO_PROBE(fdt) \ 16 | { \ 17 | int32_t totalsize_; \ 18 | if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \ 19 | return totalsize_; \ 20 | } 21 | 22 | int fdt_check_node_offset_(const void *fdt, int offset); 23 | int fdt_check_prop_offset_(const void *fdt, int offset); 24 | 25 | const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s, 26 | int s_len); 27 | static inline const char *fdt_find_string_(const char *strtab, int tabsize, 28 | const char *s) 29 | { 30 | return fdt_find_string_len_(strtab, tabsize, s, strlen(s)); 31 | } 32 | 33 | int fdt_node_end_offset_(void *fdt, int nodeoffset); 34 | 35 | static inline const void *fdt_offset_ptr_(const void *fdt, int offset) 36 | { 37 | return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; 38 | } 39 | 40 | static inline void *fdt_offset_ptr_w_(void *fdt, int offset) 41 | { 42 | return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset); 43 | } 44 | 45 | static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n) 46 | { 47 | const struct fdt_reserve_entry *rsv_table = 48 | (const struct fdt_reserve_entry *) 49 | ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); 50 | 51 | return rsv_table + n; 52 | } 53 | static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) 54 | { 55 | return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n); 56 | } 57 | 58 | /* 59 | * Internal helpers to access structural elements of the device tree 60 | * blob (rather than for example reading integers from within property 61 | * values). We assume that we are either given a naturally aligned 62 | * address for the platform or if we are not, we are on a platform 63 | * where unaligned memory reads will be handled in a graceful manner. 64 | * If not the external helpers fdtXX_ld() from libfdt.h can be used 65 | * instead. 66 | */ 67 | static inline uint32_t fdt32_ld_(const fdt32_t *p) 68 | { 69 | return fdt32_to_cpu(*p); 70 | } 71 | 72 | static inline uint64_t fdt64_ld_(const fdt64_t *p) 73 | { 74 | return fdt64_to_cpu(*p); 75 | } 76 | 77 | #define FDT_SW_MAGIC (~FDT_MAGIC) 78 | 79 | /**********************************************************************/ 80 | /* Checking controls */ 81 | /**********************************************************************/ 82 | 83 | #ifndef FDT_ASSUME_MASK 84 | #define FDT_ASSUME_MASK 0 85 | #endif 86 | 87 | /* 88 | * Defines assumptions which can be enabled. Each of these can be enabled 89 | * individually. For maximum safety, don't enable any assumptions! 90 | * 91 | * For minimal code size and no safety, use ASSUME_PERFECT at your own risk. 92 | * You should have another method of validating the device tree, such as a 93 | * signature or hash check before using libfdt. 94 | * 95 | * For situations where security is not a concern it may be safe to enable 96 | * ASSUME_SANE. 97 | */ 98 | enum { 99 | /* 100 | * This does essentially no checks. Only the latest device-tree 101 | * version is correctly handled. Inconsistencies or errors in the device 102 | * tree may cause undefined behaviour or crashes. Invalid parameters 103 | * passed to libfdt may do the same. 104 | * 105 | * If an error occurs when modifying the tree it may leave the tree in 106 | * an intermediate (but valid) state. As an example, adding a property 107 | * where there is insufficient space may result in the property name 108 | * being added to the string table even though the property itself is 109 | * not added to the struct section. 110 | * 111 | * Only use this if you have a fully validated device tree with 112 | * the latest supported version and wish to minimise code size. 113 | */ 114 | ASSUME_PERFECT = 0xff, 115 | 116 | /* 117 | * This assumes that the device tree is sane. i.e. header metadata 118 | * and basic hierarchy are correct. 119 | * 120 | * With this assumption enabled, normal device trees produced by libfdt 121 | * and the compiler should be handled safely. Malicious device trees and 122 | * complete garbage may cause libfdt to behave badly or crash. Truncated 123 | * device trees (e.g. those only partially loaded) can also cause 124 | * problems. 125 | * 126 | * Note: Only checks that relate exclusively to the device tree itself 127 | * (not the parameters passed to libfdt) are disabled by this 128 | * assumption. This includes checking headers, tags and the like. 129 | */ 130 | ASSUME_VALID_DTB = 1 << 0, 131 | 132 | /* 133 | * This builds on ASSUME_VALID_DTB and further assumes that libfdt 134 | * functions are called with valid parameters, i.e. not trigger 135 | * FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any 136 | * extensive checking of parameters and the device tree, making various 137 | * assumptions about correctness. 138 | * 139 | * It doesn't make sense to enable this assumption unless 140 | * ASSUME_VALID_DTB is also enabled. 141 | */ 142 | ASSUME_VALID_INPUT = 1 << 1, 143 | 144 | /* 145 | * This disables checks for device-tree version and removes all code 146 | * which handles older versions. 147 | * 148 | * Only enable this if you know you have a device tree with the latest 149 | * version. 150 | */ 151 | ASSUME_LATEST = 1 << 2, 152 | 153 | /* 154 | * This assumes that it is OK for a failed addition to the device tree, 155 | * due to lack of space or some other problem, to skip any rollback 156 | * steps (such as dropping the property name from the string table). 157 | * This is safe to enable in most circumstances, even though it may 158 | * leave the tree in a sub-optimal state. 159 | */ 160 | ASSUME_NO_ROLLBACK = 1 << 3, 161 | 162 | /* 163 | * This assumes that the device tree components appear in a 'convenient' 164 | * order, i.e. the memory reservation block first, then the structure 165 | * block and finally the string block. 166 | * 167 | * This order is not specified by the device-tree specification, 168 | * but is expected by libfdt. The device-tree compiler always created 169 | * device trees with this order. 170 | * 171 | * This assumption disables a check in fdt_open_into() and removes the 172 | * ability to fix the problem there. This is safe if you know that the 173 | * device tree is correctly ordered. See fdt_blocks_misordered_(). 174 | */ 175 | ASSUME_LIBFDT_ORDER = 1 << 4, 176 | 177 | /* 178 | * This assumes that libfdt itself does not have any internal bugs. It 179 | * drops certain checks that should never be needed unless libfdt has an 180 | * undiscovered bug. 181 | * 182 | * This can generally be considered safe to enable. 183 | */ 184 | ASSUME_LIBFDT_FLAWLESS = 1 << 5, 185 | }; 186 | 187 | /** 188 | * can_assume_() - check if a particular assumption is enabled 189 | * 190 | * @mask: Mask to check (ASSUME_...) 191 | * @return true if that assumption is enabled, else false 192 | */ 193 | static inline bool can_assume_(int mask) 194 | { 195 | return FDT_ASSUME_MASK & mask; 196 | } 197 | 198 | /** helper macros for checking assumptions */ 199 | #define can_assume(_assume) can_assume_(ASSUME_ ## _assume) 200 | 201 | #endif /* LIBFDT_INTERNAL_H */ 202 | -------------------------------------------------------------------------------- /efifetch/info/disk.c: -------------------------------------------------------------------------------- 1 | #include"info.h" 2 | #include"readable.h" 3 | #include"print.h" 4 | #include"utils.h" 5 | #include"init.h" 6 | #include"disk.h" 7 | #include"str.h" 8 | 9 | static bool get_cur_disk_info(efi_handle*hand,efi_disk_info_protocol**di){ 10 | efi_status st; 11 | efi_handle h=efi_get_current_device(); 12 | while(h){ 13 | efi_disk_info_protocol*info=NULL; 14 | st=g_bs->handle_proto(h,&gEfiDiskInfoProtocolGuid,(void**)&info); 15 | if(!efi_error(st)&&info){ 16 | *hand=h,*di=info; 17 | return true; 18 | } 19 | dbg_printf("disk %p get disk info protocol: %m\n",h,st); 20 | h=efi_get_parent_device(h); 21 | } 22 | return false; 23 | } 24 | 25 | struct disk_info{ 26 | char type[64]; 27 | char vendor[64]; 28 | char model[64]; 29 | uint64_t size; 30 | }; 31 | 32 | static efi_status disk_fill_size_block_io(efi_handle hand,struct disk_info*info){ 33 | efi_status st; 34 | efi_block_io_protocol*bio=NULL; 35 | st=g_bs->handle_proto(hand,&gEfiBlockIoProtocolGuid,(void**)&bio); 36 | if(efi_error(st)){ 37 | dbg_printf("disk %p get block io failed: %m\n",hand,st); 38 | return st; 39 | } 40 | dbg_printf("disk %p found block io %p\n",hand,bio); 41 | dbg_printf("disk %p last blocks %llu\n",hand,bio->media->last_block); 42 | dbg_printf("disk %p last blocks 0x%llx\n",hand,bio->media->last_block); 43 | uint64_t blocks=bio->media->last_block+1; 44 | dbg_printf("disk %p blocks %llu\n",hand,blocks); 45 | dbg_printf("disk %p block size %u\n",hand,bio->media->block_size); 46 | info->size=bio->media->block_size*blocks; 47 | dbg_printf("disk %p size %llu\n",hand,info->size); 48 | return efi_success; 49 | } 50 | 51 | static efi_status disk_get_scsi(efi_handle hand,efi_disk_info_protocol*proto,struct disk_info*info){ 52 | efi_status st; 53 | scsi_inquiry_data data; 54 | uint32_t size=sizeof(data); 55 | memset(&data,0,size); 56 | st=proto->inquiry(proto,&data,&size); 57 | if(efi_error(st)){ 58 | dbg_printf("disk %p usb inquiry failed: %m\n",hand,st); 59 | return st; 60 | } 61 | memcpy(info->vendor,data.vendor_id,sizeof(data.vendor_id)); 62 | memcpy(info->model,data.product_id,sizeof(data.product_id)); 63 | return efi_success; 64 | } 65 | 66 | static efi_status disk_get_usb(efi_handle hand,efi_disk_info_protocol*proto,struct disk_info*info){ 67 | efi_status st; 68 | usb_boot_inquiry_data data; 69 | uint32_t size=sizeof(data); 70 | memset(&data,0,size); 71 | st=proto->inquiry(proto,&data,&size); 72 | if(efi_error(st)){ 73 | dbg_printf("disk %p usb inquiry failed: %m\n",hand,st); 74 | return st; 75 | } 76 | memcpy(info->vendor,data.vendor_id,sizeof(data.vendor_id)); 77 | memcpy(info->model,data.product_id,sizeof(data.product_id)); 78 | return efi_success; 79 | } 80 | 81 | static efi_status disk_get_ata(efi_handle hand,efi_disk_info_protocol*proto,struct disk_info*info){ 82 | efi_status st; 83 | ata_identify_data data; 84 | uint32_t size=sizeof(data); 85 | memset(&data,0,size); 86 | st=proto->identify(proto,&data,&size); 87 | if(efi_error(st)){ 88 | dbg_printf("disk %p ata inquiry failed: %m\n",hand,st); 89 | return st; 90 | } 91 | for(uintn_t i=0;i+1model[i]=data.model_name[i+1]; 93 | info->model[i+1]=data.model_name[i]; 94 | } 95 | return efi_success; 96 | } 97 | 98 | static efi_status disk_get_nvme(efi_handle hand,efi_disk_info_protocol*proto,struct disk_info*info){ 99 | efi_status st; 100 | nvme_admin_controller_data*data; 101 | efi_nvme_passthru_protocol*pt=NULL; 102 | efi_nvme_passthru_cmd_pkt cmdpkt; 103 | efi_nvme_completion comp; 104 | efi_device_path_protocol*dp; 105 | efi_handle handle=hand; 106 | efi_nvme_cmd cmd; 107 | memset(&cmd,0,sizeof(cmd)); 108 | memset(&cmdpkt,0,sizeof(cmdpkt)); 109 | memset(&comp,0,sizeof(comp)); 110 | st=g_bs->handle_proto(hand,&gEfiDevicePathProtocolGuid,(void**)&dp); 111 | if (efi_error (st)) { 112 | dbg_printf("disk %p handle device path failed: %m\n",hand,st); 113 | return st; 114 | } 115 | st=g_bs->locate_device_path(&gEfiNvmExpressPassThruProtocolGuid,&dp,&handle); 116 | if(efi_error(st)||!handle){ 117 | dbg_printf("disk %p handle get controller failed: %m\n",hand,st); 118 | return st; 119 | } 120 | if(dp->type!=3||dp->sub_type!=0x17){ 121 | dbg_printf("disk %p device path type mismatch %x %x\n",hand,dp->type,dp->sub_type); 122 | return efi_unsupported; 123 | } 124 | dbg_printf("disk %p found nvme controller handle %p\n",hand,handle); 125 | st=g_bs->handle_proto(handle,&gEfiNvmExpressPassThruProtocolGuid,(void**)&pt); 126 | if(efi_error(st)||!pt){ 127 | dbg_printf("disk %p handle get passthru protocol failed: %m\n",handle,st); 128 | return st; 129 | } 130 | if(!(data=zalloc(sizeof(*data)))){ 131 | dbg_print("allocate nvme_admin_controller_data failed\n"); 132 | return efi_out_of_resources; 133 | } 134 | cmd.cdw0.opcode=6; 135 | cmd.nsid=0; 136 | cmdpkt.nvme_cmd=&cmd; 137 | cmdpkt.nvme_completion=∁ 138 | cmdpkt.transfer_buffer=data; 139 | cmdpkt.transfer_length=sizeof(*data); 140 | cmdpkt.cmd_timeout=50000000; 141 | cmdpkt.queue_type=NVME_ADMIN_QUEUE; 142 | cmd.cdw10=1; 143 | cmd.flags=CDW10_VALID; 144 | st=pt->passthru(pt,0,&cmdpkt,NULL); 145 | if(efi_error(st)){ 146 | dbg_printf("disk %p nvme passthru failed: %m\n",handle,st); 147 | free(data); 148 | return st; 149 | } 150 | memcpy(info->model,data->mn,sizeof(data->mn)); 151 | free(data); 152 | return efi_success; 153 | } 154 | 155 | static efi_status disk_get_sdmmc(efi_handle hand,efi_disk_info_protocol*proto,struct disk_info*info){ 156 | return efi_unsupported; 157 | } 158 | 159 | static struct disk_type{ 160 | const char*name; 161 | const efi_guid*intf; 162 | efi_status(*get_info)(efi_handle hand,efi_disk_info_protocol*proto,struct disk_info*info); 163 | }disk_types[]={ 164 | {"IDE", &gEfiDiskInfoIdeInterfaceGuid, disk_get_ata}, 165 | {"SCSI", &gEfiDiskInfoScsiInterfaceGuid, disk_get_scsi}, 166 | {"USB", &gEfiDiskInfoUsbInterfaceGuid, disk_get_usb}, 167 | {"SATA", &gEfiDiskInfoAhciInterfaceGuid, disk_get_ata}, 168 | {"NVMe", &gEfiDiskInfoNvmeInterfaceGuid, disk_get_nvme}, 169 | {"UFS", &gEfiDiskInfoUfsInterfaceGuid, disk_get_scsi}, 170 | {"SD/MMC", &gEfiDiskInfoSdMmcInterfaceGuid, disk_get_sdmmc}, 171 | {NULL,NULL,NULL} 172 | }; 173 | 174 | void efifetch_load_info_disk(efifetch*ctx){ 175 | efi_status st; 176 | efi_handle handle=NULL; 177 | efi_disk_info_protocol*info=NULL; 178 | if(!IS_EMPTY(DISK))return; 179 | get_cur_disk_info(&handle,&info); 180 | if(!handle||!info){ 181 | dbg_print("skip disk because no handle or info\n"); 182 | return; 183 | } 184 | RESET(DISK); 185 | struct disk_type*t=NULL; 186 | for(uintn_t i=0;disk_types[i].intf;i++) 187 | if(memcmp(&info->interface,disk_types[i].intf,sizeof(efi_guid))==0) 188 | t=&disk_types[i]; 189 | if(!t){ 190 | dbg_printf("disk %p unknown interface type\n",handle); 191 | return; 192 | } 193 | SET(DISK,t->name); 194 | struct disk_info dinfo={}; 195 | st=t->get_info(handle,info,&dinfo); 196 | if(efi_error(st)){ 197 | dbg_printf("disk %p get info failed: %m\n",handle,st); 198 | return; 199 | } 200 | char str_size[32]={}; 201 | trim(dinfo.type); 202 | trim(dinfo.vendor); 203 | trim(dinfo.model); 204 | if(dinfo.type[0])SET(DISK,dinfo.type); 205 | if(dinfo.vendor[0]){ 206 | if(!IS_EMPTY(DISK))APPEND(DISK," / "); 207 | APPEND(DISK,dinfo.vendor); 208 | } 209 | if(dinfo.model[0]){ 210 | if(!IS_EMPTY(DISK))APPEND(DISK," / "); 211 | APPEND(DISK,dinfo.model); 212 | } 213 | if(dinfo.size==0)disk_fill_size_block_io(handle,&dinfo); 214 | if(dinfo.size>0){ 215 | format_size_float_ex( 216 | str_size,sizeof(str_size), 217 | dinfo.size,size_units_b,1000,2 218 | ); 219 | if(!IS_EMPTY(DISK))APPEND(DISK," / "); 220 | APPEND(DISK,str_size); 221 | } 222 | } 223 | --------------------------------------------------------------------------------