Compare commits

...

48 Commits

Author SHA1 Message Date
Fabio Belavenuto
71e44bc7a3 Merge pull request #64 from fbelavenuto/dev
wip
2022-07-29 13:24:13 -03:00
Fabio Belavenuto
09dba3251b wip 2022-07-29 13:23:34 -03:00
Fabio Belavenuto
1682713fed Merge pull request #61 from fbelavenuto/dev
Modules
2022-07-27 11:41:59 -03:00
Fabio Belavenuto
e678c2aa53 Cosmetics 2022-07-26 17:28:01 -03:00
Fabio Belavenuto
2bceaea550 Modules 2022-07-26 13:12:12 -03:00
Fabio Belavenuto
ae78abc404 Merge pull request #59 from fbelavenuto/dev
Changing addon/modules instalation (for addons with modules)
2022-07-25 17:26:04 -03:00
Fabio Belavenuto
71df9e5a92 Changing addon/modules instalation (for addons with modules)
On build change, check invalid addons
2022-07-25 17:24:15 -03:00
Fabio Belavenuto
a74537aa02 Merge pull request #58 from fbelavenuto/dev
Fixing synoinfo entries for SHR
2022-07-25 14:27:51 -03:00
Fabio Belavenuto
16716b2172 Fixing synoinfo entries for SHR
Little bug into add synoinfo entry
2022-07-25 13:08:31 -03:00
Fabio Belavenuto
027a412b65 Merge pull request #57 from fbelavenuto/dev
Dev
2022-07-25 12:35:25 -03:00
Fabio Belavenuto
4ea6b9ad5c Force action cache remake 2022-07-25 12:34:58 -03:00
Fabio Belavenuto
c0209e0aae Missing synoinfo entries 2022-07-25 11:41:31 -03:00
Fabio Belavenuto
2c3ad3e7fb Merge pull request #56 from fbelavenuto/dev
PATA modules, unified p1 and p2 size
2022-07-25 11:26:59 -03:00
Fabio Belavenuto
74f09ffcd9 Now kernel/ramdisk of DSM and ARPL are located in partition 3 2022-07-25 09:59:35 -03:00
Fabio Belavenuto
acd413ab61 Adding PATA drivers 2022-07-25 08:22:48 -03:00
Fabio Belavenuto
415ee7e75d Merge pull request #53 from fbelavenuto/dev
Various commits
2022-07-22 16:58:46 -03:00
Fabio Belavenuto
2fe9b3237e Modules compiled with DSM toolchain 2022-07-22 16:58:08 -03:00
Fabio Belavenuto
81c0e00b76 Little fixes 2022-07-22 15:59:00 -03:00
Fabio Belavenuto
1b766e4974 Docker: using DSM toolchain 2022-07-22 15:50:43 -03:00
Fabio Belavenuto
690af5115d Re-added Addon external download 2022-07-22 08:11:37 -03:00
Fabio Belavenuto
a6ec7c0c46 Merge pull request #50 from fbelavenuto/dev
Adding module firmwares
2022-07-21 17:24:21 -03:00
Fabio Belavenuto
37fe50a1c5 Adding module firmwares 2022-07-21 17:22:38 -03:00
Fabio Belavenuto
ce5f427837 Merge pull request #49 from fbelavenuto/dev
Synoinfo entries unified
2022-07-21 16:50:16 -03:00
Fabio Belavenuto
5dc0b6e705 Synoinfo entries unified:
Synoinfo entries from model config file are copyed to user config file when the user choose a build.
2022-07-21 16:49:04 -03:00
Fabio Belavenuto
ea67f64d31 Merge pull request #48 from fbelavenuto/dev
Fixing custom MAC address
2022-07-21 14:26:12 -03:00
Fabio Belavenuto
722c03a506 Fixing custom MAC address 2022-07-21 14:21:25 -03:00
Fabio Belavenuto
678c7b6591 Merge pull request #47 from fbelavenuto/dev
Update modules set DIRTY flag
2022-07-21 11:22:12 -03:00
Fabio Belavenuto
8f7318f90f Cosmetics
Update module sets DIRTY flag
2022-07-21 11:21:24 -03:00
Fabio Belavenuto
7b2a7b210a Added DS2422+ 42661 build 2022-07-19 14:22:40 -03:00
Fabio Belavenuto
14362aae17 Added option to boot into junior mode 2022-07-19 13:54:51 -03:00
Fabio Belavenuto
0e16f96fad Added option to boot into junior mode 2022-07-19 13:53:03 -03:00
Fabio Belavenuto
159b7172b0 Merge pull request #43 from fbelavenuto/dev
Removing no more necessary php
2022-07-19 12:44:47 -03:00
Fabio Belavenuto
75c637a6e4 Removing no more necessary php 2022-07-19 12:44:03 -03:00
Fabio Belavenuto
a3bb685def Merge pull request #42 from fbelavenuto/dev
Rewind vanilla e1000e
2022-07-19 12:30:10 -03:00
Fabio Belavenuto
42010a1dc0 Rewind vanilla e1000e 2022-07-19 12:01:44 -03:00
Fabio Belavenuto
a456c2b21e Merge pull request #41 from fbelavenuto/dev
Fixing modules
2022-07-19 09:54:32 -03:00
Fabio Belavenuto
917c5f7280 Fixing modules 2022-07-19 09:53:42 -03:00
Fabio Belavenuto
8b530f12d1 Merge pull request #40 from fbelavenuto/dev
Dev
2022-07-18 17:06:37 -03:00
Fabio Belavenuto
604728ecec Added Fusion SPI module 2022-07-18 17:05:30 -03:00
Fabio Belavenuto
de224baf98 Fixing e1000 module (kernel panic) 2022-07-18 14:48:16 -03:00
Fabio Belavenuto
6ee0672e74 Merge pull request #39 from fbelavenuto/dev
Dev
2022-07-18 13:19:05 -03:00
Fabio Belavenuto
ff422707b7 Replaced php scripts for alternatives
Add kpatch C code for patch DSM kernel
Fix ramdisk-common-init-script (wrong merge)
2022-07-18 13:15:26 -03:00
Fabio Belavenuto
9edb1cfe0f Adding title into boot screen 2022-07-18 10:46:03 -03:00
Fabio Belavenuto
755a3d6a39 Added "Define custom MAC" to cmdline menu 2022-07-18 10:30:58 -03:00
Fabio Belavenuto
a17dc55a17 Merge pull request #38 from fbelavenuto/dev
Dev
2022-07-18 10:10:03 -03:00
Fabio Belavenuto
b35a71f023 new mpt3sas module
new version
2022-07-18 10:09:33 -03:00
Fabio Belavenuto
b9a02143b1 Little bugs 2022-07-18 09:36:03 -03:00
Fabio Belavenuto
8091c22402 wip 2022-07-16 19:09:13 -03:00
77 changed files with 773 additions and 668 deletions

View File

