#!/bin/sh
-DSTDIR=../../IMG/cpio/ventoy/busybox
+DSTDIR1=../../IMG/cpio_x86/ventoy/busybox
+DSTDIR2=../../IMG/cpio_arm64/ventoy/busybox
+DSTDIR3=../../IMG/cpio_mips64/ventoy/busybox
rm -f vtchmod32 vtchmod64 vtchmod64_musl vtchmodaa64
-rm -f $DSTDIR/vtchmod32 $DSTDIR/vtchmod64 $DSTDIR/vtchmodaa64 $DSTDIR/vtchmodm64e
+rm -f $DSTDIR1/vtchmod32 $DSTDIR1/vtchmod64 $DSTDIR2/vtchmodaa64 $DSTDIR3/vtchmodm64e
/opt/diet32/bin/diet gcc -Os -m32 vtchmod.c -o vtchmod32
/opt/diet64/bin/diet gcc -Os vtchmod.c -o vtchmod64
chmod 777 vtchmod64_musl
chmod 777 vtchmodm64e
-cp -a vtchmod32 $DSTDIR/
-cp -a vtchmod64 $DSTDIR/
-cp -a vtchmodaa64 $DSTDIR/
-cp -a vtchmod64_musl $DSTDIR/
-cp -a vtchmodm64e $DSTDIR/
+cp -a vtchmod32 $DSTDIR1/
+cp -a vtchmod64 $DSTDIR1/
+cp -a vtchmod64_musl $DSTDIR1/
+cp -a vtchmodaa64 $DSTDIR2/
+cp -a vtchmodm64e $DSTDIR3/
+#include <stdio.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/utsname.h>
int main(int argc, char **argv)
{
{
return 1;
}
-
+
+ if (argv[1][0] == '-' && argv[1][1] == '6')
+ {
+ struct utsname buf;
+ if (0 == uname(&buf))
+ {
+ if (strstr(buf.machine, "amd64"))
+ {
+ return 0;
+ }
+
+ if (strstr(buf.machine, "x86_64"))
+ {
+ return 0;
+ }
+ }
+ return 1;
+ }
+
return chmod(argv[1], 0777);
}
--- /dev/null
+
+obj-m += dm_patch.o
+
+EXTRA_CFLAGS := -Wall
+
+dm_patch-objs := dmpatch.o
+
--- /dev/null
+/******************************************************************************
+ * dmpatch.c ---- patch for device-mapper
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/mutex.h>
+#include <linux/mempool.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+
+#define MAX_PATCH 4
+
+#define magic_sig 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF
+
+typedef int (*kprobe_reg_pf)(void *);
+typedef void (*kprobe_unreg_pf)(void *);
+typedef int (*printk_pf)(const char *fmt, ...);
+typedef int (*set_memory_attr_pf)(unsigned long addr, int numpages);
+
+#pragma pack(1)
+typedef struct ko_param
+{
+ unsigned char magic[16];
+ unsigned long struct_size;
+ unsigned long pgsize;
+ unsigned long printk_addr;
+ unsigned long ro_addr;
+ unsigned long rw_addr;
+ unsigned long reg_kprobe_addr;
+ unsigned long unreg_kprobe_addr;
+ unsigned long sym_get_addr;
+ unsigned long sym_get_size;
+ unsigned long sym_put_addr;
+ unsigned long sym_put_size;
+ unsigned long padding[3];
+}ko_param;
+
+#pragma pack()
+
+static printk_pf kprintf = NULL;
+static set_memory_attr_pf set_mem_ro = NULL;
+static set_memory_attr_pf set_mem_rw = NULL;
+static kprobe_reg_pf reg_kprobe = NULL;
+static kprobe_unreg_pf unreg_kprobe = NULL;
+
+static volatile ko_param g_ko_param =
+{
+ { magic_sig },
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+#define CODE_MATCH(code, i) \
+ (code[i] == 0x40 && code[i + 1] == 0x80 && code[i + 2] == 0xce && code[i + 3] == 0x80)
+
+#define vdebug(fmt, args...) if(kprintf) kprintf(KERN_ERR fmt, ##args)
+
+static int notrace dmpatch_replace_code(unsigned long addr, unsigned long size, int expect, const char *desc)
+{
+ int i = 0;
+ int cnt = 0;
+ unsigned long align;
+ unsigned char *patch[MAX_PATCH];
+ unsigned char *opCode = (unsigned char *)addr;
+
+ vdebug("patch for %s 0x%lx %d\n", desc, addr, (int)size);
+
+ for (i = 0; i < (int)size - 4; i++)
+ {
+ if (CODE_MATCH(opCode, i) && cnt < MAX_PATCH)
+ {
+ patch[cnt] = opCode + i + 3;
+ cnt++;
+ }
+ }
+
+ if (cnt != expect || cnt >= MAX_PATCH)
+ {
+ vdebug("patch error: cnt=%d expect=%d\n", cnt, expect);
+ return 1;
+ }
+
+
+ for (i = 0; i < cnt; i++)
+ {
+ opCode = patch[i];
+ align = (unsigned long)opCode / g_ko_param.pgsize * g_ko_param.pgsize;
+
+ set_mem_rw(align, 1);
+ *opCode = 0;
+ set_mem_ro(align, 1);
+ }
+
+ return 0;
+}
+
+static int notrace dmpatch_init(void)
+{
+ int r = 0;
+ int rc = 0;
+
+ kprintf = (printk_pf)(g_ko_param.printk_addr);
+
+ vdebug("dmpatch_init start pagesize=%lu ...\n", g_ko_param.pgsize);
+
+ if (g_ko_param.struct_size != sizeof(ko_param))
+ {
+ vdebug("Invalid struct size %d %d\n", (int)g_ko_param.struct_size, (int)sizeof(ko_param));
+ return -EINVAL;
+ }
+
+ if (g_ko_param.sym_get_addr == 0 || g_ko_param.sym_put_addr == 0 ||
+ g_ko_param.ro_addr == 0 || g_ko_param.rw_addr == 0)
+ {
+ return -EINVAL;
+ }
+
+ set_mem_ro = (set_memory_attr_pf)(g_ko_param.ro_addr);
+ set_mem_rw = (set_memory_attr_pf)(g_ko_param.rw_addr);
+ reg_kprobe = (kprobe_reg_pf)g_ko_param.reg_kprobe_addr;
+ unreg_kprobe = (kprobe_unreg_pf)g_ko_param.unreg_kprobe_addr;
+
+ r = dmpatch_replace_code(g_ko_param.sym_get_addr, g_ko_param.sym_get_size, 2, "dm_get_table_device");
+ if (r)
+ {
+ rc = -EINVAL;
+ goto out;
+ }
+ vdebug("patch dm_get_table_device success\n");
+
+ r = dmpatch_replace_code(g_ko_param.sym_put_addr, g_ko_param.sym_put_size, 1, "dm_put_table_device");
+ if (r)
+ {
+ rc = -EINVAL;
+ goto out;
+ }
+ vdebug("patch dm_put_table_device success\n");
+
+ vdebug("#####################################\n");
+ vdebug("######## dm patch success ###########\n");
+ vdebug("#####################################\n");
+
+out:
+
+ return rc;
+}
+
+static void notrace dmpatch_exit(void)
+{
+
+}
+
+module_init(dmpatch_init);
+module_exit(dmpatch_exit);
+
+
+MODULE_DESCRIPTION("dmpatch driver");
+MODULE_AUTHOR("longpanda <admin@ventoy.net>");
+MODULE_LICENSE("GPL");
+
--- /dev/null
+1. install ubuntu 21.10\r
+2. apt-get install build-essential flex ncurse linux-headers-generic linux-source ...... and so on\r
+3. cp /lib/modules/5.13.0-23-generic/build/Module.symvers ./\r
+4. /boot/config-5.13.0-23-generic as .config make oldconfig\r
+5. make menuconfig \r
+ 1. close CONFIG_STACKPROTECTOR\r
+ 2. close CONFIG_RETPOLINE\r
+\r
+6. modify ./scripts/mod/modpost.c\r
+ 1. skip add_srcversion (just return)\r
+ 2. force add_retpoline (#ifdef --> #ifndef)\r
+\r
+7. make modules_prepare LOCALVERSION=-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r
+\r
+8. Append padding at the end of struct module <include/linux/module.h>\r
+struct module {\r
+ enum module_state state;\r
+\r
+ /* Member of list of modules */\r
+ struct list_head list;\r
+\r
+ /* Unique handle for this module */\r
+ char name[MODULE_NAME_LEN];\r
+ \r
+ ....\r
+ \r
+ char padding[1024];\r
+};\r
+\r
+This is because struct module size is different in different kernel versions or with different CONFIG item.\r
+\r
+\r
+9. make modules M=/home/dmpatch\r
+10. strip --strip-debug /home/dmpatch/dm_patch.ko\r
+\r
IN UINTN MapKey
)
{
+ if (g_org_get_variable)
+ {
+ gRT->GetVariable = g_org_get_variable;
+ g_org_get_variable = NULL;
+ }
+
return g_org_exit_boot_service(ImageHandle, MapKey);
}
CHAR16 gFirstTryBootFile[256] = {0};
+STATIC EFI_GET_VARIABLE g_org_get_variable = NULL;
+STATIC EFI_EXIT_BOOT_SERVICES g_org_exit_boot_service = NULL;
+
/* Boot filename */
UINTN gBootFileStartIndex = 1;
CONST CHAR16 *gEfiBootFileName[] =
return EFI_SUCCESS;
}
+EFI_STATUS EFIAPI ventoy_get_variable_wrapper
+(
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes, OPTIONAL
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ Status = g_org_get_variable(VariableName, VendorGuid, Attributes, DataSize, Data);
+ if (StrCmp(VariableName, L"SecureBoot") == 0)
+ {
+ if ((*DataSize == 1) && Data)
+ {
+ *(UINT8 *)Data = 0;
+ }
+ }
+
+ return Status;
+}
+
+EFI_STATUS EFIAPI ventoy_exit_boot_service_wrapper
+(
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN MapKey
+)
+{
+ if (g_org_get_variable)
+ {
+ gRT->GetVariable = g_org_get_variable;
+ g_org_get_variable = NULL;
+ }
+
+ return g_org_exit_boot_service(ImageHandle, MapKey);
+}
+
+STATIC EFI_STATUS EFIAPI ventoy_disable_secure_boot(IN EFI_HANDLE ImageHandle)
+{
+ UINT8 Value = 0;
+ UINTN DataSize = 1;
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ Status = gRT->GetVariable(L"SecureBoot", &gEfiGlobalVariableGuid, NULL, &DataSize, &Value);
+ if (!EFI_ERROR(Status))
+ {
+ if (DataSize == 1 && Value == 0)
+ {
+ debug("Current secure boot is off, no need to disable");
+ return EFI_SUCCESS;
+ }
+ }
+
+ debug("ventoy_disable_secure_boot");
+
+ /* step1: wrapper security protocol. */
+ /* Do we still need it since we have been loaded ? */
+
+
+ /* step2: fake SecureBoot variable */
+ g_org_exit_boot_service = gBS->ExitBootServices;
+ gBS->ExitBootServices = ventoy_exit_boot_service_wrapper;
+
+ g_org_get_variable = gRT->GetVariable;
+ gRT->GetVariable = ventoy_get_variable_wrapper;
+
+ return EFI_SUCCESS;
+}
+
+
STATIC EFI_STATUS EFIAPI ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle)
{
UINT32 i = 0;
{
g_hook_keyboard = TRUE;
}
+
+ if (g_os_param_reserved[5] == 1 && g_os_param_reserved[2] == ventoy_chain_linux)
+ {
+ ventoy_disable_secure_boot(ImageHandle);
+ }
debug("internal param: secover:%u keyboard:%u", g_fixup_iso9660_secover_enable, g_hook_keyboard);
DebugLib\r
\r
[Guids]\r
+ gEfiGlobalVariableGuid\r
gShellVariableGuid\r
gEfiVirtualCdGuid\r
gEfiFileInfoGuid\r
{
char *pos;
const char *fs = NULL;
+ const char *val = NULL;
const char *cdprompt = NULL;
grub_uint32_t i;
grub_uint8_t chksum = 0;
param->vtoy_reserved[3] = 1;
}
+ param->vtoy_reserved[5] = 0;
+ val = ventoy_get_env("VTOY_LINUX_REMOUNT");
+ if (val && val[0] == '1' && val[1] == 0)
+ {
+ param->vtoy_reserved[5] = 1;
+ }
+
/* calculate checksum */
for (i = 0; i < sizeof(ventoy_os_param); i++)
{
* vtoy_reserved[2]: vtoy_chain_type 0:Linux 1:Windows 2:wimfile
* vtoy_reserved[3]: vtoy_iso_format 0:iso9660 1:udf
* vtoy_reserved[4]: vtoy_windows_cd_prompt
+ * vtoy_reserved[5]: vtoy_linux_remount
*
*/
grub_uint8_t vtoy_reserved[32]; // Internal use by ventoy
fi
fi
+if [ "$VTOY_ARCH" = "i386" ]; then
+ if $BUSYBOX_PATH/vtchmod32 -6; then
+ export VTOY_ARCH=x86_64
+ fi
+fi
+
echo $VTOY_ARCH > $VTOY_PATH/ventoy_arch
export VTOY_BREAK_LEVEL=$(hexdump -n 1 -s 449 -e '1/1 "%02x"' $VTOY_PATH/ventoy_os_param)
export VTOY_DEBUG_LEVEL=$(hexdump -n 1 -s 450 -e '1/1 "%02x"' $VTOY_PATH/ventoy_os_param)
+export VTOY_LINUX_REMOUNT=$(hexdump -n 1 -s 454 -e '1/1 "%02x"' $VTOY_PATH/ventoy_os_param)
#Fixme: busybox shell output redirect seems to have some bug in rhel5
if uname -a | grep -q el5; then
HEAD=$BUSYBOX_PATH/head
VTOY_DM_PATH=/dev/mapper/ventoy
VTOY_DEBUG_LEVEL=$($BUSYBOX_PATH/hexdump -n 1 -s 450 -e '1/1 "%02x"' $VTOY_PATH/ventoy_os_param)
+VTOY_LINUX_REMOUNT=$($BUSYBOX_PATH/hexdump -n 1 -s 454 -e '1/1 "%02x"' $VTOY_PATH/ventoy_os_param)
if [ "$VTOY_DEBUG_LEVEL" = "01" ]; then
if [ -e /dev/console ]; then
fi
}
+ventoy_need_dm_patch() {
+ if [ "$VTOY_LINUX_REMOUNT" != "01" ]; then
+ $BUSYBOX_PATH/false; return
+ fi
+
+ if $GREP -q 'device-mapper' /proc/devices; then
+ :
+ else
+ $BUSYBOX_PATH/false; return
+ fi
+
+ if $GREP -q 'dm_patch' /proc/modules; then
+ $BUSYBOX_PATH/false; return
+ fi
+
+ vtMajorVer=$($BUSYBOX_PATH/uname -r | $AWK -F. '{print $1}')
+ vtMinorVer=$($BUSYBOX_PATH/uname -r | $AWK -F. '{print $2}')
+
+ if [ $vtMajorVer -lt 3 ]; then
+ $BUSYBOX_PATH/false; return
+ elif [ $vtMajorVer -eq 3 -a $vtMinorVer -lt 10 ]; then
+ $BUSYBOX_PATH/false; return
+ fi
+
+
+ $BUSYBOX_PATH/true
+}
+
+ventoy_dm_patch() {
+ vtMType=$($BUSYBOX_PATH/uname -m)
+
+ vtlog "######### ventoy_dm_patch ############"
+
+ if echo $vtMType | $EGREP -i -q "x86.64|amd64"; then
+ vtKoName=dm_patch_64.ko
+ else
+ vtlog "unsupported machine type $vtMType"
+ return
+ fi
+
+ if [ -f $VTOY_PATH/tool/$vtKoName ]; then
+ vtlog "/ventoy/tool/$vtKoName exist OK"
+ else
+ vtlog "/ventoy/tool/$vtKoName NOT exist"
+ return
+ fi
+
+ $CAT /proc/kallsyms | $BUSYBOX_PATH/sort > $VTOY_PATH/kallsyms
+
+ vtLine=$($VTOY_PATH/tool/vtoyksym dm_get_table_device $VTOY_PATH/kallsyms)
+ get_addr=$(echo $vtLine | $AWK '{print $1}')
+ get_size=$(echo $vtLine | $AWK '{print $2}')
+
+ vtLine=$($VTOY_PATH/tool/vtoyksym dm_put_table_device $VTOY_PATH/kallsyms)
+ put_addr=$(echo $vtLine | $AWK '{print $1}')
+ put_size=$(echo $vtLine | $AWK '{print $2}')
+
+ ro_addr=$($GREP ' set_memory_ro$' /proc/kallsyms | $AWK '{print $1}')
+ rw_addr=$($GREP ' set_memory_rw$' /proc/kallsyms | $AWK '{print $1}')
+ kprobe_reg_addr=$($GREP ' register_kprobe$' /proc/kallsyms | $AWK '{print $1}')
+ kprobe_unreg_addr=$($GREP ' unregister_kprobe$' /proc/kallsyms | $AWK '{print $1}')
+
+ if [ "$VTOY_DEBUG_LEVEL" = "01" ]; then
+ printk_addr=$($GREP ' printk$' /proc/kallsyms | $AWK '{print $1}')
+ vtDebug="-v"
+ else
+ printk_addr=0
+ fi
+
+ #printk_addr=$($GREP ' printk$' /proc/kallsyms | $AWK '{print $1}')
+ #vtDebug="-v"
+
+ vtlog get_addr=$get_addr get_size=$get_size
+ vtlog put_addr=$put_addr put_size=$put_size
+ vtlog kprobe_reg_addr=$kprobe_reg_addr kprobe_unreg_addr=$kprobe_unreg_addr
+ vtlog ro_addr=$ro_addr rw_addr=$rw_addr printk_addr=$printk_addr
+
+ if [ "$get_addr" = "0" -o "$put_addr" = "0" ]; then
+ vtlog "Invalid symbol address"
+ return
+ fi
+ if [ "$ro_addr" = "0" -o "$rw_addr" = "0" ]; then
+ vtlog "Invalid symbol address"
+ return
+ fi
+
+
+ vtKv=$($BUSYBOX_PATH/uname -r)
+ vtModPath=$($FIND /lib/modules/$vtKv/kernel/fs/ -name "*.ko*" | $HEAD -n1)
+ vtModName=$($BUSYBOX_PATH/basename $vtModPath)
+
+ vtlog "template module is $vtModPath $vtModName"
+
+ if echo $vtModPath | $GREP -q "[.]ko$"; then
+ $BUSYBOX_PATH/cp -a $vtModPath $VTOY_PATH/$vtModName
+ elif echo $vtModPath | $GREP -q "[.]ko[.]xz$"; then
+ $BUSYBOX_PATH/xzcat $vtModPath > $VTOY_PATH/$vtModName
+ elif echo $vtModPath | $GREP -q "[.]ko[.]gz$"; then
+ $BUSYBOX_PATH/zcat $vtModPath > $VTOY_PATH/$vtModName
+ else
+ vtlog "unsupport module type"
+ return
+ fi
+
+ #step1: modify vermagic/mod crc/relocation
+ $VTOY_PATH/tool/vtoykmod -u $VTOY_PATH/tool/$vtKoName $VTOY_PATH/$vtModName $vtDebug
+
+ #step2: fill parameters
+ vtPgsize=$($VTOY_PATH/tool/vtoyksym -p)
+ $VTOY_PATH/tool/vtoykmod -f $VTOY_PATH/tool/$vtKoName $vtPgsize 0x$printk_addr 0x$ro_addr 0x$rw_addr $get_addr $get_size $put_addr $put_size 0x$kprobe_reg_addr 0x$kprobe_unreg_addr $vtDebug
+
+ $BUSYBOX_PATH/insmod $VTOY_PATH/tool/$vtKoName
+
+ if $GREP -q 'dm_patch' /proc/modules; then
+ echo "done" > $VTOY_PATH/dm_patch_done
+ fi
+
+}
+
create_ventoy_device_mapper() {
vtlog "create_ventoy_device_mapper $*"
fi
vtlog "dmsetup avaliable in system $VT_DM_BIN"
-
+
if ventoy_check_dm_module "$1"; then
vtlog "device-mapper module check success"
else
vterr "Error: no dm module avaliable"
fi
- $VTOY_PATH/tool/vtoydm -p -f $VTOY_PATH/ventoy_image_map -d $1 > $VTOY_PATH/ventoy_dm_table
+ $VTOY_PATH/tool/vtoydm -p -f $VTOY_PATH/ventoy_image_map -d $1 > $VTOY_PATH/ventoy_dm_table
+
+
+ vtLevel1=$($CAT /proc/sys/kernel/printk | $AWK '{print $1}')
+ vtLevel2=$($CAT /proc/sys/kernel/printk | $AWK '{print $2}')
+ vtLevel3=$($CAT /proc/sys/kernel/printk | $AWK '{print $3}')
+ vtLevel4=$($CAT /proc/sys/kernel/printk | $AWK '{print $4}')
+ if ventoy_need_dm_patch; then
+ ventoy_dm_patch
+ #suppress printk message
+ echo 0 $vtLevel2 0 $vtLevel4 > /proc/sys/kernel/printk
+ fi
+
if [ -z "$2" ]; then
$VT_DM_BIN create ventoy $VTOY_PATH/ventoy_dm_table >>$VTLOG 2>&1
else
$VT_DM_BIN "$2" create ventoy $VTOY_PATH/ventoy_dm_table >>$VTLOG 2>&1
- fi
+ fi
+
+ if ventoy_need_dm_patch; then
+ #recover printk level
+ echo $vtLevel1 $vtLevel2 $vtLevel3 $vtLevel4 > /proc/sys/kernel/printk
+ fi
}
create_persistent_device_mapper() {
vterr "Error: no dm module avaliable"
fi
- $VTOY_PATH/tool/vtoydm -p -f $VTOY_PATH/ventoy_persistent_map -d $1 > $VTOY_PATH/persistent_dm_table
+ $VTOY_PATH/tool/vtoydm -p -f $VTOY_PATH/ventoy_persistent_map -d $1 > $VTOY_PATH/persistent_dm_table
+
+
+ vtLevel1=$($CAT /proc/sys/kernel/printk | $AWK '{print $1}')
+ vtLevel2=$($CAT /proc/sys/kernel/printk | $AWK '{print $2}')
+ vtLevel3=$($CAT /proc/sys/kernel/printk | $AWK '{print $3}')
+ vtLevel4=$($CAT /proc/sys/kernel/printk | $AWK '{print $4}')
+ if [ -f $VTOY_PATH/dm_patch_done ]; then
+ #suppress printk message
+ echo 0 $vtLevel2 0 $vtLevel4 > /proc/sys/kernel/printk
+ fi
+
$VT_DM_BIN create vtoy_persistent $VTOY_PATH/persistent_dm_table >>$VTLOG 2>&1
+
+ if [ -f $VTOY_PATH/dm_patch_done ]; then
+ #recover printk level
+ echo $vtLevel1 $vtLevel2 $vtLevel3 $vtLevel4 > /proc/sys/kernel/printk
+ fi
}
fi
}
+ventoy_partname_to_diskname() {
+ if echo $1 | $EGREP -q "nvme.*p[0-9]$|mmc.*p[0-9]$|nbd.*p[0-9]$"; then
+ echo -n "${1:0:-2}"
+ else
+ echo -n "${1:0:-1}"
+ fi
+}
+
+ventoy_diskname_to_partname() {
+ if echo $1 | $EGREP -q "nvme.*p[0-9]$|mmc.*p[0-9]$|nbd.*p[0-9]$"; then
+ echo -n "${1}p$2"
+ else
+ echo -n "${1}$2"
+ fi
+}
+
ventoy_udev_disk_common_hook() {
if echo $1 | $EGREP -q "nvme.*p[0-9]$|mmc.*p[0-9]$|nbd.*p[0-9]$"; then
VTDISK="${1:0:-2}"
create_persistent_device_mapper "/dev/$VTDISK"
ventoy_create_persistent_link
fi
+
+ if $GREP -q 'dm_patch' /proc/modules; then
+ $BUSYBOX_PATH/rmmod dm_patch
+ fi
}
ventoy_create_dev_ventoy_part() {
if [ -e /vtoy_dm_table ]; then
vtPartid=1
+ vtLevel1=$($CAT /proc/sys/kernel/printk | $AWK '{print $1}')
+ vtLevel2=$($CAT /proc/sys/kernel/printk | $AWK '{print $2}')
+ vtLevel3=$($CAT /proc/sys/kernel/printk | $AWK '{print $3}')
+ vtLevel4=$($CAT /proc/sys/kernel/printk | $AWK '{print $4}')
+ if [ -f $VTOY_PATH/dm_patch_done ]; then
+ #suppress printk message
+ echo 0 $vtLevel2 0 $vtLevel4 > /proc/sys/kernel/printk
+ fi
+
$CAT /vtoy_dm_table | while read vtline; do
echo $vtline > /ventoy/dm_table_part${vtPartid}
$VTOY_PATH/tool/dmsetup create ventoy${vtPartid} /ventoy/dm_table_part${vtPartid}
$BUSYBOX_PATH/mknod -m 0666 /dev/ventoy${vtPartid} b $blkdev_num
vtPartid=$(expr $vtPartid + 1)
- done
+ done
+
+ if [ -f $VTOY_PATH/dm_patch_done ]; then
+ #recover printk level
+ echo $vtLevel1 $vtLevel2 $vtLevel3 $vtLevel4 > /proc/sys/kernel/printk
+ fi
fi
}
#############################################################
#############################################################
-set VENTOY_VERSION="1.0.63"
+set VENTOY_VERSION="1.0.64"
#ACPI not compatible with Window7/8, so disable by default
set VTOY_PARAM_NO_ACPI=1
data1->filter_vhd != data2->filter_vhd ||
data1->filter_vtoy != data2->filter_vtoy ||
data1->win11_bypass_check != data2->win11_bypass_check ||
+ data1->linux_remount != data2->linux_remount ||
data1->menu_timeout != data2->menu_timeout)
{
return 1;
VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_FILE_FLT_VHD", filter_vhd);
VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_FILE_FLT_VTOY", filter_vtoy);
VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_WIN11_BYPASS_CHECK", win11_bypass_check);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_LINUX_REMOUNT", linux_remount);
VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_MENU_TIMEOUT", menu_timeout);
VTOY_JSON_FMT_CTRL_STRN(L2, "VTOY_DEFAULT_KBD_LAYOUT", default_kbd_layout);
VTOY_JSON_FMT_SINT("filter_vhd", ctrl->filter_vhd);
VTOY_JSON_FMT_SINT("filter_vtoy", ctrl->filter_vtoy);
VTOY_JSON_FMT_SINT("win11_bypass_check", ctrl->win11_bypass_check);
+ VTOY_JSON_FMT_SINT("linux_remount", ctrl->linux_remount);
VTOY_JSON_FMT_SINT("menu_timeout", ctrl->menu_timeout);
VTOY_JSON_FMT_STRN("default_kbd_layout", ctrl->default_kbd_layout);
VTOY_JSON_FMT_STRN("help_text_language", ctrl->help_text_language);
VTOY_JSON_INT("filter_vhd", ctrl->filter_vhd);
VTOY_JSON_INT("filter_vtoy", ctrl->filter_vtoy);
VTOY_JSON_INT("win11_bypass_check", ctrl->win11_bypass_check);
+ VTOY_JSON_INT("linux_remount", ctrl->linux_remount);
VTOY_JSON_INT("menu_timeout", ctrl->menu_timeout);
VTOY_JSON_STR("default_image", ctrl->default_image);
{
CONTROL_PARSE_INT(child, data->win11_bypass_check);
}
+ else if (strcmp(child->pcName, "VTOY_LINUX_REMOUNT") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->linux_remount);
+ }
else if (strcmp(child->pcName, "VTOY_TREE_VIEW_MENU_STYLE") == 0)
{
CONTROL_PARSE_INT(child, data->treeview_style);
int filter_vtoy;
int win11_bypass_check;
int menu_timeout;
+ int linux_remount;
char default_search_root[MAX_PATH];
char default_image[MAX_PATH];
char default_kbd_layout[32];
-20211203 17:44:10
\ No newline at end of file
+20220108 22:41:02
\ No newline at end of file
\r
<footer class="main-footer">\r
<div class="pull-right hidden-xs">\r
- <b id="plugson_build_date">20211203 17:44:10</b>
+ <b id="plugson_build_date">20220108 22:41:02</b>
</div>\r
<strong><a href="https://www.ventoy.net" target="_blank">https://www.ventoy.net</a></strong>\r
</footer>\r
</div><!-- /.box -->\r
\r
\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_LINUX_REMOUNT\r
+ <span id="id_span_desc_cn"> —— Linux 启动后继续访问ISO文件所在分区</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_linux_remount_radio0" name="id_ctrl_linux_remount_radio" data-type="0" value="0"/> <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_linux_remount_radio1" name="id_ctrl_linux_remount_radio" data-type="1" value="1"/> <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> Linux启动后不需要继续访问ISO文件所在的分区。<br/>\r
+ <code style="font-weight: bold;">1</code> Linux启动后需要继续访问ISO文件所在的分区。<br/><br/>\r
+ 该选项只对 Linux 系统镜像有效。<br/>\r
+ 默认情况下,受Linux内核相关功能的限制,对于Linux系统,在启动后无法继续访问ISO文件所在的分区。在mount的时候会提示 device busy。<br/>\r
+ 如果这里选择 1,则 Ventoy 会尝试通过一些特殊的手段绕过内核的这个限制,但是这个功能是实验性质的,没有经过大规模和长时间的验证。 \r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> I don't need to access the image partition after boot.<br/>\r
+ <code style="font-weight: bold;">1</code> I need to access the image partition after boot. <br/><br/>\r
+ This option is only avaliable for Linux distro image files. <br/>\r
+\r
+ By default, the image partition where the ISO files locate can not be accessed after boot. When you try to mount it you will get device busy error.\r
+ This is due to linux kernel restriction (device-mapper module).<br/>\r
+ If you select 1 here, Ventoy will try to bypass the restriction with some special mechanism.<br/>\r
+ But it should be noted that, this is an experimental feature and is not fully tested.\r
+ \r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
\r
\r
<div class="box box-primary box-solid">\r
var level;\r
\r
data.win11_bypass_check = parseInt($('input:radio[name=id_ctrl_bypass_win11_radio]:checked').val());\r
+ data.linux_remount = parseInt($('input:radio[name=id_ctrl_linux_remount_radio]:checked').val());\r
data.default_search_root = $('input:text[id=id_ctrl_text_search_root]').val();\r
data.menu_timeout = parseInt($('input:text[id=id_ctrl_text_timeout]').val());\r
data.default_image = $('input:text[id=id_ctrl_text_default_img]').val();\r
function VtoyFillCurrentPageItem(data) {\r
//VTOY_WIN11_BYPASS_CHECK\r
$('input:radio[name=id_ctrl_bypass_win11_radio]')[data.win11_bypass_check].checked = true;\r
+ $('input:radio[name=id_ctrl_linux_remount_radio]')[data.linux_remount].checked = true;\r
\r
//VTOY_DEFAULT_SEARCH_ROOT\r
$('input:text[id=id_ctrl_text_search_root]').val(data.default_search_root);\r
method : 'save_control',\r
index: current_tab_index,\r
win11_bypass_check: data.win11_bypass_check,\r
+ linux_remount:data.linux_remount,\r
default_search_root: data.default_search_root,\r
menu_timeout: data.menu_timeout,\r
default_image: data.default_image,\r
x86 Legacy BIOS, IA32 UEFI, x86_64 UEFI, ARM64 UEFI and MIPS64EL UEFI are supported in the same way.<br/>
Both MBR and GPT partition style are supported in the same way.<br/>
Most type of OS supported(Windows/WinPE/Linux/Unix/ChromeOS/Vmware/Xen...) <br/>
- 770+ ISO files are tested (<a href="https://www.ventoy.net/en/isolist.html">List</a>). 90%+ distros in <a href="https://distrowatch.com/">distrowatch.com</a> supported (<a href="https://www.ventoy.net/en/distrowatch.html">Details</a>). <br/>
+ 780+ ISO files are tested (<a href="https://www.ventoy.net/en/isolist.html">List</a>). 90%+ distros in <a href="https://distrowatch.com/">distrowatch.com</a> supported (<a href="https://www.ventoy.net/en/distrowatch.html">Details</a>). <br/>
<br/>Official Website: <a href=https://www.ventoy.net>https://www.ventoy.net</a>
</h4>
* FAT32/exFAT/NTFS/UDF/XFS/Ext2(3)(4) supported for main partition
* ISO files larger than 4GB supported
* Native boot menu style for Legacy & UEFI
-* Most type of OS supported, 770+ iso files tested
+* Most type of OS supported, 780+ iso files tested
* Linux vDisk boot supported
* Not only boot but also complete installation process
* Menu dynamically switchable between List/TreeView mode
--- /dev/null
+/******************************************************************************
+ * vtoykmod.c ---- ventoy kmod
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#define _ull unsigned long long
+
+#define magic_sig 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF
+
+#define EI_NIDENT (16)
+
+#define EI_MAG0 0 /* e_ident[] indexes */
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_OSABI 7
+#define EI_PAD 8
+
+#define ELFMAG0 0x7f /* EI_MAG */
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define ELFCLASSNONE 0 /* EI_CLASS */
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+#define ELFCLASSNUM 3
+
+#define ELFDATANONE 0 /* e_ident[EI_DATA] */
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+#define EV_NONE 0 /* e_version, EI_VERSION */
+#define EV_CURRENT 1
+#define EV_NUM 2
+
+#define ELFOSABI_NONE 0
+#define ELFOSABI_LINUX 3
+
+#define SHT_STRTAB 3
+
+#pragma pack(1)
+
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ uint16_t e_type; /* Object file type */
+ uint16_t e_machine; /* Architecture */
+ uint32_t e_version; /* Object file version */
+ uint32_t e_entry; /* Entry point virtual address */
+ uint32_t e_phoff; /* Program header table file offset */
+ uint32_t e_shoff; /* Section header table file offset */
+ uint32_t e_flags; /* Processor-specific flags */
+ uint16_t e_ehsize; /* ELF header size in bytes */
+ uint16_t e_phentsize; /* Program header table entry size */
+ uint16_t e_phnum; /* Program header table entry count */
+ uint16_t e_shentsize; /* Section header table entry size */
+ uint16_t e_shnum; /* Section header table entry count */
+ uint16_t e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ uint16_t e_type; /* Object file type */
+ uint16_t e_machine; /* Architecture */
+ uint32_t e_version; /* Object file version */
+ uint64_t e_entry; /* Entry point virtual address */
+ uint64_t e_phoff; /* Program header table file offset */
+ uint64_t e_shoff; /* Section header table file offset */
+ uint32_t e_flags; /* Processor-specific flags */
+ uint16_t e_ehsize; /* ELF header size in bytes */
+ uint16_t e_phentsize; /* Program header table entry size */
+ uint16_t e_phnum; /* Program header table entry count */
+ uint16_t e_shentsize; /* Section header table entry size */
+ uint16_t e_shnum; /* Section header table entry count */
+ uint16_t e_shstrndx; /* Section header string table index */
+} Elf64_Ehdr;
+
+typedef struct
+{
+ uint32_t sh_name; /* Section name (string tbl index) */
+ uint32_t sh_type; /* Section type */
+ uint32_t sh_flags; /* Section flags */
+ uint32_t sh_addr; /* Section virtual addr at execution */
+ uint32_t sh_offset; /* Section file offset */
+ uint32_t sh_size; /* Section size in bytes */
+ uint32_t sh_link; /* Link to another section */
+ uint32_t sh_info; /* Additional section information */
+ uint32_t sh_addralign; /* Section alignment */
+ uint32_t sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+ uint32_t sh_name; /* Section name (string tbl index) */
+ uint32_t sh_type; /* Section type */
+ uint64_t sh_flags; /* Section flags */
+ uint64_t sh_addr; /* Section virtual addr at execution */
+ uint64_t sh_offset; /* Section file offset */
+ uint64_t sh_size; /* Section size in bytes */
+ uint32_t sh_link; /* Link to another section */
+ uint32_t sh_info; /* Additional section information */
+ uint64_t sh_addralign; /* Section alignment */
+ uint64_t sh_entsize; /* Entry size if section holds table */
+} Elf64_Shdr;
+
+typedef struct elf32_rel {
+ uint32_t r_offset;
+ uint32_t r_info;
+} Elf32_Rel;
+
+typedef struct elf64_rel {
+ uint64_t r_offset; /* Location at which to apply the action */
+ uint64_t r_info; /* index and type of relocation */
+} Elf64_Rel;
+
+typedef struct elf32_rela{
+ uint32_t r_offset;
+ uint32_t r_info;
+ int32_t r_addend;
+} Elf32_Rela;
+
+typedef struct elf64_rela {
+ uint64_t r_offset; /* Location at which to apply the action */
+ uint64_t r_info; /* index and type of relocation */
+ int64_t r_addend; /* Constant addend used to compute value */
+} Elf64_Rela;
+
+
+struct modversion_info {
+ unsigned long crc;
+ char name[64 - sizeof(unsigned long)];
+};
+
+
+typedef struct ko_param
+{
+ unsigned char magic[16];
+ unsigned long struct_size;
+ unsigned long pgsize;
+ unsigned long printk_addr;
+ unsigned long ro_addr;
+ unsigned long rw_addr;
+ unsigned long reg_kprobe_addr;
+ unsigned long unreg_kprobe_addr;
+ unsigned long sym_get_addr;
+ unsigned long sym_get_size;
+ unsigned long sym_put_addr;
+ unsigned long sym_put_size;
+ unsigned long padding[3];
+}ko_param;
+
+#pragma pack()
+
+static int verbose = 0;
+#define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
+
+static int vtoykmod_write_file(char *name, void *buf, int size)
+{
+ FILE *fp;
+
+ fp = fopen(name, "wb+");
+ if (!fp)
+ {
+ return -1;
+ }
+
+ fwrite(buf, 1, size, fp);
+ fclose(fp);
+
+ return 0;
+}
+
+static int vtoykmod_read_file(char *name, char **buf)
+{
+ int size;
+ FILE *fp;
+ char *databuf;
+
+ fp = fopen(name, "rb");
+ if (!fp)
+ {
+ debug("failed to open %s %d\n", name, errno);
+ return -1;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size = (int)ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ databuf = malloc(size);
+ if (!databuf)
+ {
+ debug("failed to open malloc %d\n", size);
+ return -1;
+ }
+
+ fread(databuf, 1, size, fp);
+ fclose(fp);
+
+ *buf = databuf;
+ return size;
+}
+
+static int vtoykmod_find_section64(char *buf, char *section, int *offset, int *len)
+{
+ uint16_t i;
+ int cmplen;
+ char *name = NULL;
+ char *strtbl = NULL;
+ Elf64_Ehdr *elf = NULL;
+ Elf64_Shdr *sec = NULL;
+
+ cmplen = (int)strlen(section);
+
+ elf = (Elf64_Ehdr *)buf;
+ sec = (Elf64_Shdr *)(buf + elf->e_shoff);
+ strtbl = buf + sec[elf->e_shstrndx].sh_offset;
+
+ for (i = 0; i < elf->e_shnum; i++)
+ {
+ name = strtbl + sec[i].sh_name;
+ if (name && strncmp(name, section, cmplen) == 0)
+ {
+ *offset = (int)(sec[i].sh_offset);
+ *len = (int)(sec[i].sh_size);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int vtoykmod_find_section32(char *buf, char *section, int *offset, int *len)
+{
+ uint16_t i;
+ int cmplen;
+ char *name = NULL;
+ char *strtbl = NULL;
+ Elf32_Ehdr *elf = NULL;
+ Elf32_Shdr *sec = NULL;
+
+ cmplen = (int)strlen(section);
+
+ elf = (Elf32_Ehdr *)buf;
+ sec = (Elf32_Shdr *)(buf + elf->e_shoff);
+ strtbl = buf + sec[elf->e_shstrndx].sh_offset;
+
+ for (i = 0; i < elf->e_shnum; i++)
+ {
+ name = strtbl + sec[i].sh_name;
+ if (name && strncmp(name, section, cmplen) == 0)
+ {
+ *offset = (int)(sec[i].sh_offset);
+ *len = (int)(sec[i].sh_size);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int vtoykmod_update_modcrc(char *oldmodver, int oldcnt, char *newmodver, int newcnt)
+{
+ int i, j;
+ struct modversion_info *pold, *pnew;
+
+ pold = (struct modversion_info *)oldmodver;
+ pnew = (struct modversion_info *)newmodver;
+
+ for (i = 0; i < oldcnt; i++)
+ {
+ for (j = 0; j < newcnt; j++)
+ {
+ if (strcmp(pold[i].name, pnew[j].name) == 0)
+ {
+ debug("CRC 0x%08lx --> 0x%08lx %s\n", pold[i].crc, pnew[i].crc, pold[i].name);
+ pold[i].crc = pnew[j].crc;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int vtoykmod_update_vermagic(char *oldbuf, int oldsize, char *newbuf, int newsize, int *modver)
+{
+ int i = 0;
+ char *oldver = NULL;
+ char *newver = NULL;
+
+ *modver = 0;
+
+ for (i = 0; i < oldsize - 9; i++)
+ {
+ if (strncmp(oldbuf + i, "vermagic=", 9) == 0)
+ {
+ oldver = oldbuf + i + 9;
+ debug("Find old vermagic at %d <%s>\n", i, oldver);
+ break;
+ }
+ }
+
+ for (i = 0; i < newsize - 9; i++)
+ {
+ if (strncmp(newbuf + i, "vermagic=", 9) == 0)
+ {
+ newver = newbuf + i + 9;
+ debug("Find new vermagic at %d <%s>\n", i, newver);
+ break;
+ }
+ }
+
+ if (oldver && newver)
+ {
+ memcpy(oldver, newver, strlen(newver) + 1);
+ if (strstr(newver, "modversions"))
+ {
+ *modver = 1;
+ }
+ }
+
+ return 0;
+}
+
+int vtoykmod_update(char *oldko, char *newko)
+{
+ int rc = 0;
+ int modver = 0;
+ int oldoff, oldlen;
+ int newoff, newlen;
+ int oldsize, newsize;
+ char *newbuf, *oldbuf;
+
+ oldsize = vtoykmod_read_file(oldko, &oldbuf);
+ newsize = vtoykmod_read_file(newko, &newbuf);
+ if (oldsize < 0 || newsize < 0)
+ {
+ return 1;
+ }
+
+ /* 1: update vermagic */
+ vtoykmod_update_vermagic(oldbuf, oldsize, newbuf, newsize, &modver);
+
+ /* 2: update modversion crc */
+ if (modver)
+ {
+ if (oldbuf[EI_CLASS] == ELFCLASS64)
+ {
+ rc = vtoykmod_find_section64(oldbuf, "__versions", &oldoff, &oldlen);
+ rc += vtoykmod_find_section64(newbuf, "__versions", &newoff, &newlen);
+ }
+ else
+ {
+ rc = vtoykmod_find_section32(oldbuf, "__versions", &oldoff, &oldlen);
+ rc += vtoykmod_find_section32(newbuf, "__versions", &newoff, &newlen);
+ }
+
+ if (rc == 0)
+ {
+ vtoykmod_update_modcrc(oldbuf + oldoff, oldlen / 64, newbuf + newoff, newlen / 64);
+ }
+ }
+ else
+ {
+ debug("no need to proc modversions\n");
+ }
+
+ /* 3: update relocate address */
+ if (oldbuf[EI_CLASS] == ELFCLASS64)
+ {
+ Elf64_Rela *oldRela, *newRela;
+
+ rc = vtoykmod_find_section64(oldbuf, ".rela.gnu.linkonce.this_module", &oldoff, &oldlen);
+ rc += vtoykmod_find_section64(newbuf, ".rela.gnu.linkonce.this_module", &newoff, &newlen);
+ if (rc == 0)
+ {
+ oldRela = (Elf64_Rela *)(oldbuf + oldoff);
+ newRela = (Elf64_Rela *)(newbuf + newoff);
+
+ debug("init_module rela: 0x%llx --> 0x%llx\n", (_ull)(oldRela[0].r_offset), (_ull)(newRela[0].r_offset));
+ oldRela[0].r_offset = newRela[0].r_offset;
+ oldRela[0].r_addend = newRela[0].r_addend;
+
+ debug("cleanup_module rela: 0x%llx --> 0x%llx\n", (_ull)(oldRela[1].r_offset), (_ull)(newRela[1].r_offset));
+ oldRela[1].r_offset = newRela[1].r_offset;
+ oldRela[1].r_addend = newRela[1].r_addend;
+ }
+ else
+ {
+ debug("section .rela.gnu.linkonce.this_module not found\n");
+ }
+ }
+ else
+ {
+ Elf32_Rel *oldRel, *newRel;
+
+ rc = vtoykmod_find_section32(oldbuf, ".rel.gnu.linkonce.this_module", &oldoff, &oldlen);
+ rc += vtoykmod_find_section32(newbuf, ".rel.gnu.linkonce.this_module", &newoff, &newlen);
+ if (rc == 0)
+ {
+ oldRel = (Elf32_Rel *)(oldbuf + oldoff);
+ newRel = (Elf32_Rel *)(newbuf + newoff);
+
+ debug("init_module rel: 0x%x --> 0x%x\n", oldRel[0].r_offset, newRel[0].r_offset);
+ oldRel[0].r_offset = newRel[0].r_offset;
+
+ debug("cleanup_module rel: 0x%x --> 0x%x\n", oldRel[0].r_offset, newRel[0].r_offset);
+ oldRel[1].r_offset = newRel[1].r_offset;
+ }
+ else
+ {
+ debug("section .rel.gnu.linkonce.this_module not found\n");
+ }
+ }
+
+ vtoykmod_write_file(oldko, oldbuf, oldsize);
+
+ free(oldbuf);
+ free(newbuf);
+
+ return 0;
+}
+
+int vtoykmod_fill_param(char **argv)
+{
+ int i;
+ int size;
+ char *buf = NULL;
+ ko_param *param;
+ unsigned char magic[16] = { magic_sig };
+
+ size = vtoykmod_read_file(argv[0], &buf);
+ if (size < 0)
+ {
+ return 1;
+ }
+
+ for (i = 0; i < size; i++)
+ {
+ if (memcmp(buf + i, magic, 16) == 0)
+ {
+ debug("Find param magic at %d\n", i);
+ param = (ko_param *)(buf + i);
+
+ param->struct_size = (unsigned long)sizeof(ko_param);
+ param->pgsize = strtoul(argv[1], NULL, 10);
+ param->printk_addr = strtoul(argv[2], NULL, 16);
+ param->ro_addr = strtoul(argv[3], NULL, 16);
+ param->rw_addr = strtoul(argv[4], NULL, 16);
+ param->sym_get_addr = strtoul(argv[5], NULL, 16);
+ param->sym_get_size = strtoul(argv[6], NULL, 10);
+ param->sym_put_addr = strtoul(argv[7], NULL, 16);
+ param->sym_put_size = strtoul(argv[8], NULL, 10);
+ param->reg_kprobe_addr = strtoul(argv[9], NULL, 16);
+ param->unreg_kprobe_addr = strtoul(argv[10], NULL, 16);
+
+ debug("pgsize=%lu (%s)\n", param->pgsize, argv[1]);
+ debug("printk_addr=0x%lx (%s)\n", param->printk_addr, argv[2]);
+ debug("ro_addr=0x%lx (%s)\n", param->ro_addr, argv[3]);
+ debug("rw_addr=0x%lx (%s)\n", param->rw_addr, argv[4]);
+ debug("sym_get_addr=0x%lx (%s)\n", param->sym_get_addr, argv[5]);
+ debug("sym_get_size=%lu (%s)\n", param->sym_get_size, argv[6]);
+ debug("sym_put_addr=0x%lx (%s)\n", param->sym_put_addr, argv[7]);
+ debug("sym_put_size=%lu (%s)\n", param->sym_put_size, argv[8]);
+ debug("reg_kprobe_addr=0x%lx (%s)\n", param->reg_kprobe_addr, argv[9]);
+ debug("unreg_kprobe_addr=0x%lx (%s)\n", param->unreg_kprobe_addr, argv[10]);
+
+ break;
+ }
+ }
+
+ if (i >= size)
+ {
+ debug("### param magic not found \n");
+ }
+
+ vtoykmod_write_file(argv[0], buf, size);
+
+ free(buf);
+ return 0;
+}
+
+int vtoykmod_main(int argc, char **argv)
+{
+ int i;
+
+ for (i = 0; i < argc; i++)
+ {
+ if (argv[i][0] == '-' && argv[i][1] == 'v')
+ {
+ verbose = 1;
+ break;
+ }
+ }
+
+ if (argv[1][0] == '-' && argv[1][1] == 'f')
+ {
+ return vtoykmod_fill_param(argv + 2);
+ }
+ else if (argv[1][0] == '-' && argv[1][1] == 'u')
+ {
+ return vtoykmod_update(argv[2], argv[3]);
+ }
+
+ return 0;
+}
+
+// wrapper main
+#ifndef BUILD_VTOY_TOOL
+int main(int argc, char **argv)
+{
+ return vtoykmod_main(argc, argv);
+}
+#endif
+
--- /dev/null
+/******************************************************************************
+ * vtoyksym.c ---- ventoy ksym
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+static int verbose = 0;
+#define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
+
+int vtoyksym_main(int argc, char **argv)
+{
+ int i;
+ unsigned long long addr1 = 0;
+ unsigned long long addr2 = 0;
+ char sym[256];
+ char line[1024];
+ const char *name = NULL;
+ FILE *fp;
+
+ for (i = 0; i < argc; i++)
+ {
+ if (argv[i][0] == '-' && argv[i][1] == 'p')
+ {
+ printf("%d", getpagesize());
+ return 0;
+ }
+ }
+
+ for (i = 0; i < argc; i++)
+ {
+ if (argv[i][0] == '-' && argv[i][1] == 'v')
+ {
+ verbose = 1;
+ break;
+ }
+ }
+
+ name = argv[2] ? argv[2] : "/proc/kallsyms";
+ fp = fopen(name, "r");
+ if (!fp)
+ {
+ fprintf(stderr, "Failed to open file %s err:%d\n", name, errno);
+ return 1;
+ }
+
+ debug("open %s success\n", name);
+
+ snprintf(sym, sizeof(sym), " %s", argv[1]);
+ debug("lookup for <%s>\n", sym);
+
+ while (fgets(line, sizeof(line), fp))
+ {
+ if (strstr(line, sym))
+ {
+ addr1 = strtoull(line, NULL, 16);
+ if (!fgets(line, sizeof(line), fp))
+ {
+ addr1 = 0;
+ fprintf(stderr, "Failed to read next line\n");
+ }
+ else
+ {
+ addr2 = strtoull(line, NULL, 16);
+ }
+
+ debug("addr1=<0x%llx> addr2=<0x%llx>\n", addr1, addr2);
+ break;
+ }
+ }
+
+ if (addr1 > addr2)
+ {
+ debug("Invalid addr range\n");
+ printf("0 0\n");
+ }
+ else
+ {
+ printf("0x%llx %llu\n", addr1, addr2 - addr1);
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+// wrapper main
+#ifndef BUILD_VTOY_TOOL
+int main(int argc, char **argv)
+{
+ return vtoyksym_main(argc, argv);
+}
+#endif
+
int vtoytool_install(int argc, char **argv);
int vtoyloader_main(int argc, char **argv);
int vtoyvine_main(int argc, char **argv);
+int vtoyksym_main(int argc, char **argv);
+int vtoykmod_main(int argc, char **argv);
static char *g_vtoytool_name = NULL;
static cmd_def g_cmd_list[] =
{ "vtoydump", vtoydump_main },
{ "vtoydm", vtoydm_main },
{ "loader", vtoyloader_main },
+ { "vtoyksym", vtoyksym_main },
+ { "vtoykmod", vtoykmod_main },
{ "--install", vtoytool_install },
};