@@ -1,28 +1,17 @@
name: Build image
# Controls when the workflow will run
on:
# Push
push:
branches:
- main
tags:
- v*
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3
# Check cache
@@ -49,7 +38,7 @@ jobs:
cp -Ru files/* .buildroot
cd .buildroot
echo "Generating default config"
make arpl_defconfig
make BR2_EXTERNAL=../external arpl_defconfig
echo "First make"
make BR2_EXTERNAL=../external
@@ -65,32 +54,32 @@ jobs:
rm -rf .buildroot/board/arpl/p1
rm -rf .buildroot/board/arpl/p3
# Get latest LKMs
echo "Getting latest LKMs"
TAG=`curl -s https://api.github.com/repos/fbelavenuto/redpill-lkm/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}'`
curl -L "https://github.com/fbelavenuto/redpill-lkm/releases/download/${TAG}/rp-lkms.zip" -o /tmp/rp-lkms.zip
rm -rf files/board/arpl/p3/lkms/*
unzip /tmp/rp-lkms.zip -d files/board/arpl/p3/lkms
# Get latest addons and install its
echo "Getting latest Addons"
TAG=`curl -s https://api.github.com/repos/fbelavenuto/arpl-addons/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}'`
curl -L "https://github.com/fbelavenuto/arpl-addons/releases/download/${TAG}/addons.zip" -o /tmp/addons.zip
mkdir -p /tmp/addons
unzip /tmp/addons.zip -d /tmp/addons
DEST_PATH="files/board/arpl/p3/addons"
echo "Installing addons to ${DEST_PATH}"
for PKG in `ls /tmp/addons/*.addon`; do
ADDON=`basename ${PKG} | sed 's|.addon||'`
mkdir -p "${DEST_PATH}/${ADDON}"
echo "Extracting ${PKG} to ${DEST_PATH}/${ADDON}"
tar xaf "${PKG}" -C "${DEST_PATH}/${ADDON}"
done
# echo "Getting latest LKMs"
# TAG=`curl -s https://api.github.com/repos/fbelavenuto/redpill-lkm/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}'`
# curl -L "https://github.com/fbelavenuto/redpill-lkm/releases/download/${TAG}/rp-lkms.zip" -o /tmp/rp-lkms.zip
# rm -rf files/board/arpl/p3/lkms/*
# unzip /tmp/rp-lkms.zip -d files/board/arpl/p3/lkms
# # Get latest addons and install its
# echo "Getting latest Addons"
# TAG=`curl -s https://api.github.com/repos/fbelavenuto/arpl-addons/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}'`
# curl -L "https://github.com/fbelavenuto/arpl-addons/releases/download/${TAG}/addons.zip" -o /tmp/addons.zip
# mkdir -p /tmp/addons
# unzip /tmp/addons.zip -d /tmp/addons
# DEST_PATH="files/board/arpl/p3/addons"
# echo "Installing addons to ${DEST_PATH}"
# for PKG in `ls /tmp/addons/*.addon`; do
# ADDON=`basename ${PKG} | sed 's|.addon||'`
# mkdir -p "${DEST_PATH}/${ADDON}"
# echo "Extracting ${PKG} to ${DEST_PATH}/${ADDON}"
# tar xaf "${PKG}" -C "${DEST_PATH}/${ADDON}"
# done
# Copy files
echo "Copying files"
sed 's/^ARPL_VERSION=.*/ARPL_VERSION="'${VERSION}'"/' -i files/board/arpl/overlayfs/opt/arpl/include/consts.sh
cp -Ru files/* .buildroot/
cd .buildroot
echo "Generating default config"
make arpl_defconfig
make BR2_EXTERNAL=../external arpl_defconfig
echo "Version: ${VERSION}"
echo "Building..."
make BR2_EXTERNAL=../external

5
.gitignore vendored
View File

@@ -1,10 +1,11 @@
!.gitkeep
.vscode
arpl.img
arpl.vmdk
arpl*.img
arpl*.vmdk
*.zip
.buildroot
test.sh
docker/Dockerfile
docker/cache
*.bak
*.o

View File

@@ -4,25 +4,28 @@ This particular project was created to facilitate my testing with Redpill and I
It is still in alpha stage, with little documentation, but it is functional. I'm Brazilian and my English is not good, so I apologize for my translations.
I tried to make the system as user-friendly as possible, to make life easier. The loader automatically detects which device is being used, SATADom or USB, detecting its VID and PID correctly. redpill-lkm has been edited to allow booting the kernel without setting the variables related to network interfaces so the loader (and user) doesn't have to worry about that. The Jun's code that makes the zImage and Ramdisk patch is embedded, if there is a change in "zImage" or "rd.gz" by some update, the loader re-applies the patches. Builds 42218 and 42661 up to update5 are working. Automatic updates should still be disabled as we are not sure if this technique will work forever.
I tried to make the system as user-friendly as possible, to make life easier. The loader automatically detects which device is being used, SATADom or USB, detecting its VID and PID correctly. redpill-lkm has been edited to allow booting the kernel without setting the variables related to network interfaces so the loader (and user) doesn't have to worry about that. The Jun's code that makes the zImage and Ramdisk patch is embedded, if there is a change in "zImage" or "rd.gz" by some update, the loader re-applies the patches. Builds 42218 and 42661 up to update5 are working. Automatic updates should still be disabled as we are not sure if this technique will work forever. The most important kernel modules are built into the DSM ramdisk image for automatic peripheral detection.
# Use
To use this project, download the latest image available and burn it to a USB stick or SATA disk-on-module. Set the PC to boot from the burned media and follow the informations on the screen. When booting, the user can call the "menu.sh" command from the computer itself, access via SSH or use the virtual terminal (ttyd) by typing the address provided on the screen (http://(ip):7681). The loader will automatically increase the size of the last partition and use this space as cache if it is larger than 2GiB.
The menu system is dynamic and I hope it is intuitive enough that the user can use it without any problems. Its allows you to choose a model, the existing buildnumber for the chosen model, randomly type or create a serial number, add/remove addons with a hardware detection option, add/remove/view "cmdline" and "synoinfo" entries, choose the LKM version, create the loader, boot, manually edit the configuration file, choose a keymap, update and exit.
### It is highly recommended to use an SSD for the loader in the case of the option via DoM or a fast USB flash drive
Addons and "synoinfo" entries require re-creating the loader, "cmdline" entries do not. You can view the "cmdline" and "synoinfo" entries defined for the chosen model, with user-defined entries having higher priority.
The menu system is dynamic and I hope it is intuitive enough that the user can use it without any problems. Its allows you to choose a model, the existing buildnumber for the chosen model, type or randomly create a serial number, add/remove addons, add/remove/view "cmdline" and "synoinfo" entries, choose the LKM version, create the loader, boot, manually edit the configuration file, choose a keymap, update and exit.
Changing addons and synoinfo entries require re-creating the loader, cmdline entries do not.
There is no need to configure the VID/PID (if using a USB stick) or define the MAC Addresses of the network interfaces. If the user wants to modify the MAC Address of any interface, he must manually add "cmdline" entries in the corresponding menu (set "netif_num" according to "mac1..4" entries).
If a model is chosen that uses the Device-tree system to define the HDs, there is no need to configure anything. In the case of models that do not use device-tree, the configurations must be done manually and for this there is an option in the "Cmdline" menu to display the SATA controllers, DUMMY ports and ports in use, to assist in the creation of the "SataPortMap", "DiskIdxMap" and "sata_remap".
If a model is chosen that uses the Device-tree system to define the HDs, there is no need to configure anything. In the case of models that do not use device-tree, the configurations must be done manually and for this there is an option in the "Cmdline" menu to display the SATA controllers, DUMMY ports and ports in use, to assist in the creation of the "SataPortMap", "DiskIdxMap" and "sata_remap" if necessary.
Another important point is that the loader detects whether or not the CPU has the FMA3 instruction and does not display the models that require it. So if the DS918+ and DVA3221 models are not displayed it is because of the CPU's lack of support for FMA instructions.
I developed a simple patch to no longer display the DUMMY port error on models without device-tree, the user will be able to install without having to worry about it.
Addons can be downloaded and added to the loader.
# Thanks
All code was based on the work of TTG, pocopico, jumkey and others involved in continuing TTG's original redpill-load project.
More information will be added in the future.

8
TODO
View File

@@ -1,6 +1,6 @@
A fazer
- Validar netif_num e macX
- Descobrir como é o serial do DS2422+
- Mudar addons para colocar pacote completo na partição 3 e detectar dinâmicamente durante o boot do júnior
- Estudar acrescentar modo simples e avançado do menu
Concluidos:
@@ -24,5 +24,7 @@ Concluidos:
- Arrumar detecção de discos/maxdisks. 918 tem só 4 discos e dá problema com proxmox
- Melhorar opções de HD, talvez criar um menu a parte
- Implementar update do bzimage e ramdisk online
https://kb.synology.com/en-me/DSM/tutorial/What_kind_of_CPU_does_my_NAS_have
- Mudar addons para colocar pacote completo na partição 3 e detectar dinâmicamente durante o boot do júnior
- Acertar flag DIRTY ao atualizar módulos, etc
- Consertar MAC custom
- Mudar synoinfo para ler do modelo e preencher no user_config, para usuário poder deletar entradas do modelo

View File

@@ -12,11 +12,8 @@ tasks:
cmds:
- ./build.sh
compile-lkms:
compile-kpatch:
dir: kpatch
cmds:
- ./compile-lkm.sh
compile-addons:
dir: addons
cmds:
- ./compile-addons.sh {{.CLI_ARGS}}
- make clean all
- mv kpatch ../files/board/arpl/overlayfs/opt/arpl/

View File

@@ -1 +1 @@
0.3-alpha2
0.3-alpha6

View File

@@ -3,20 +3,17 @@ ARG PLATFORMS="@@@PLATFORMS@@@"
ARG TOOLKIT_VER="@@@TOOLKIT_VER@@@"
# Copy downloaded toolkits
ADD cache /cache
ADD cache/$TOOLKIT_VER /cache
# Extract toolkits
RUN for V in ${PLATFORMS}; do \
echo "${V}" | while IFS=':' read PLATFORM KVER; do \
echo -e "${PLATFORM}\t${KVER}" >> /opt/platforms && \
echo "Extracting ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz" && \
mkdir "/opt/${PLATFORM}" && \
tar -xaf "/cache/ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz" -C "/opt/${PLATFORM}" --strip-components=10 \
"usr/local/x86_64-pc-linux-gnu/x86_64-pc-linux-gnu/sys-root/usr/lib/modules/DSM-${TOOLKIT_VER}/build" && \
echo -e "${PLATFORM}\t${KVER}" >> /opt/platforms && \
if [ ! -d "/opt/linux-${KVER}" ]; then \
mkdir "/opt/linux-${KVER}" && \
echo "Extracting linux-${KVER}.tar.xz" && \
tar -xaf "/cache/linux-${KVER}.tar.xz" -C "/opt/linux-${KVER}" --strip-components=1; \
fi; \
tar -xaf "/cache/ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz" -C "/opt/${PLATFORM}" --strip-components=9 \
"usr/local/x86_64-pc-linux-gnu/x86_64-pc-linux-gnu/sys-root/usr/lib/modules/DSM-${TOOLKIT_VER}" && \
echo "Extracting ${PLATFORM}-toolchain.txz" && \
tar -xaf "/cache/${PLATFORM}-toolchain.txz" -C "/opt/${PLATFORM}" --strip-components=1; \
done; \
done

View File

@@ -6,50 +6,75 @@ function trap_cancel() {
sleep 2 || exit 1
}
trap trap_cancel SIGINT SIGTERM
cd `dirname $0`
# Read platforms/kerver version
echo "Reading platforms"
declare -A PLATFORMS
while read PLATFORM KVER; do
PLATFORMS[${PLATFORM}]="${KVER}"
done <../PLATFORMS
###############################################################################
function prepare() {
declare -A URLS
# Download toolkits
mkdir -p cache
URLS["apollolake"]="https://global.download.synology.com/download/ToolChain/toolchain/${TOOLCHAIN_VER}/Intel%20x86%20Linux%204.4.180%20%28Apollolake%29/apollolake-${GCCLIB_VER}_x86_64-GPL.txz"
URLS["broadwell"]="https://global.download.synology.com/download/ToolChain/toolchain/${TOOLCHAIN_VER}/Intel%20x86%20Linux%204.4.180%20%28Broadwell%29/broadwell-${GCCLIB_VER}_x86_64-GPL.txz"
URLS["broadwellnk"]="https://global.download.synology.com/download/ToolChain/toolchain/${TOOLCHAIN_VER}/Intel%20x86%20Linux%204.4.180%20%28Broadwellnk%29/broadwellnk-${GCCLIB_VER}_x86_64-GPL.txz"
URLS["bromolow"]="https://global.download.synology.com/download/ToolChain/toolchain/${TOOLCHAIN_VER}/Intel%20x86%20linux%203.10.108%20%28Bromolow%29/bromolow-${GCCLIB_VER}_x86_64-GPL.txz"
URLS["denverton"]="https://global.download.synology.com/download/ToolChain/toolchain/${TOOLCHAIN_VER}/Intel%20x86%20Linux%204.4.180%20%28Denverton%29/denverton-${GCCLIB_VER}_x86_64-GPL.txz"
URLS["geminilake"]="https://global.download.synology.com/download/ToolChain/toolchain/${TOOLCHAIN_VER}/Intel%20x86%20Linux%204.4.180%20%28GeminiLake%29/geminilake-${GCCLIB_VER}_x86_64-GPL.txz"
URLS["v1000"]="https://global.download.synology.com/download/ToolChain/toolchain/${TOOLCHAIN_VER}/Intel%20x86%20Linux%204.4.180%20%28V1000%29/v1000-${GCCLIB_VER}_x86_64-GPL.txz"
# Read platforms/kerver version
echo "Reading platforms"
declare -A PLATFORMS
while read PLATFORM KVER; do
PLATFORMS[${PLATFORM}]="${KVER}"
done <../PLATFORMS
# Download toolkits
mkdir -p cache
for PLATFORM in ${!PLATFORMS[@]}; do
KVER="${PLATFORMS[${PLATFORM}]}"
echo -n "Checking cache/${TOOLKIT_VER}/ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz... "
if [ ! -f "cache/${TOOLKIT_VER}/ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz" ]; then
URL="https://global.download.synology.com/download/ToolChain/toolkit/${TOOLKIT_VER}/${PLATFORM}/ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz"
echo "Downloading ${URL}"
curl -L "${URL}" -o "cache/${TOOLKIT_VER}/ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz"
else
echo "OK"
fi
echo -n "Checking cache/${TOOLKIT_VER}/${PLATFORM}-toolchain.txz... "
if [ ! -f "cache/${TOOLKIT_VER}/${PLATFORM}-toolchain.txz" ]; then
URL=${URLS["${PLATFORM}"]}
echo "Downloading ${URL}"
curl -L "${URL}" -o "cache/${TOOLKIT_VER}/${PLATFORM}-toolchain.txz"
else
echo "OK"
fi
done
# Generate Dockerfile
echo "Generating Dockerfile"
cp Dockerfile.template Dockerfile
VALUE=""
for PLATFORM in ${!PLATFORMS[@]}; do
VALUE+="${PLATFORM}:${PLATFORMS[${PLATFORM}]} "
done
sed -i "s|@@@PLATFORMS@@@|${VALUE::-1}|g" Dockerfile
sed -i "s|@@@TOOLKIT_VER@@@|${TOOLKIT_VER}|g" Dockerfile
}
# 7.0
TOOLKIT_VER="7.0"
for PLATFORM in ${!PLATFORMS[@]}; do
KVER="${PLATFORMS[${PLATFORM}]}"
echo -n "Checking cache/ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz... "
if [ ! -f "cache/ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz" ]; then
URL="https://global.download.synology.com/download/ToolChain/toolkit/${TOOLKIT_VER}/${PLATFORM}/ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz"
echo "Downloading ${URL}"
curl -L "${URL}" -o "cache/ds.${PLATFORM}-${TOOLKIT_VER}.dev.txz"
else
echo "OK"
fi
# echo -n "Checking cache/linux-${KVER}.tar.xz... "
# if [ ! -f "cache/linux-${KVER}.tar.xz" ]; then
# URL="https://cdn.kernel.org/pub/linux/kernel/v${KVER:0:1}.x/linux-${KVER}.tar.xz"
# echo "Downloading ${URL}"
# curl -L "${URL}" -o "cache/linux-${KVER}.tar.xz"
# else
# echo "OK"
# fi
done
TOOLCHAIN_VER="7.0-41890"
GCCLIB_VER="gcc750_glibc226"
prepare
echo "Building ${TOOLKIT_VER}"
docker image rm fbelavenuto/syno-compiler:${TOOLKIT_VER} >/dev/null 2>&1
docker buildx build . --load --tag fbelavenuto/syno-compiler:${TOOLKIT_VER}
# Generate Dockerfile
echo "Generating Dockerfile"
cp Dockerfile.template Dockerfile
VALUE=""
for PLATFORM in ${!PLATFORMS[@]}; do
VALUE+="${PLATFORM}:${PLATFORMS[${PLATFORM}]} "
done
sed -i "s|@@@PLATFORMS@@@|${VALUE::-1}|g" Dockerfile
sed -i "s|@@@TOOLKIT_VER@@@|${TOOLKIT_VER}|g" Dockerfile
# Build
echo "Building... Drink a coffee and wait!"
docker image rm fbelavenuto/syno-compiler >/dev/null 2>&1
docker buildx build . --load --tag fbelavenuto/syno-compiler
# 7.1
TOOLKIT_VER="7.1"
TOOLCHAIN_VER="7.1-42661"
GCCLIB_VER="gcc850_glibc226"
prepare
echo "Building ${TOOLKIT_VER}"
docker image rm fbelavenuto/syno-compiler:${TOOLKIT_VER} >/dev/null 2>&1
docker buildx build . --load --tag fbelavenuto/syno-compiler:${TOOLKIT_VER} --tag fbelavenuto/syno-compiler:latest

View File

@@ -1,5 +1,20 @@
#!/usr/bin/env bash
set -e
function export-vars {
# Validate
if [ -z "${1}" ]; then
echo "Use: export-vars <platform>"
exit 1
fi
export CROSS_COMPILE="/opt/${1}/bin/x86_64-pc-linux-gnu-"
export CFLAGS="-I/opt/${1}/include"
export LDFLAGS="-I/opt/${1}/lib"
export LD_LIBRARY_PATH="/opt/${1}/lib"
export ARCH=x86_64
}
function compile-module {
# Validate
if [ -z "${1}" ]; then
@@ -14,12 +29,14 @@ function compile-module {
fi
done </opt/platforms
if [ $VALID -eq 0 ]; then
echo "Platform ${PLATFORM} not found."
echo "Platform ${1} not found."
exit 1
fi
echo "Compiling module for ${PLATFORM}-${KVER}..."
cp -R /input /tmp
make -C "/opt/${PLATFORM}" M="/tmp/input" PLATFORM=${PLATFORM^^} modules
export-vars ${PLATFORM}
make -C "/opt/${PLATFORM}/build" M="/tmp/input" \
${PLATFORM^^}-Y=y ${PLATFORM^^}-M=m modules
while read F; do
strip -g "${F}"
echo "Copying `basename ${F}`"
@@ -34,11 +51,13 @@ function compile-lkm {
exit 1
fi
cp -R /input /tmp
make -C "/tmp/input" LINUX_SRC="/opt/${PLATFORM}" dev-v7
export-vars ${PLATFORM}
export LINUX_SRC="/opt/${PLATFORM}/build"
make -C "/tmp/input" dev-v7
strip -g "/tmp/input/redpill.ko"
mv "/tmp/input/redpill.ko" "/output/redpill-dev.ko"
make -C "/tmp/input" LINUX_SRC="/opt/${PLATFORM}" clean
make -C "/tmp/input" LINUX_SRC="/opt/${PLATFORM}" prod-v7
make -C "/tmp/input" clean
make -C "/tmp/input" prod-v7
strip -g "/tmp/input/redpill.ko"
mv "/tmp/input/redpill.ko" "/output/redpill-prod.ko"
}
@@ -71,10 +90,10 @@ if [ $# -lt 1 ]; then
exit 1
fi
case $1 in
bash) shift; bash -l $@ ;;
bash) shift && bash -l $@ ;;
shell) export-vars $2 && shift 2 && bash -l $@ ;;
compile-module) compile-module $2 ;;
compile-lkm) compile-lkm $2 ;;
# compile-drivers) compile-drivers ;;
*) echo "Command not recognized: $1" ;;
esac

View File

@@ -121,6 +121,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_SAS_ATA=y
CONFIG_BLK_DEV_3W_XXXX_RAID=m
CONFIG_SCSI_HPSA=m
CONFIG_SCSI_3W_9XXX=m
@@ -184,9 +185,31 @@ CONFIG_SATA_SIL=m
CONFIG_SATA_SIS=m
CONFIG_SATA_ULI=m
CONFIG_SATA_VIA=m
CONFIG_PATA_ALI=m
CONFIG_PATA_AMD=y
CONFIG_PATA_ARTOP=m
CONFIG_PATA_ATIIXP=m
CONFIG_PATA_ATP867X=m
CONFIG_PATA_CMD64X=m
CONFIG_PATA_EFAR=m
CONFIG_PATA_HPT366=m
CONFIG_PATA_HPT37X=m
CONFIG_PATA_HPT3X2N=m
CONFIG_PATA_HPT3X3=m
CONFIG_PATA_IT821X=m
CONFIG_PATA_JMICRON=m
CONFIG_PATA_NINJA32=m
CONFIG_PATA_NS87415=m
CONFIG_PATA_OLDPIIX=y
CONFIG_PATA_PDC2027X=m
CONFIG_PATA_PDC_OLD=m
CONFIG_PATA_RDC=m
CONFIG_PATA_SCH=y
CONFIG_PATA_SERVERWORKS=m
CONFIG_PATA_SIL680=m
CONFIG_PATA_TRIFLEX=m
CONFIG_PATA_VIA=m
CONFIG_PATA_WINBOND=m
CONFIG_ATA_GENERIC=y
CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
@@ -194,6 +217,7 @@ CONFIG_BLK_DEV_DM=y
CONFIG_DM_MIRROR=y
CONFIG_DM_ZERO=y
CONFIG_FUSION=y
CONFIG_FUSION_SPI=m
CONFIG_FUSION_SAS=m
CONFIG_FUSION_CTL=m
CONFIG_NETDEVICES=y

View File

@@ -19,7 +19,7 @@ dd if="/dev/zero" of="${IMAGE_FILE}" bs=1M count=300 conv=sync 2>/dev/null
# Copy grub stage1 to image
dd if="${BOARD_PATH}/grub.bin" of="${IMAGE_FILE}" conv=notrunc,sync 2>/dev/null
# Create partitions on image
echo -e "n\np\n\n\n+150M\na\nt\n\n0b\nn\np\n\n\n+50M\nn\np\n\n\n\nw" | fdisk "${IMAGE_FILE}" >/dev/null
echo -e "n\np\n\n\n+50M\na\nt\n\n0b\nn\np\n\n\n+50M\nn\np\n\n\n\nw" | fdisk "${IMAGE_FILE}" >/dev/null
# Force umount, ignore errors
sudo umount "${BINARIES_DIR}/p1" 2>/dev/null || true
@@ -40,8 +40,8 @@ sudo mount /dev/loop8p1 "${BINARIES_DIR}/p1"
sudo mount /dev/loop8p3 "${BINARIES_DIR}/p3"
echo "Copying files"
sudo cp "${BINARIES_DIR}/bzImage" "${BINARIES_DIR}/p1/bzImage-arpl"
sudo cp "${BINARIES_DIR}/rootfs.cpio.xz" "${BINARIES_DIR}/p1/initrd-arpl"
sudo cp "${BINARIES_DIR}/bzImage" "${BINARIES_DIR}/p3/bzImage-arpl"
sudo cp "${BINARIES_DIR}/rootfs.cpio.xz" "${BINARIES_DIR}/p3/initrd-arpl"
sudo cp -R "${BOARD_PATH}/p1/"* "${BINARIES_DIR}/p1"
sudo cp -R "${BOARD_PATH}/p3/"* "${BINARIES_DIR}/p3"
sync

View File

@@ -0,0 +1,33 @@
#!/bin/sh
#
# Start/stop dhcpcd
#
DAEMON=/usr/sbin/dhcpcd
CONFIG=/etc/dhcpcd.conf
PIDFILE=/var/run/dhcpcd/pid
[ -f $CONFIG ] || exit 0
case "$1" in
start)
echo "Starting dhcpcd..."
start-stop-daemon -S -x "$DAEMON" -p "$PIDFILE" -- -f "$CONFIG"
;;
stop)
echo "Stopping dhcpcd..."
start-stop-daemon -K -x "$DAEMON" -p "$PIDFILE" -o
;;
reload|force-reload)
echo "Reloading dhcpcd configuration..."
"$DAEMON" -s reload
;;
restart)
"$0" stop
sleep 1 # Prevent race condition: ensure dhcpcd stops before start.
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart|reload|force-reload}"
exit 1
esac

View File

@@ -9,12 +9,13 @@ loaderIsConfigured || die "Loader is not configured!"
# Print text centralized, if variable ${COLUMNS} is defined
clear
TITLE="Welcome to Automated Redpill Loader v${ARPL_VERSION}"
printf "\033[1;44m%*s\n" $COLUMNS ""
printf "\033[1;44m%*s\033[A\n" $COLUMNS ""
printf "\033[1;32m%*s\033[0m\n" $(((${#TITLE}+$COLUMNS)/2)) "${TITLE}"
printf "\033[1;44m%*s\033[0m\n" $COLUMNS ""
TITLE="BOOTING..."
if [ -z "${COLUMNS}" ]; then
echo -e "\033[1;33m${TITLE}\033[0m"
else
printf "\033[1;33m%*s\033[0m\n" $(((${#TITLE}+${COLUMNS})/2)) "${TITLE}"
fi
printf "\033[1;33m%*s\033[0m\n" $(((${#TITLE}+${COLUMNS})/2)) "${TITLE}"
# Check if DSM zImage changed, patch it if necessary
ZIMAGE_HASH="`readConfigKey "zimage-hash" "${USER_CONFIG_FILE}"`"
@@ -75,13 +76,15 @@ EFI_BUG="`readModelKey "${MODEL}" "builds.${BUILD}.efi-bug"`"
LOADER_DISK="`blkid | grep 'LABEL="ARPL3"' | cut -d3 -f1`"
BUS=`udevadm info --query property --name ${LOADER_DISK} | grep ID_BUS | cut -d= -f2`
if [ "${BUS}" = "ata" ]; then
SIZE=$((`df -BM | awk '/\/mnt\/p3/{print$2}' | tr 'M' ' '`+300))
LOADER_DEVICE_NAME=`echo ${LOADER_DISK} | sed 's|/dev/||'`
SIZE=$((`cat /sys/block/${LOADER_DEVICE_NAME}/size`/2048+10))
# Read SATADoM type
DOM="`readModelKey "${MODEL}" "dom"`"
fi
# Prepare command line
CMDLINE_LINE=""
grep -q "force_junior" /proc/cmdline && CMDLINE_LINE+="force_junior "
[ ${EFI} -eq 1 ] && CMDLINE_LINE+="withefi "
[ "${BUS}" = "ata" ] && CMDLINE_LINE+="synoboot_satadom=${DOM} dom_szmax=${SIZE} "
CMDLINE_LINE+="console=ttyS0,115200n8 earlyprintk log_buf_len=32M earlycon=uart8250,io,0x3f8,115200n8 elevator=elevator root=/dev/md0 loglevel=15"
@@ -100,18 +103,19 @@ echo -e "Cmdline:\n\033[1;36m${CMDLINE_LINE}\033[0m"
# Wait for an IP
COUNT=0
echo -n "IP: "
echo -n "IP"
while true; do
IP=`ip route get 1.1.1.1 2>/dev/null | awk '{print$7}'`
if [ -n "${IP}" ]; then
echo -e "\033[1;32m${IP}\033[0m"
echo -e ": \033[1;32m${IP}\033[0m"
break
elif [ ${COUNT} -eq 15 ]; then
echo -e "\033[1;31mERROR\033[0m"
echo -e ": \033[1;31mERROR\033[0m"
break
fi
COUNT=$((${COUNT}+1))
sleep 1
echo -n "."
done
echo -e "\033[1;37mLoading DSM kernel...\033[0m"

View File

@@ -1,245 +0,0 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);
/**
* This file contains usual common functions used by patchers
*
* Most of the functions here are written to be C-like without utilizing any of the PHP's magic. This functionality is
* ultimately intended to be rewritten into a dynamic patcher in C. Making this code compatible wtih simple C (e.g.
* by not using fancy regexes) will make it slower in PHP but MUCH easier to rewrite into C later on.
*/
function perr(string $txt, $die = false)
{
fwrite(STDERR, $txt);
if ($die) {
die();
}
}
/**
* @return int
*/
function getELFSectionAddr(string $elf, string $section, int $pos)
{
$secAddr = exec(
sprintf('readelf -S \'%1$s\' | grep -E \'\s%2$s\s\' | awk -F\'%2$s\' \'{ print $2 }\' | awk \'{ print $%3$d }\'', $elf, str_replace('.', '\.', $section), $pos)
);
if (!$secAddr) {
perr("$section section not found in $elf file\n", true);
}
$secAddr = hexdec(substr($secAddr, -8));
perr("Found $section at " . decTo32bUFhex($secAddr) . " in $elf\n");
return $secAddr;
}
function getELFStringLoc(string $elf, string $text)
{
$strAddr = exec(
sprintf(
'readelf -p \'.rodata\' \'%s\' | grep \'%s\' | grep -oE \'\[(\s+)?.+\]\' | grep -oE \'[a-f0-9]+\'',
$elf, $text
)
);
if (!$strAddr) {
perr("$text string not found in $elf file's .rodata section\n", true);
}
$secAddr = hexdec(substr($strAddr, -8));
perr("Found \"$text\" at " . decTo32bUFhex($secAddr) . " in $elf\n");
return $secAddr;
}
function getArgFilePath(int $argn)
{
global $argv;
$file = realpath($argv[$argn]);
if (!is_file($file) || !$file) {
perr("Expected a readable file in argument $argn - found none\n", true);
}
return $file;
}
/**
* Converts decimal value to 32-bit little-endian hex value
*/
function decTo32bLEhex(int $dec)
{
$hex = str_pad(dechex($dec), 32 / 8 * 2, 'f', STR_PAD_LEFT); //32-bit hex
return implode('', array_reverse(str_split($hex, 2))); //make it little-endian
}
/**
* Converts decimal value to 32-bit user-friendly (and big-endian) hex value
*
* This function should really be used for printing
*/
function decTo32bUFhex(int $dec)
{
return implode(' ', str_split(str_pad(dechex($dec), 32 / 8 * 2, 'f', STR_PAD_LEFT), 2));
}
function rawToUFhex(string $raw)
{
$out = '';
for($i=0, $iMax = strlen($raw); $i < $iMax; $i++) {
$out .= sprintf('%02x', ord($raw[$i]));
if ($i+1 !== $iMax) {
$out .= ' ';
}
}
return $out;
}
/**
* Convert hex values to their binary/raw counterparts as-is
*/
function hex2raw(string $hex)
{
$bin = '';
for ($i = 0, $iMax = strlen($hex); $i < $iMax; $i += 2) {
$bin .= chr(hexdec($hex[$i] . $hex[$i + 1]));
}
return $bin;
}
const DIR_FWD = 1;
const DIR_RWD = -1;
function findSequence($fp, string $bin, int $pos, int $dir, int $maxToCheck)
{
if ($maxToCheck === -1) {
$maxToCheck = PHP_INT_MAX;
}
$len = strlen($bin);
do {
fseek($fp, $pos);
if (strcmp(fread($fp, $len), $bin) === 0) {
return $pos;
}
$pos = $pos + $dir;
$maxToCheck--;
} while (!feof($fp) && $pos != -1 && $maxToCheck != 0);
return -1;
}
/**
* Locates a pattern of bytes $searchSeqNum in a $fp stream starting from $pos seeking up to $maxToCheck
*
* @param array $searchSeqNum An array containing n elements (where n=length of the searched sequence). Each element can
* be a null (denoting "any byte"), singular hex/int value (e.g. 0xF5), or a range in a form
* of a two-element array (e.g. [0xF0, 0xF7])
*/
function findSequenceWithWildcard($fp, array $searchSeqNum, int $pos, int $maxToCheck)
{
if ($maxToCheck === -1) {
$maxToCheck = PHP_INT_MAX;
}
$bufLen = count($searchSeqNum);
if ($maxToCheck < $bufLen) {
perr("maxToCheck cannot be smaller than search sequence!", true);
}
//Convert all singular value to raw bytes while leaving arrays as numeric (performance reasons). As this loop is
//executed once per pattern it can be sub-optimal but more careful with data validation
$searchSeq = [];
foreach ($searchSeqNum as $idx => $num) {
if ($num === null) {
$searchSeq[] = null;
} elseif (is_array($num) && count($num) == 2 && is_int($num[0]) && is_int($num[1]) && $num[0] >= 0 &&
$num[0] <= 255 && $num[1] >= 0 && $num[1] <= 255 && $num[0] < $num[1]) {
$searchSeq[] = $num; //Leave them as numeric
} elseif (is_int($num) && $num >= 0 && $num <= 255) {
$searchSeq[] = chr($num);
} else {
perr("Found invalid search sequence at index $idx", true);
}
}
//$pos denotes start position but it's also used to mark where start of a potential pattern match was found
fseek($fp, $pos);
do { //This loop is optimized for speed
$buf = fread($fp, $bufLen);
if (!isset($buf[$bufLen-1])) {
break; //Not enough data = no match
}
$successfulLoops = 0;
foreach ($searchSeq as $byteIdx => $seekByte) {
if ($seekByte === null) { //any character
++$successfulLoops;
continue;
}
//element in the array can be a range [(int)from,(int)to] or a literal SINGLE byte
//if isset finds a second element it will mean for us that it's an array of 2 elements (as we don't expect
//a string longer than a single byte)
if (isset($seekByte[1])) {
$curByteNum = ord($buf[$byteIdx]);
if ($curByteNum < $seekByte[0] || $curByteNum > $seekByte[1]) {
break;
}
} elseif($buf[$byteIdx] !== $seekByte) { //If the byte doesn't match literally we know it's not a match
break;
}
++$successfulLoops;
}
if ($successfulLoops === $bufLen) {
return $pos;
}
fseek($fp, ++$pos);
$maxToCheck--;
} while (!feof($fp) && $maxToCheck != 0);
return -1;
}
/**
* @return resource
*/
function getFileMemMapped(string $path)
{
$fp = fopen('php://memory', 'r+');
fwrite($fp, file_get_contents($path)); //poor man's mmap :D
return $fp;
}
function saveStreamToFile($fp, string $path)
{
perr("Saving stream to $path ...\n");
$fp2 = fopen($path, 'w');
fseek($fp, 0);
while (!feof($fp)) {
fwrite($fp2, fread($fp, 8192));
}
fclose($fp2);
perr("DONE!\n");
}
/**
* Do not call this in time-sensitive code...
*/
function readAt($fp, int $pos, int $len)
{
fseek($fp, $pos);
return fread($fp, $len);
}

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env php
<?php
if ($argc < 2 || $argc > 2) {
fwrite(STDERR, "Usage: " . $argv[0] . " <file>\n");
die();
}
echo hash_file('crc32b', $argv[1]);
?>

View File

@@ -1,5 +1,5 @@
ARPL_VERSION="0.3-alpha2"
ARPL_VERSION="0.3-alpha6"
# Define paths
TMP_PATH="/tmp"
@@ -8,12 +8,14 @@ RAMDISK_PATH="${TMP_PATH}/ramdisk"
LOG_FILE="${TMP_PATH}/log.txt"
USER_CONFIG_FILE="${BOOTLOADER_PATH}/user-config.yml"
MOD_ZIMAGE_FILE="${BOOTLOADER_PATH}/zImage"
MOD_RDGZ_FILE="${BOOTLOADER_PATH}/rd.gz"
ORI_ZIMAGE_FILE="${SLPART_PATH}/zImage"
ORI_RDGZ_FILE="${SLPART_PATH}/rd.gz"
ARPL_BZIMAGE_FILE="${CACHE_PATH}/bzImage-arpl"
ARPL_RAMDISK_FILE="${CACHE_PATH}/initrd-arpl"
MOD_ZIMAGE_FILE="${CACHE_PATH}/zImage-dsm"
MOD_RDGZ_FILE="${CACHE_PATH}/initrd-dsm"
ADDONS_PATH="${CACHE_PATH}/addons"
LKM_PATH="${CACHE_PATH}/lkms"
MODULES_PATH="${CACHE_PATH}/modules"

View File

@@ -34,7 +34,6 @@ mount ${LOADER_DISK}1 ${BOOTLOADER_PATH} || die "Can't mount ${BOOTLOADER_PATH}"
mount ${LOADER_DISK}2 ${SLPART_PATH} || die "Can't mount ${SLPART_PATH}"
mount ${LOADER_DISK}3 ${CACHE_PATH} || die "Can't mount ${CACHE_PATH}"
mkdir -p "${ADDONS_PATH}"
# Move/link SSH machine keys to/from cache volume
[ ! -d "${CACHE_PATH}/ssh" ] && cp -R "/etc/ssh" "${CACHE_PATH}/ssh"
rm -rf "/etc/ssh"
@@ -59,6 +58,14 @@ if [ ! -f "${USER_CONFIG_FILE}" ]; then
writeConfigKey "addons" "{}" "${USER_CONFIG_FILE}"
fi
# Set custom MAC if defined
MAC1=`readConfigKey "cmdline.mac1" "${USER_CONFIG_FILE}"`
if [ -n "${MAC1}" ]; then
MAC="${MAC1:0:2}:${MAC1:2:2}:${MAC1:4:2}:${MAC1:6:2}:${MAC1:8:2}:${MAC1:10:2}"
ip link set dev eth0 address ${MAC} >/dev/null 2>&1 && \
(/etc/init.d/S41dhcpcd restart >/dev/null 2>&1 &) || true
fi
# Get the VID/PID if we are in USB
VID="0x0000"
PID="0x0000"
@@ -148,3 +155,7 @@ echo
echo -e "User config is on \033[1;32m${USER_CONFIG_FILE}\033[0m"
echo -e "Default SSH Root password is \033[1;31mRedp1lL-1s-4weSomE\033[0m"
echo
mkdir -p "${ADDONS_PATH}"
mkdir -p "${LKM_PATH}"
mkdir -p "${MODULES_PATH}"

Binary file not shown.

View File

@@ -63,6 +63,7 @@ function modelMenu() {
M="`basename ${M}`"
M="${M::-4}"
PLATFORM=`readModelKey "${M}" "platform"`
DT="`readModelKey "${M}" "dt"`"
# Check id model is compatible with CPU
COMPATIBLE=1
for F in `readModelArray "${M}" "flags"`; do
@@ -71,9 +72,10 @@ function modelMenu() {
break
fi
done
[ ${COMPATIBLE} -eq 1 ] && ITEMS+="${M} ${PLATFORM} "
[ "${DT}" = "true" ] && DT="-DT" || DT=""
[ ${COMPATIBLE} -eq 1 ] && ITEMS+="${M} \Zb${PLATFORM}${DT}\Zn "
done < <(find "${MODEL_CONFIG_PATH}" -maxdepth 1 -name \*.yml | sort)
dialog --backtitle "`backtitle`" --menu "Choose the model" 0 0 0 \
dialog --backtitle "`backtitle`" --colors --menu "Choose the model" 0 0 0 \
${ITEMS} 2>${TMP_PATH}/resp
[ $? -ne 0 ] && return
resp=$(<${TMP_PATH}/resp)
@@ -104,9 +106,23 @@ function buildMenu() {
if [ "${BUILD}" != "${resp}" ]; then
BUILD=${resp}
writeConfigKey "build" "${BUILD}" "${USER_CONFIG_FILE}"
DIRTY=1
# Delete synoinfo and reload model/build synoinfo
writeConfigKey "synoinfo" "{}" "${USER_CONFIG_FILE}"
while IFS="=" read KEY VALUE; do
writeConfigKey "synoinfo.${KEY}" "${VALUE}" "${USER_CONFIG_FILE}"
done < <(readModelMap "${MODEL}" "builds.${BUILD}.synoinfo")
# Check addons
PLATFORM="`readModelKey "${MODEL}" "platform"`"
KVER="`readModelKey "${MODEL}" "builds.${BUILD}.kver"`"
while IFS="=" read ADDON PARAM; do
[ -z "${ADDON}" ] && continue
if ! checkAddonExist "${ADDON}" "${PLATFORM}" "${KVER}"; then
deleteConfigKey "addons.${ADDON}" "${USER_CONFIG_FILE}"
fi
done < <(readConfigMap "addons" "${USER_CONFIG_FILE}")
# Remove old files
rm -f "${ORI_ZIMAGE_FILE}" "${ORI_RDGZ_FILE}" "${MOD_ZIMAGE_FILE}" "${MOD_RDGZ_FILE}"
DIRTY=1
fi
}
@@ -168,6 +184,7 @@ function addonMenu() {
d "Delete addon(s)" \
s "Show user addons" \
m "Show all available addons" \
o "Download a external addon" \
e "Exit" \
2>${TMP_PATH}/resp
[ $? -ne 0 ] && return
@@ -180,6 +197,7 @@ function addonMenu() {
done < <(availableAddons "${PLATFORM}" "${KVER}")
if [ ! -f "${TMP_PATH}/menu" ] ; then
dialog --backtitle "`backtitle`" --msgbox "No available addons to add" 0 0
NEXT="e"
continue
fi
dialog --backtitle "`backtitle`" --menu "Select an addon" 0 0 0 \
@@ -237,6 +255,30 @@ function addonMenu() {
dialog --backtitle "`backtitle`" --title "Available addons" \
--colors --msgbox "${MSG}" 0 0
;;
o)
TEXT="please enter the complete URL to download.\n"
dialog --backtitle "`backtitle`" --aspect 18 --colors --inputbox "${TEXT}" 0 0 \
2>${TMP_PATH}/resp
[ $? -ne 0 ] && continue
URL="`<"${TMP_PATH}/resp"`"
[ -z "${URL}" ] && continue
clear
echo "Downloading ${URL}"
curl --insecure -L "${URL}" -o "${TMP_PATH}/addon.tgz" --progress-bar
if [ $? -ne 0 ]; then
dialog --backtitle "`backtitle`" --title "Error downloading" --aspect 18 \
--msgbox "Check internet, URL or cache disk space" 0 0
return 1
fi
ADDON="`untarAddon "${TMP_PATH}/addon.tgz"`"
if [ -n "${ADDON}" ]; then
dialog --backtitle "`backtitle`" --title "Success" --aspect 18 \
--msgbox "Addon '${ADDON}' added to loader" 0 0
else
dialog --backtitle "`backtitle`" --title "Invalid addon" --aspect 18 \
--msgbox "File format not recognized!" 0 0
fi
;;
e) return ;;
esac
done
@@ -249,12 +291,13 @@ function cmdlineMenu() {
while IFS="=" read KEY VALUE; do
[ -n "${KEY}" ] && CMDLINE["${KEY}"]="${VALUE}"
done < <(readConfigMap "cmdline" "${USER_CONFIG_FILE}")
echo "a \"Add/edit an cmdline item\"" > "${TMP_PATH}/menu"
echo "d \"Delete cmdline item(s)\"" >> "${TMP_PATH}/menu"
echo "s \"Show user cmdline\"" >> "${TMP_PATH}/menu"
echo "m \"Show model/build cmdline\"" >> "${TMP_PATH}/menu"
echo "u \"Show SATA(s) # ports and drives\"" >> "${TMP_PATH}/menu"
echo "e \"Exit\"" >> "${TMP_PATH}/menu"
echo "a \"Add/edit an cmdline item\"" > "${TMP_PATH}/menu"
echo "d \"Delete cmdline item(s)\"" >> "${TMP_PATH}/menu"
echo "c \"Define a custom MAC\"" >> "${TMP_PATH}/menu"
echo "s \"Show user cmdline\"" >> "${TMP_PATH}/menu"
echo "m \"Show model/build cmdline\"" >> "${TMP_PATH}/menu"
echo "u \"Show SATA(s) # ports and drives\"" >> "${TMP_PATH}/menu"
echo "e \"Exit\"" >> "${TMP_PATH}/menu"
# Loop menu
while true; do
dialog --backtitle "`backtitle`" --menu "Choose a option" 0 0 0 \
@@ -296,6 +339,29 @@ function cmdlineMenu() {
deleteConfigKey "cmdline.${I}" "${USER_CONFIG_FILE}"
done
;;
c)
dialog --backtitle "`backtitle`" --title "User cmdline" \
--inputbox "Type a custom MAC address" 0 0 "${CMDLINE['mac1']}"\
2>${TMP_PATH}/resp
[ $? -ne 0 ] && continue
MAC1="`sed 's/://g' <"${TMP_PATH}/resp"`"
if [ -z "${MAC1}" ]; then
unset CMDLINE["mac1"]
unset CMDLINE["netif_num"]
deleteConfigKey "cmdline.mac1" "${USER_CONFIG_FILE}"
deleteConfigKey "cmdline.netif_num" "${USER_CONFIG_FILE}"
else
CMDLINE["mac1"]="${MAC1}"
CMDLINE["netif_num"]=1
writeConfigKey "cmdline.mac1" "${MAC1}" "${USER_CONFIG_FILE}"
writeConfigKey "cmdline.netif_num" "1" "${USER_CONFIG_FILE}"
fi
/etc/init.d/S30arpl-mac restart 2>&1 | dialog --backtitle "`backtitle`" \
--title "User cmdline" --progressbox "Changing mac" 20 70
/etc/init.d/S41dhcpcd restart 2>&1 | dialog --backtitle "`backtitle`" \
--title "User cmdline" --progressbox "Renewing IP" 20 70
IP=`ip route get 1.1.1.1 2>/dev/null | awk '{print$7}'`
;;
s)
ITEMS=""
for KEY in ${!CMDLINE[@]}; do
@@ -361,8 +427,7 @@ function synoinfoMenu() {
if [ "${DT}" != "true" ]; then
echo "x \"Set maxdisks manually\"" >> "${TMP_PATH}/menu"
fi
echo "s \"Show user synoinfo\"" >> "${TMP_PATH}/menu"
echo "m \"Show model/build synoinfo\"" >> "${TMP_PATH}/menu"
echo "s \"Show synoinfo entries\"" >> "${TMP_PATH}/menu"
echo "e \"Exit\"" >> "${TMP_PATH}/menu"
# menu loop
@@ -372,13 +437,14 @@ function synoinfoMenu() {
[ $? -ne 0 ] && return
case "`<${TMP_PATH}/resp`" in
a)
dialog --backtitle "`backtitle`" --title "User synoinfo" \
--inputbox "Type a name of synoinfo variable" 0 0 \
dialog --backtitle "`backtitle`" --title "Synoinfo entries" \
--inputbox "Type a name of synoinfo entry" 0 0 \
2>${TMP_PATH}/resp
[ $? -ne 0 ] && continue
NAME="`sed 's/://g' <"${TMP_PATH}/resp"`"
dialog --backtitle "`backtitle`" --title "User synoinfo" \
--inputbox "Type a value of '${NAME}' variable" 0 0 "${SYNOINFO[${NAME}]}" \
NAME="`<"${TMP_PATH}/resp"`"
[ -z "${NAME}" ] && continue
dialog --backtitle "`backtitle`" --title "Synoinfo entries" \
--inputbox "Type a value of '${NAME}' entry" 0 0 "${SYNOINFO[${NAME}]}" \
2>${TMP_PATH}/resp
[ $? -ne 0 ] && continue
VALUE="`<"${TMP_PATH}/resp"`"
@@ -388,7 +454,7 @@ function synoinfoMenu() {
;;
d)
if [ ${#SYNOINFO[@]} -eq 0 ]; then
dialog --backtitle "`backtitle`" --msgbox "No user synoinfo to remove" 0 0
dialog --backtitle "`backtitle`" --msgbox "No synoinfo entries to remove" 0 0
continue
fi
ITEMS=""
@@ -396,7 +462,7 @@ function synoinfoMenu() {
ITEMS+="${I} ${SYNOINFO[${I}]} off "
done
dialog --backtitle "`backtitle`" \
--checklist "Select synoinfo to remove" 0 0 0 ${ITEMS} \
--checklist "Select synoinfo entry to remove" 0 0 0 ${ITEMS} \
2>"${TMP_PATH}/resp"
[ $? -ne 0 ] && continue
RESP=`<"${TMP_PATH}/resp"`
@@ -421,15 +487,7 @@ function synoinfoMenu() {
for KEY in ${!SYNOINFO[@]}; do
ITEMS+="${KEY}: ${SYNOINFO[$KEY]}\n"
done
dialog --backtitle "`backtitle`" --title "User synoinfo" \
--aspect 18 --msgbox "${ITEMS}" 0 0
;;
m)
ITEMS=""
while IFS="=" read KEY VALUE; do
ITEMS+="${KEY}: ${VALUE}\n"
done < <(readModelMap "${MODEL}" "builds.${BUILD}.synoinfo")
dialog --backtitle "`backtitle`" --title "Model/build synoinfo" \
dialog --backtitle "`backtitle`" --title "Synoinfo entries" \
--aspect 18 --msgbox "${ITEMS}" 0 0
;;
e) return ;;
@@ -724,8 +782,8 @@ function updateMenu() {
fi
dialog --backtitle "`backtitle`" --title "Update arpl" --aspect 18 \
--infobox "Installing new files" 0 0
mv /tmp/bzImage /mnt/p1/bzImage-arpl
mv /tmp/rootfs.cpio.xz /mnt/p1/initrd-arpl
mv /tmp/bzImage "${ARPL_BZIMAGE_FILE}"
mv /tmp/rootfs.cpio.xz "${ARPL_RAMDISK_FILE}"
dialog --backtitle "`backtitle`" --title "Update arpl" --aspect 18 \
--yesno "Arpl updated with success to ${TAG}!\nReboot?" 0 0
[ $? -ne 0 ] && continue
@@ -757,13 +815,13 @@ function updateMenu() {
unzip /tmp/addons.zip -d /tmp/addons >/dev/null 2>&1
dialog --backtitle "`backtitle`" --title "Update addons" --aspect 18 \
--infobox "Installing new addons" 0 0
DEST_PATH="/mnt/p3/addons"
for PKG in `ls /tmp/addons/*.addon`; do
ADDON=`basename ${PKG} | sed 's|.addon||'`
rm -rf "${DEST_PATH}/${ADDON}"
mkdir -p "${DEST_PATH}/${ADDON}"
tar xaf "${PKG}" -C "${DEST_PATH}/${ADDON}" >/dev/null 2>&1
rm -rf "${ADDONS_PATH}/${ADDON}"
mkdir -p "${ADDONS_PATH}/${ADDON}"
tar xaf "${PKG}" -C "${ADDONS_PATH}/${ADDON}" >/dev/null 2>&1
done
DIRTY=1
dialog --backtitle "`backtitle`" --title "Update addons" --aspect 18 \
--msgbox "Addons updated with success!" 0 0
;;
@@ -789,6 +847,7 @@ function updateMenu() {
--infobox "Extracting last version" 0 0
rm -rf "${LKM_PATH}/"*
unzip /tmp/rp-lkms.zip -d "${LKM_PATH}" >/dev/null 2>&1
DIRTY=1
dialog --backtitle "`backtitle`" --title "Update LKMs" --aspect 18 \
--msgbox "LKMs updated with success!" 0 0
;;
@@ -825,6 +884,7 @@ function updateMenu() {
rm "${MODULES_PATH}/${P}.tgz"
mv "/tmp/${P}.tgz" "${MODULES_PATH}/${P}.tgz"
done
DIRTY=1
dialog --backtitle "`backtitle`" --title "Update Modules" --aspect 18 \
--msgbox "Modules updated with success!" 0 0
;;

View File

@@ -11,6 +11,8 @@ synoinfo: &synoinfo
updateurl: "http://example.com/"
myds_region_api_base_url: "https://example.com"
security_version_server: "https://example.com/smallupdate"
supportraidgroup: "no"
supportssdcache: "no"
cmdline: &cmdline
SMBusHddDynamicPower: 1
vender_format_version: 2
@@ -47,3 +49,21 @@ builds:
- "ramdisk-common-disable-root-pwd.patch"
- "ramdisk-common-init-script.patch"
- "ramdisk-common-post-init-script.patch"
42661:
ver: "7.1.0"
kver: "4.4.180"
rd-compressed: false
efi-bug: no
cmdline:
<<: *cmdline
synoinfo:
<<: *synoinfo
pat:
url: "https://global.download.synology.com/download/DSM/release/7.1/42661-1/DSM_DS2422%2B_42661.pat"
hash: "c38fee0470c592b679ab52a64eac76b2a3912fb2e6aba65a65abb5aa05a98d4c"
ramdisk-hash: "bb109132e96b1e26d5e3d44557944f7518168d8cb18e35d6254c0dfe7fb19382"
zimage-hash: "d939b5937be00a644aae64c33633619a7c310433e60a515c77bbef00b0a7e6b6"
patch:
- "ramdisk-common-disable-root-pwd.patch"
- "ramdisk-common-init-script.patch"
- "ramdisk-42661-post-init-script.patch"

View File

@@ -7,6 +7,10 @@ synoinfo: &synoinfo
small_info_path: "https://example.com/null"
updateurl: "http://example.com/"
myds_region_api_base_url: "https://example.com"
support_disk_compatibility: "no"
support_memory_compatibility: "no"
supportraidgroup: "no"
supportssdcache: "no"
cmdline: &cmdline
syno_hdd_powerup_seq: 0
HddHotplug: 0

View File

@@ -11,6 +11,10 @@ synoinfo: &synoinfo
updateurl: "http://example.com/"
myds_region_api_base_url: "https://example.com"
security_version_server: "https://example.com/smallupdate"
support_disk_compatibility: "no"
support_memory_compatibility: "no"
supportraidgroup: "no"
supportssdcache: "no"
cmdline: &cmdline
syno_hdd_powerup_seq: 0
HddHotplug: 0

View File

@@ -1,141 +0,0 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);
/**
* A quick tool for patching the boot_params check in the DSM kernel image
* This lets you tinker with the initial ramdisk contents without disabling mount() features and modules loading
*
* The overall pattern we need to find is:
* - an CDECL function
* - does "LOCK OR [const-ptr],n" 4x
* - values of ORs are 1/2/4/8 respectively
* - [const-ptr] is always the same
*
* Usage: php patch-boot_params-check.php vmlinux vmlinux-mod
*/
require __DIR__ . '/common.php';
if ($argc < 2 || $argc > 3) {
perr("Usage: " . $argv[0] . " <inFile> [<outFile>]\n", true);
}
$file = getArgFilePath(1);
perr("\nGenerating patch for $file\n");
//The function will reside in init code part. We don't care we may potentially search beyond as we expect it to be found
$codeAddr = getELFSectionAddr($file, '.init.text', 3);
//Finding a function boundary is non-trivial really as patters can vary, we can have multiple exit points, and in CISC
// there are many things which may match e.g. "PUSH EBP". Implementing even a rough disassembler is pointless.
//However, we can certainly cheat here as we know with CDECL a non-empty function will always contain one or more
// PUSH (0x41) R12-R15 (0x54-57) sequences. Then we can search like a 1K forward for these characteristic LOCK OR.
const PUSH_R12_R15_SEQ = [0x41, [0x54, 0x57]];
const PUSH_R12_R15_SEQ_LEN = 2;
const LOCK_OR_LOOK_AHEAD = 1024;
const LOCK_OR_PTR_SEQs = [
[0xF0, 0x80, null, null, null, null, null, 0x01],
[0xF0, 0x80, null, null, null, null, null, 0x02],
[0xF0, 0x80, null, null, null, null, null, 0x04],
[0xF0, 0x80, null, null, null, null, null, 0x08],
];
const LOCK_OR_PTR_SEQs_NUM = 4; //how many sequences we are expecting
const LOCK_OR_PTR_SEQ_LEN = 8; //length of a single sequence
$fp = getFileMemMapped($file); //Read the whole file to memory to make fseet/fread much faster
$pos = $codeAddr; //Start from where code starts
$orsPos = null; //When matched it will contain our resulting file offsets to LOCK(); OR BYTE PTR [rip+...],0x calls
perr("Looking for f() candidates...\n");
do {
$find = findSequenceWithWildcard($fp, PUSH_R12_R15_SEQ, $pos, -1);
if ($find === -1) {
break; //no more "functions" left
}
perr("\rAnalyzing f() candidate @ " . decTo32bUFhex($pos));
//we found something looking like PUSH R12-R15, now find the ORs
$orsPos = []; //file offsets where LOCK() calls should start
$orsPosNum = 0; //Number of LOCK(); OR ptr sequences found
$seqPos = $pos;
foreach (LOCK_OR_PTR_SEQs as $idx => $seq) {
$find = findSequenceWithWildcard($fp, $seq, $seqPos, LOCK_OR_LOOK_AHEAD);
if ($find === -1) {
break; //Seq not found - there's no point to look further
}
$orsPos[] = $find;
++$orsPosNum;
$seqPos = $find + LOCK_OR_PTR_SEQ_LEN; //Next search will start after the current sequence code
}
//We can always move forward by the function token length (obvious) but if we couldn't find any LOCK-OR tokens
// we can skip the whole look ahead distance. We CANNOT do that if we found even a single token because the next one
// might have been just after the look ahead distance
if ($orsPosNum !== LOCK_OR_PTR_SEQs_NUM) {
$pos += PUSH_R12_R15_SEQ_LEN;
if ($orsPosNum === 0) {
$pos += LOCK_OR_LOOK_AHEAD;
}
continue; //Continue the main search loop to find next function candidate
}
//We found LOCK(); OR ptr sequences so we can print some logs and collect ptrs (as this is quite expensive)
$seqPtrsDist = [];
perr("\n[?] Found possible f() @ " . decTo32bUFhex($pos) . "\n");
$ptrOffset = null;
$equalJumps = 0;
foreach (LOCK_OR_PTR_SEQs as $idx => $seq) {
//data will have the following bytes:
// [0-LOCK()] [1-OR()] [2-BYTE-PTR] [3-OFFS-b3] [4-OFFS-b2] [5-OFFS-b1] [6-OFFS-b1] [7-NUMBER]
$seqData = readAt($fp, $orsPos[$idx], LOCK_OR_PTR_SEQ_LEN);
$newPtrOffset = //how far it "jumps"
$orsPos[$idx] +
(unpack('V', $seqData[3] . $seqData[4] . $seqData[5] . $seqData[6])[1]); //u32 bit LE
if($ptrOffset === null) {
$ptrOffset = $newPtrOffset; //Save the first one to compare in the next loop
++$equalJumps;
} elseif ($ptrOffset === $newPtrOffset) {
++$equalJumps;
}
perr(
"\t[+] Found LOCK-OR#$idx sequence @ " . decTo32bUFhex($orsPos[$idx]) . " => " .
rawToUFhex($seqData) . " [RIP+(dec)$newPtrOffset]\n"
);
}
if ($equalJumps !== 4) {
perr("\t[-] LOCK-OR PTR offset mismatch - $equalJumps/" . LOCK_OR_PTR_SEQs_NUM . " matched\n");
//If the pointer checking failed we can at least move beyond the last LOCK-OR found as we know there's no valid
// sequence of LOCK-ORs there
$pos = $orsPos[3];
continue;
}
perr("\t[+] All $equalJumps LOCK-OR PTR offsets equal - match found!\n");
break;
} while(!feof($fp));
if ($orsPos === null) { //There's a small chance no candidates with LOCK ORs were found
perr("Failed to find matching sequences", true);
}
//Patch offsets
foreach ($orsPos as $seqFileOffset) {
//The offset will point at LOCK(), we need to change the OR (0x80 0x0d) to AND (0x80 0x25) so the two bytes after
$seqFileOffset = $seqFileOffset+2;
perr("Patching OR to AND @ file offset (dec)$seqFileOffset\n");
fseek($fp, $seqFileOffset);
fwrite($fp, "\x25"); //0x0d is OR, 0x25 is AND
}
if (!isset($argv[2])) {
perr("No output file specified - discarding data\n");
exit;
}
saveStreamToFile($fp, $argv[2]);
fclose($fp);

View File

@@ -1,85 +0,0 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);
/**
* A quick tool for patching the ramdisk check in the DSM kernel image
* This lets you tinker with the initial ramdisk contents without disabling mount() features and modules loading
*
* Usage: php patch-ramdisk-check.php vmlinux vmlinux-mod
*/
require __DIR__ . '/common.php';
if ($argc < 2 || $argc > 3) {
perr("Usage: " . $argv[0] . " <inFile> [<outFile>]\n", true);
}
$file = getArgFilePath(1);
perr("\nGenerating patch for $file\n");
//Strings (e.g. error for printk()) reside in .rodata - start searching there to save time
$rodataAddr = getELFSectionAddr($file, '.rodata', 2);
//Locate the precise location of "ramdisk error" string
$rdErrAddr = getELFStringLoc($file, '3ramdisk corrupt');
//offsets will be 32 bit in ASM and in LE
$errPrintAddr = $rodataAddr + $rdErrAddr;
$errPrintCAddrLEH = decTo32bLEhex($errPrintAddr - 1); //Somehow rodata contains off-by-one sometimes...
$errPrintAddrLEH = decTo32bLEhex($errPrintAddr);
perr("LE arg addr: " . $errPrintCAddrLEH . "\n");
$fp = getFileMemMapped($file); //Read the whole file to memory to make fseet/fread much faster
//Find the printk() call argument
$printkPos = findSequence($fp, hex2raw($errPrintCAddrLEH), 0, DIR_FWD, -1);
if ($printkPos === -1) {
perr("printk pos not found!\n", true);
}
perr("Found printk arg @ " . decTo32bUFhex($printkPos) . "\n");
//double check if it's a MOV reg,VAL (where reg is EAX/ECX/EDX/EBX/ESP/EBP/ESI/EDI)
fseek($fp, $printkPos - 3);
$instr = fread($fp, 3);
if (strncmp($instr, "\x48\xc7", 2) !== 0) {
perr("Expected MOV=>reg before printk error, got " . bin2hex($instr) . "\n", true);
}
$dstReg = ord($instr[2]);
if ($dstReg < 192 || $dstReg > 199) {
perr("Expected MOV w/reg operand [C0-C7], got " . bin2hex($instr[2]) . "\n", true);
}
$movPos = $printkPos - 3;
perr("Found printk MOV @ " . decTo32bUFhex($movPos) . "\n");
//now we should seek a reasonable amount (say, up to 32 bytes) for a sequence of CALL x => TEST EAX,EAX => JZ
$testPos = findSequence($fp, "\x85\xc0", $movPos, DIR_RWD, 32);
if ($testPos === -1) {
perr("Failed to find TEST eax,eax\n", true);
}
$jzPos = $testPos + 2;
fseek($fp, $jzPos);
$jz = fread($fp, 2);
if ($jz[0] !== "\x74") {
perr("Failed to find JZ\n", true);
}
$jzp = "\xEB" . $jz[1];
perr('OK - patching ' . bin2hex($jz) . " (JZ) to " . bin2hex($jzp) . " (JMP) @ $jzPos\n");
fseek($fp, $jzPos); //we should be here already
perr("Patched " . fwrite($fp, $jzp) . " bytes in memory\n");
if (!isset($argv[2])) {
perr("No output file specified - discarding data\n");
exit;
}
if (!isset($argv[2])) {
perr("No output file specified - discarding data\n");
exit;
}
saveStreamToFile($fp, $argv[2]);
fclose($fp);

View File

@@ -13,7 +13,7 @@
echo "Insert basic USB modules..."
SYNOLoadModules $USB_MODULES
+SYNOLoadModules "usb-storage"
+/addons/addons.sh early; /addons/addons.sh patches
+/addons/addons.sh early
# insert Etron USB3.0 drivers

View File

@@ -44,10 +44,7 @@ RD_COMPRESSED="`readModelKey "${MODEL}" "builds.${BUILD}.rd-compressed"`"
declare -A SYNOINFO
declare -A ADDONS
# Read more config
while IFS="=" read KEY VALUE; do
[ -n "${KEY}" ] && SYNOINFO["${KEY}"]="${VALUE}"
done < <(readModelMap "${MODEL}" "builds.${BUILD}.synoinfo")
# Read synoinfo and addons from config
while IFS="=" read KEY VALUE; do
[ -n "${KEY}" ] && SYNOINFO["${KEY}"]="${VALUE}"
done < <(readConfigMap "synoinfo" "${USER_CONFIG_FILE}")
@@ -89,14 +86,14 @@ gzip -dc "${CACHE_PATH}/modules/${PLATFORM}-${KVER}.tgz" | tar xf - -C "${TMP_PA
for F in `ls "${TMP_PATH}/modules/"*.ko`; do
M=`basename ${F}`
# Skip existent modules
[ -f "${RAMDISK_PATH}/usr/lib/modules/${M}" ] || mv "${F}" "${RAMDISK_PATH}/usr/lib/modules/${M}"
# [ -f "${RAMDISK_PATH}/usr/lib/modules/${M}" ] || mv "${F}" "${RAMDISK_PATH}/usr/lib/modules/${M}"
cp "${F}" "${RAMDISK_PATH}/usr/lib/modules/${M}"
done
mkdir -p "${RAMDISK_PATH}/usr/lib/firmware"
gzip -dc "${CACHE_PATH}/modules/firmware.tgz" | tar xf - -C "${RAMDISK_PATH}/usr/lib/firmware"
# Clean
rm -rf "${TMP_PATH}/modules"
# Build modules dependencies
/opt/arpl/depmod -a -b ${RAMDISK_PATH} 2>/dev/null
echo -n "."
# Copying fake modprobe
cp "${PATCH_PATH}/iosched-trampoline.sh" "${RAMDISK_PATH}/usr/sbin/modprobe"
@@ -107,16 +104,22 @@ cp "${LKM_PATH}/rp-${PLATFORM}-${KVER}-${LKM}.ko" "${RAMDISK_PATH}/usr/lib/modul
MAXDISKS=`readConfigKey "maxdisks" "${USER_CONFIG_FILE}"`
# Check if model needs Device-tree dynamic patch
DT="`readModelKey "${MODEL}" "dt"`"
# Add system addon "dtbpatch" or "maxdisks"
[ "${DT}" = "true" ] && ADDONS['dtbpatch']="" || ADDONS['maxdisks']="${MAXDISKS}"
# Indispensable eudev system addon
ADDONS['eudev']=""
echo -n "."
mkdir -p "${RAMDISK_PATH}/addons"
echo "#!/bin/sh" > "${RAMDISK_PATH}/addons/addons.sh"
echo 'export INSMOD="/sbin/insmod"' >> "${RAMDISK_PATH}/addons/addons.sh"
echo 'echo "addons.sh called with params ${@}"' >> "${RAMDISK_PATH}/addons/addons.sh"
# Required eudev and dtbpatch/maxdisks
installAddon eudev
echo "/addons/eudev.sh \${1} " >> "${RAMDISK_PATH}/addons/addons.sh" 2>"${LOG_FILE}" || dieLog
if [ "${DT}" = "true" ]; then
installAddon dtbpatch
echo "/addons/dtbpatch.sh \${1} " >> "${RAMDISK_PATH}/addons/addons.sh" 2>"${LOG_FILE}" || dieLog
else
installAddon maxdisks
echo "/addons/maxdisks.sh \${1} ${MAXDISKS}" >> "${RAMDISK_PATH}/addons/addons.sh" 2>"${LOG_FILE}" || dieLog
fi
# User addons
for ADDON in ${!ADDONS[@]}; do
PARAMS=${ADDONS[${ADDON}]}
if ! installAddon ${ADDON}; then
@@ -127,6 +130,9 @@ for ADDON in ${!ADDONS[@]}; do
done
chmod +x "${RAMDISK_PATH}/addons/addons.sh"
# Build modules dependencies
/opt/arpl/depmod -a -b ${RAMDISK_PATH} 2>/dev/null
# Reassembly ramdisk
echo -n "."
if [ "${RD_COMPRESSED}" == "true" ]; then

View File

@@ -56,8 +56,7 @@ gzip -cd "${SCRIPT_DIR}/zImage_template.gz" > "${ZIMAGE_MOD}"
dd if="${VMLINUX_MOD}" of="${ZIMAGE_MOD}" bs=16494 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
file_size_le "${VMLINUX_MOD}" | dd of="${ZIMAGE_MOD}" bs=15745134 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
RUN_SIZE=$(objdump -h ${VMLINUX_MOD} | sh "${SCRIPT_DIR}/calc_run_size.sh")
RUN_SIZE=`objdump -h ${VMLINUX_MOD} | sh "${SCRIPT_DIR}/calc_run_size.sh"`
size_le $RUN_SIZE | dd of=$ZIMAGE_MOD bs=15745210 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
file_size_le "${VMLINUX_MOD}" | dd of="${ZIMAGE_MOD}" bs=15745244 seek=1 conv=notrunc >"${LOG_FILE}" 2>&1 || dieLog
# cksum $ZIMAGE_MOD # https://blog.box.com/crc32-checksums-the-good-the-bad-and-the-ugly
size_le $(($((16#$(php "${SCRIPT_DIR}/crc32.php" "${ZIMAGE_MOD}"))) ^ 0xFFFFFFFF)) | dd of="${ZIMAGE_MOD}" conv=notrunc oflag=append >"${LOG_FILE}" 2>&1 || dieLog
size_le $(($((16#`crc32 "${ZIMAGE_MOD}" | awk '{print$1}'`)) ^ 0xFFFFFFFF)) | dd of="${ZIMAGE_MOD}" conv=notrunc oflag=append >"${LOG_FILE}" 2>&1 || dieLog

View File

@@ -12,14 +12,11 @@ echo -n "."
# Extract vmlinux
/opt/arpl/bzImage-to-vmlinux.sh "${ORI_ZIMAGE_FILE}" "${TMP_PATH}/vmlinux" >"${LOG_FILE}" 2>&1 || dieLog
echo -n "."
# Patch boot params
/opt/arpl/patch-boot_params-check.php "${TMP_PATH}/vmlinux" "${TMP_PATH}/vmlinux-mod1" >"${LOG_FILE}" 2>&1 || dieLog
echo -n "."
# Patch ramdisk check
/opt/arpl/patch-ramdisk-check.php "${TMP_PATH}/vmlinux-mod1" "${TMP_PATH}/vmlinux-mod2" >"${LOG_FILE}" 2>&1 || dieLog
# Patch boot params and ramdisk check
/opt/arpl/kpatch "${TMP_PATH}/vmlinux" "${TMP_PATH}/vmlinux-mod" >"${LOG_FILE}" 2>&1 || dieLog
echo -n "."
# rebuild zImage
/opt/arpl/vmlinux-to-bzImage.sh "${TMP_PATH}/vmlinux-mod2" "${MOD_ZIMAGE_FILE}" >"${LOG_FILE}" 2>&1 || dieLog
/opt/arpl/vmlinux-to-bzImage.sh "${TMP_PATH}/vmlinux-mod" "${MOD_ZIMAGE_FILE}" >"${LOG_FILE}" 2>&1 || dieLog
echo -n "."
# Update HASH of new DSM zImage

View File

@@ -6,7 +6,7 @@ terminal_input console
terminal_output console
set default="0"
set timeout="3"
set timeout="5"
set timeout_style="menu"
insmod loadenv
@@ -51,8 +51,8 @@ if serial --unit=0 --speed=115200; then
fi
insmod search
search --set=root --label "ARPL1"
if [ -s /zImage -a -s /rd.gz ]; then
search --set=root --label "ARPL3"
if [ -s /zImage-dsm -a -s /initrd-dsm ]; then
menuentry 'Boot DSM' --id boot {
echo "Loading kernel..."
linux /bzImage-arpl console=ttyS0,115200n8 quiet
@@ -60,6 +60,13 @@ if [ -s /zImage -a -s /rd.gz ]; then
initrd /initrd-arpl
echo "Booting..."
}
menuentry 'Force re-install DSM' --id junior {
echo "Loading kernel..."
linux /bzImage-arpl console=ttyS0,115200n8 quiet force_junior
echo "Loading initramfs..."
initrd /initrd-arpl
echo "Booting..."
}
else
set timeout="1"
fi

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,25 @@
version: 1
name: 9p
description: "Driver for virtio 9p"
available-for:
bromolow-3.10.108:
install-script: &script "install.sh"
copy: "bromolow-3.10.108"
apollolake-4.4.180:
install-script: *script
copy: "apollolake-4.4.180"
broadwell-4.4.180:
install-script: *script
copy: "broadwell-4.4.180"
broadwellnk-4.4.180:
install-script: *script
copy: "broadwellnk-4.4.180"
denverton-4.4.180:
install-script: *script
copy: "denverton-4.4.180"
geminilake-4.4.180:
install-script: *script
copy: "geminilake-4.4.180"
v1000-4.4.180:
install-script: *script
copy: "v1000-4.4.180"

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,7 @@
version: 1
name: i915
description: "Intel iGPU Drivers (10th Gen)"
available-for:
geminilake-4.4.180:
install-script: "install.sh"
copy: "geminilake-4.4.180"

Binary file not shown.

View File

@@ -37,12 +37,11 @@ BR2_PACKAGE_NVME=y
BR2_PACKAGE_PCIUTILS=y
BR2_PACKAGE_SMARTMONTOOLS=y
BR2_PACKAGE_USBUTILS=y
BR2_PACKAGE_PHP=y
BR2_PACKAGE_PHP_SAPI_CLI=y
BR2_PACKAGE_DTC=y
BR2_PACKAGE_DTC_PROGRAMS=y
BR2_PACKAGE_LIBCURL=y
BR2_PACKAGE_LIBCURL_CURL=y
BR2_PACKAGE_PCRE2=y
BR2_PACKAGE_DHCPCD=y
BR2_PACKAGE_OPENSSH=y
# BR2_PACKAGE_OPENSSH_CLIENT is not set
@@ -63,3 +62,4 @@ BR2_PACKAGE_HOST_DOSFSTOOLS=y
BR2_PACKAGE_HOST_E2FSPROGS=y
BR2_PACKAGE_R8168=y
BR2_PACKAGE_R8125=y

View File

@@ -49,6 +49,7 @@ if [ -d ../arpl-addons ]; then
echo "${D}"
(cd ${D} && tar caf "${MODULES_DIR}/${D}.tgz" *.ko)
done
(cd firmware && tar caf "${MODULES_DIR}/firmware.tgz" *)
cd -
else
TAG=`curl -s https://api.github.com/repos/fbelavenuto/arpl-modules/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}'`
@@ -56,6 +57,7 @@ else
FILE="${PLATFORM}-${KVER}"
curl -L "https://github.com/fbelavenuto/arpl-modules/releases/download/${TAG}/${FILE}.tgz" -o "${MODULES_DIR}/${FILE}.tgz"
done < PLATFORMS
curl -L "https://github.com/fbelavenuto/arpl-modules/releases/download/${TAG}/firmware.tgz" -o "${MODULES_DIR}/firmware.tgz"
fi
# Copy files
@@ -66,13 +68,14 @@ cp -Ru files/* .buildroot/
cd .buildroot
echo "Generating default config"
make arpl_defconfig
make BR2_EXTERNAL=../external arpl_defconfig
echo "Version: ${VERSION}"
echo "Building... Drink a coffee and wait!"
make BR2_EXTERNAL=../external
cd -
qemu-img convert -O vmdk -o adapter_type=lsilogic arpl.img arpl.vmdk
#qemu-img convert -O vmdk -o adapter_type=lsilogic arpl.img -o subformat=monolithicFlat arpl.vmdk
[ -x test.sh ] && ./test.sh
rm -f *.zip
zip -9 "arpl-${VERSION}.img.zip" arpl.img
qemu-img convert -O vmdk arpl.img arpl.vmdk
zip -9 "arpl-${VERSION}.vmdk.zip" arpl.vmdk
[ -x test.sh ] && ./test.sh

12
kpatch/Makefile Normal file
View File

@@ -0,0 +1,12 @@
CFLAGS = -Wall -pedantic
LDFLAGS =
LIBS = /lib/x86_64-linux-gnu/libelf.a /lib/x86_64-linux-gnu/libz.a
all: kpatch
kpatch: main.o
cc $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
rm -f kpatch *.o

333
kpatch/main.c Normal file
View File

@@ -0,0 +1,333 @@
/*
* Copyright (c) 2020 Fabio Belavenuto <belavenuto@gmail.com>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/**
* Converted from php code by Fabio Belavenuto <belavenuto@gmail.com>
*
* A quick tool for patching the boot_params check in the DSM kernel image
* This lets you tinker with the initial ramdisk contents without disabling mount() features and modules loading
*
* The overall pattern we need to find is:
* - an CDECL function
* - does "LOCK OR [const-ptr],n" 4x
* - values of ORs are 1/2/4/8 respectively
* - [const-ptr] is always the same
*
*/
/**
* A quick tool for patching the ramdisk check in the DSM kernel image
* This lets you tinker with the initial ramdisk contents without disabling mount() features and modules loading
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <gelf.h>
const int DIR_FWD = 1;
const int DIR_RWD = -1;
/* Variables */
int fd;
int verbose = 1, read_only = 0;
Elf *elfHandle;
GElf_Ehdr elfExecHeader;
uint64_t orPos[4], fileSize, rodataAddr, rodataOffs, initTextOffs;
unsigned char *fileData;
/*****************************************************************************/
void errorMsg(char *message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
/*****************************************************************************/
void errorNum() {
char str[100] = {0};
perror(str);
exit(2);
}
/*****************************************************************************/
void elfErrno() {
int err;
if ((err = elf_errno()) != 0) {
fprintf(stderr, "%s\n", elf_errmsg(err));
exit(3);
}
}
/*****************************************************************************/
//Finding a function boundary is non-trivial really as patters can vary, we can have multiple exit points, and in CISC
// there are many things which may match e.g. "PUSH EBP". Implementing even a rough disassembler is pointless.
//However, we can certainly cheat here as we know with CDECL a non-empty function will always contain one or more
// PUSH (0x41) R12-R15 (0x54-57) sequences. Then we can search like a 1K forward for these characteristic LOCK OR.
uint64_t findPUSH_R12_R15_SEQ(uint64_t start) {
uint64_t i;
for (i = start; i < fileSize; i++) {
if (fileData[i] == 0x41 && (fileData[i+1] >= 0x54 && fileData[i+1] <= 0x57)) {
return i;
}
}
return -1;
}
/*****************************************************************************/
//[0xF0, 0x80, null, null, null, null, null, 0xXX],
uint64_t findORs(uint64_t start, uint32_t maxCheck) {
uint64_t i;
int c = 0;
uint8_t lb = 0x01;
for (i = start; i < fileSize; i++) {
if (fileData[i] == 0xF0 && fileData[i+1] == 0x80 && fileData[i+7] == lb) {
orPos[c++] = i;
i += 7;
lb <<= 1;
}
if (c == 4) {
break;
}
if (--maxCheck == 0) {
break;
}
}
return c;
}
/*****************************************************************************/
void patchBootParams() {
uint64_t addr, pos;
uint64_t newPtrOffset, ptrOffset;
int n;
//The function will reside in init code part. We don't care we may potentially search beyond as we expect it to be found
printf("Found .init.text at %lX\n", initTextOffs);
while (initTextOffs < fileSize) {
addr = findPUSH_R12_R15_SEQ(initTextOffs);
if (addr == -1)
break; //no more "functions" left
printf("\rAnalyzing f() candidate @ %lX, PUSH @ %lX", initTextOffs, addr);
//we found something looking like PUSH R12-R15, now find the ORs
n = findORs(initTextOffs, 1024);
if (n != 4) {
//We can always move forward by the function token length (obvious) but if we couldn't find any LOCK-OR tokens
// we can skip the whole look ahead distance. We CANNOT do that if we found even a single token because the next one
// might have been just after the look ahead distance
initTextOffs += 2;
if (n == 0) {
initTextOffs += 1024;
}
continue; //Continue the main search loop to find next function candidate
}
//We found LOCK(); OR ptr sequences so we can print some logs and collect ptrs (as this is quite expensive)
printf("\n[?] Found possible f() @ %lX\n", initTextOffs);
ptrOffset=0;
int ec = 0;
for (n = 0; n < 4; n++) {
//data will have the following bytes:
// [0-LOCK()] [1-OR()] [2-BYTE-PTR] [3-OFFS-b3] [4-OFFS-b2] [5-OFFS-b1] [6-OFFS-b1] [7-NUMBER]
pos = orPos[n];
//how far it "jumps"
newPtrOffset = pos + (fileData[pos+6] << 24 | fileData[pos+5] << 16 | fileData[pos+4] << 8 | fileData[pos+3]);
if (ptrOffset == 0) {
ptrOffset = newPtrOffset;
++ec;
} else if (ptrOffset == newPtrOffset) {
++ec;
}
printf("\t[+] Found LOCK-OR#$idx sequence @ %lX => %02X %02X %02X %02X %02X %02X %02X %02X [RIP+%lX]\n",
pos, fileData[pos], fileData[pos+1], fileData[pos+2], fileData[pos+3], fileData[pos+4],
fileData[pos+5], fileData[pos+6], fileData[pos+7], newPtrOffset);
}
if (ec != 4) {
printf("\t[-] LOCK-OR PTR offset mismatch - %d/4 matched\n", ec);
//If the pointer checking failed we can at least move beyond the last LOCK-OR found as we know there's no valid
// sequence of LOCK-ORs there
initTextOffs = orPos[3];
continue;
}
printf("\t[+] All %d LOCK-OR PTR offsets equal - match found!\n", ec);
break;
}
if (addr == -1) {
errorMsg("\nFailed to find matching sequences");
} else {
//Patch offsets
for (n = 0; n < 4; n++) {
//The offset will point at LOCK(), we need to change the OR (0x80 0x0d) to AND (0x80 0x25) so the two bytes after
pos = orPos[n] + 2;
printf("Patching OR to AND @ %lX\n", pos);
fileData[pos] = 0x25;
}
}
}
/*****************************************************************************/
uint32_t changeEndian(uint32_t num) {
return ((num>>24)&0xff) | // move byte 3 to byte 0
((num<<8)&0xff0000) | // move byte 1 to byte 2
((num>>8)&0xff00) | // move byte 2 to byte 1
((num<<24)&0xff000000); // move byte 0 to byte 3
}
/*****************************************************************************/
uint64_t findSeq(const char* seq, int len, uint32_t pos, int dir, uint64_t max) {
uint64_t i;
i = pos;
do {
if (strncmp((const char*)fileData+i, seq, len) == 0) {
return i;
}
i += dir;
--max;
} while(i > 0 && i < fileSize && max > 0);
return -1;
}
/*****************************************************************************/
void patchRamdiskCheck() {
uint64_t pos, errPrintAddr;
uint64_t printkPos, testPos, jzPos;
const char str[] = "3ramdisk corrupt";
printf("Patching ramdisk check\n");
for (pos = rodataOffs; pos < fileSize; pos++) {
if (strncmp(str, (const char*)(fileData + pos), 16) == 0) {
pos -= rodataOffs;
break;
}
}
errPrintAddr = rodataAddr + pos - 1;
printf("LE arg addr: %08lX\n", errPrintAddr);
printkPos = findSeq((const char*)&errPrintAddr, 4, 0, DIR_FWD, -1);
if (printkPos == -1) {
errorMsg("printk pos not found!");
}
//double check if it's a MOV reg,VAL (where reg is EAX/ECX/EDX/EBX/ESP/EBP/ESI/EDI)
printkPos -= 3;
if (strncmp((const char*)fileData+printkPos, "\x48\xc7", 2) != 0) {
printf("Expected MOV=>reg before printk error, got %02X %02X\n", fileData[printkPos], fileData[printkPos+1]);
errorMsg("");
}
if (fileData[printkPos+2] < 0xC0 || fileData[printkPos+2] > 0xC7) {
printf("Expected MOV w/reg operand [C0-C7], got %02X\n", fileData[printkPos+2]);
errorMsg("");
}
printf("Found printk MOV @ %08lX\n", printkPos);
//now we should seek a reasonable amount (say, up to 32 bytes) for a sequence of CALL x => TEST EAX,EAX => JZ
testPos = findSeq("\x85\xc0", 2, printkPos, DIR_RWD, 32);
if (testPos == -1) {
errorMsg("Failed to find TEST eax,eax\n");
}
printf("Found TEST eax,eax @ %08lX\n", testPos);
jzPos = testPos + 2;
if (fileData[jzPos] != 0x74) {
errorMsg("Failed to find JZ\n");
}
printf("OK - patching %02X%02X (JZ) to %02X%02X (JMP) @ %08lX\n",
fileData[jzPos], fileData[jzPos+1], 0xEB, fileData[jzPos+1], jzPos);
fileData[jzPos] = 0xEB;
}
/*****************************************************************************/
int main(int argc, char *argv[]) {
struct stat fileInf;
Elf_Scn *section;
GElf_Shdr sectionHeader;
char *sectionName;
if (argc != 3) {
errorMsg("Use: kpatch <vmlinux> <output>");
}
if (elf_version(EV_CURRENT) == EV_NONE)
elfErrno();
if ((fd = open(argv[1], O_RDONLY)) == -1)
errorNum();
if ((elfHandle = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
elfErrno();
if (gelf_getehdr(elfHandle, &elfExecHeader) == NULL)
elfErrno();
switch(elf_kind(elfHandle)) {
case ELF_K_NUM:
case ELF_K_NONE:
errorMsg("file type unknown");
break;
case ELF_K_COFF:
errorMsg("COFF binaries not supported");
break;
case ELF_K_AR:
errorMsg("AR archives not supported");
break;
case ELF_K_ELF:
break;
}
section = NULL;
while ((section = elf_nextscn(elfHandle, section)) != NULL) {
if (gelf_getshdr(section, &sectionHeader) != &sectionHeader)
elfErrno();
if ((sectionName = elf_strptr(elfHandle, elfExecHeader.e_shstrndx, sectionHeader.sh_name)) == NULL)
elfErrno();
if (strcmp(sectionName, ".init.text") == 0) {
initTextOffs = sectionHeader.sh_offset;
} else if (strcmp(sectionName, ".rodata") == 0) {
rodataAddr = sectionHeader.sh_addr & 0xFFFFFFFF;
rodataOffs = sectionHeader.sh_offset;
}
}
elfErrno(); /* If there isn't elf_errno set, nothing will happend. */
elf_end(elfHandle);
if (fstat(fd, &fileInf) == -1)
errorNum();
fileSize = fileInf.st_size;
fileData = malloc(fileSize);
if (fileSize != read(fd, fileData, fileSize)) {
errorNum();
}
close(fd);
patchBootParams();
patchRamdiskCheck();
if ((fd = open(argv[2], O_WRONLY | O_CREAT, 0644)) == -1) {
errorNum();
}
if (fileSize != write(fd, fileData, fileSize)) {
errorNum();
}
close(fd);
printf("\n");
return 0;
}