diff --git a/package/system/rdloader/Makefile b/package/system/rdloader/Makefile new file mode 100644 index 000000000..f042dc3c2 --- /dev/null +++ b/package/system/rdloader/Makefile @@ -0,0 +1,54 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=rdloader +PKG_VERSION:=1.0.1 +PKG_RELEASE:=1 + +PKG_LICENSE:=GPLv3 +PKG_BUILD_DEPENDS:=util-linux e2fsprogs + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +define Package/rdloader + SECTION:=base + CATEGORY:=Base system + TITLE:=kmod loader for ramdisk enviroment + DEPENDS:=@TARGET_ramips +e2fsprogs +libblkid +endef + +define Package/rdloader/description + Lightweight kmod loader for ramdisk enviroment, + support uuid-based rootfs mount +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +CMAKE_OPTIONS += -DCMAKE_BUILD_TYPE=Release + +define Build/InstallDev + rm -fR $(STAGING_DIR)/rdloader + mkdir -p $(STAGING_DIR)/rdloader/{bin,lib,etc} + + $(CP) $(PKG_BUILD_DIR)/rdloader $(STAGING_DIR)/rdloader/bin/ + $(CP) $(STAGING_DIR_ROOT)/usr/sbin/e2fsck $(STAGING_DIR)/rdloader/bin/ + $(CP) $(STAGING_DIR_ROOT)/etc/e2fsck.conf $(STAGING_DIR)/rdloader/etc/ + + ( \ + export \ + READELF=$(TARGET_CROSS)readelf \ + OBJCOPY=$(TARGET_CROSS)objcopy \ + XARGS="$(XARGS)"; \ + find $(STAGING_DIR)/rdloader/bin/ -type f -a -exec \ + $(SCRIPT_DIR)/gen-rddependencies.sh {} \; ; \ + ) | while read FILE; do \ + cp $(STAGING_DIR_ROOT)/lib/$$$$FILE $(STAGING_DIR)/rdloader/lib/ || \ + cp $(STAGING_DIR_ROOT)/usr/lib/$$$$FILE $(STAGING_DIR)/rdloader/lib/ \ + ; \ + done; +endef + +$(eval $(call BuildPackage,rdloader)) diff --git a/package/system/rdloader/src/CMakeLists.txt b/package/system/rdloader/src/CMakeLists.txt new file mode 100644 index 000000000..90767725e --- /dev/null +++ b/package/system/rdloader/src/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) +set(CMAKE_C_STANDARD 99) +project(rdloader C) + +add_executable(rdloader main.c insmod.c insmod.h mknod.c mknod.h mkdev_node.c mkdev_node.h blkid2.c blkid2.h cmdline.c cmdline.h switch_root.c switch_root.h) + +target_link_libraries(${PROJECT_NAME} blkid) + +install(TARGETS rdloader RUNTIME DESTINATION /usr/sbin) diff --git a/package/system/rdloader/src/blkid2.c b/package/system/rdloader/src/blkid2.c new file mode 100644 index 000000000..91b79d6ab --- /dev/null +++ b/package/system/rdloader/src/blkid2.c @@ -0,0 +1,40 @@ +// +// Created by juno on 2022/1/11. +// + +#include +#include +#include +#include +#include +#include "blkid2.h" + +int get_blkid(const char *blkdev, char **uuid) +{ + blkid_probe pr; + int ret; + size_t len; + const char *data; + void *out; + + pr = blkid_new_probe_from_filename(blkdev); + if (!pr) + { + fprintf(stderr, "Failed open %s:%s\n", blkdev, strerror(errno)); + return -1; + } + + blkid_do_probe(pr); + ret = blkid_probe_lookup_value(pr, "UUID", &data, &len); + + if (ret == 0) + { + out = calloc(1, len + 1); + memcpy(out, data, len); + *uuid = out; + } + + blkid_free_probe(pr); + + return ret; +} diff --git a/package/system/rdloader/src/blkid2.h b/package/system/rdloader/src/blkid2.h new file mode 100644 index 000000000..79e16366e --- /dev/null +++ b/package/system/rdloader/src/blkid2.h @@ -0,0 +1,10 @@ +// +// Created by juno on 2022/1/11. +// + +#ifndef INIT_BLKID2_H +#define INIT_BLKID2_H + +int get_blkid(const char *blkdev, char **uuid); + +#endif //INIT_BLKID2_H diff --git a/package/system/rdloader/src/cmdline.c b/package/system/rdloader/src/cmdline.c new file mode 100644 index 000000000..7d1a1d57d --- /dev/null +++ b/package/system/rdloader/src/cmdline.c @@ -0,0 +1,209 @@ +// +// Created by juno on 2022/1/11. +// + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "cmdline.h" + +static void insert_fstype_tail(struct fstype **head, struct fstype *fs) +{ + struct fstype *curr = *head; + struct fstype *next = NULL; + + if (!curr) + { + *head = fs; + return; + } + + do + { + next = curr->next; + if (!next) + { + curr->next = fs; + break; + } + curr = next; + } while (curr); +} + +static int parse_root(char *args, char **ret) +{ + char *root = NULL; + + if (!args) + return -1; + + if (strstr(args, "PARTUUID=") != NULL) + { + root = strtok(args, "="); + root = strtok(NULL, "="); + root = strtok(NULL, "="); + if (!root) + return -1; + + asprintf(ret, "/dev/disk/by-partuuid/%s", root); + } + else if (strstr(args, "UUID=") != NULL) + { + + root = strtok(args, "="); + root = strtok(NULL, "="); + root = strtok(NULL, "="); + + if (!root) + return -1; + + asprintf(ret, "/dev/disk/by-uuid/%s", root); + } + else if (strstr(args, "/dev/")) + { + *ret = strdup(args); + } + else + { + asprintf(ret, "/dev/%s", args); + } + + return 0; +} + +struct fstype *parse_rootfs(char **fstype_list) +{ + struct fstype *ret = NULL; + char *list = *fstype_list; + struct fstype *default_fs = NULL; + struct fstype *fs = NULL; + + if (list) + { + list = strtok(list, "="); + + while ((list = strtok(NULL, ","))) + { + fs = calloc(1, sizeof(struct fstype)); + + if (!fs) + return NULL; + + fs->name = strdup(list); + insert_fstype_tail(&ret, fs); + } + } + + default_fs = calloc(1, sizeof(struct fstype)); + default_fs->name = strdup("ext4"); + insert_fstype_tail(&ret, default_fs); + + return ret; +} + +int parse_cmdline(struct bootargs_t **ret) +{ + FILE *fp; + char *cmdline = NULL; + struct fstype *fs = NULL; + char str[1024] = {0}; + char *root = NULL; + char *rootfs = NULL; + struct bootargs_t *bootargs = NULL; + + fp = fopen("/proc/cmdline", "r"); + + if (!fp) + { + fprintf(stderr, "get cmdline failed:%s\n", strerror(errno)); + return -1; + } + + if (fgets(str, sizeof(str) - 1, fp) == NULL) + { + fprintf(stderr, "cmdline empty\n"); + fclose(fp); + return -1; + } + + fclose(fp); + + cmdline = strtok(str, " "); + + do + { + if (!cmdline) + continue; + + if (strstr(cmdline, "root=")) + root = cmdline; + if (strstr(cmdline, "rootfstype=")) + rootfs = cmdline; + + } while ((cmdline = strtok(NULL, " ")) != NULL); + + if (parse_root(root, &root) < 0) + { + fprintf(stderr, "root args error\n"); + return -1; + } + + if ((fs = parse_rootfs(&rootfs)) == NULL) + { + fprintf(stderr, "fstype error\n"); + return -1; + } + + bootargs = calloc(1, sizeof(struct bootargs_t)); + + if (!bootargs) + { + fprintf(stderr, "alloc bootargs failed\n"); + free(fs); + free(root); + return -1; + } + + bootargs->root = root; + bootargs->fstype = fs; + + *ret = bootargs; + + return 0; +} + +void free_bootargs(struct bootargs_t **args) +{ + struct bootargs_t *bootargs = *args; + struct fstype *curr = NULL; + struct fstype *next = NULL; + + if (!bootargs) + return; + + if (bootargs->root) + free(bootargs->root); + + curr = bootargs->fstype; + + do + { + if (curr) + { + if (curr->name) + free(curr->name); + + next = curr->next; + free(curr); + } + + curr = next; + + } while (curr); + + free(bootargs); +} diff --git a/package/system/rdloader/src/cmdline.h b/package/system/rdloader/src/cmdline.h new file mode 100644 index 000000000..9c8e9abaf --- /dev/null +++ b/package/system/rdloader/src/cmdline.h @@ -0,0 +1,24 @@ +// +// Created by juno on 2022/1/11. +// + +#ifndef INIT_CMDLINE_H +#define INIT_CMDLINE_H + +struct fstype +{ + char *name; + struct fstype *next; +}; + +struct bootargs_t +{ + char *root; + struct fstype *fstype; +}; + +int parse_cmdline(struct bootargs_t **ret); + +void free_bootargs(struct bootargs_t **args); + +#endif //INIT_CMDLINE_H diff --git a/package/system/rdloader/src/insmod.c b/package/system/rdloader/src/insmod.c new file mode 100644 index 000000000..4cffbd054 --- /dev/null +++ b/package/system/rdloader/src/insmod.c @@ -0,0 +1,161 @@ +// +// Created by juno on 2022/1/7. +// +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "insmod.h" + +#define init_module(module, len, opts) syscall(__NR_init_module, module, len, opts) + +#if __BYTE_ORDER == __BIG_ENDIAN +#define SWAP_BE32(x) (x) +#define SWAP_BE64(x) (x) +#else +#define SWAP_BE32(x) bswap_32(x) +#define SWAP_BE64(x) bswap_64(x) +#endif + +static char *parse_cmdline_module_options(const char **argv, int quote_space) +{ + char *options; + int optlen; + + options = calloc(1, sizeof(char)); + optlen = 0; + + while (*++argv) + { + const char *fmt; + const char *var; + const char *val; + + var = *argv; + + options = realloc(options, optlen + 2 + strlen(var) + 2); + + fmt = "%.*s%s "; + + var = strchrnul(var, '='); + + if (quote_space) + { + if (*val) + { + val++; + if (strchr(val, ' ')) + fmt = "%.*s\"%s\" "; + } + } + + optlen += sprintf(options + optlen, fmt, (int)(val - var), var, val); + } + + return options; +} + +static void *mmap_read(int fd, size_t size) +{ + return mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); +} + +static void *try_to_map_module(const char *filename, size_t *image_size_p) +{ + void *image = NULL; + struct stat st; + int fd; + + fd = open(filename, O_RDONLY); + + if (fd < 0) + { + fprintf(stderr, "open %s failed:%s\n", filename, strerror(errno)); + return NULL; + } + + fstat(fd, &st); + + if (st.st_size <= *image_size_p) + { + size_t image_size = st.st_size; + image = mmap_read(fd, image_size); + + if (image == MAP_FAILED) + { + image = NULL; + } + else if (*(u_int32_t *)image != SWAP_BE32(0x7f454C46)) + { + munmap(image, image_size); + } + else + { + *image_size_p = image_size; + } + } + + close(fd); + return image; +} + +static void *malloc_open_zipped_read_close(const char *filename, size_t *image_size_p) +{ + return NULL; +} + +int do_insmod(const char *modname, const char **argv) +{ + int mmaped = 0; + size_t image_size = INT_MAX - 4095; + void *image = NULL; + int ret; + + if (!modname) + { + return -1; + } + + char *options = *argv == NULL ? "" : parse_cmdline_module_options(argv, 0); + + image = try_to_map_module(modname, &image_size); + + if (image) + { + mmaped = 1; + } + else + { + errno = ENOMEM; + image = malloc_open_zipped_read_close(modname, &image_size); + if (!image) + return -ENOMEM; + } + + errno = 0; + + init_module(image, image_size, options); + + ret = errno; + + if (mmaped) + munmap(image, image_size); + else + free(image); + + if (ret) + { + fprintf(stderr, "insmod failed:%s\n", strerror(ret)); + } + + return ret; +} diff --git a/package/system/rdloader/src/insmod.h b/package/system/rdloader/src/insmod.h new file mode 100644 index 000000000..f938ef16f --- /dev/null +++ b/package/system/rdloader/src/insmod.h @@ -0,0 +1,10 @@ +// +// Created by juno on 2022/1/7. +// + +#ifndef INIT_INSMOD_H +#define INIT_INSMOD_H + +int do_insmod(const char *modname, const char **argv); + +#endif //INIT_INSMOD_H diff --git a/package/system/rdloader/src/main.c b/package/system/rdloader/src/main.c new file mode 100644 index 000000000..b975d67bd --- /dev/null +++ b/package/system/rdloader/src/main.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "insmod.h" +#include "mknod.h" +#include "mkdev_node.h" +#include "cmdline.h" +#include "switch_root.h" + +static void hang(void); + +static int mount_fs(void) +{ + int ret; + + unsigned long flags = MS_NOEXEC | MS_NOSUID | MS_RELATIME | MS_NODEV; + + ret = mount(NULL, "/proc", "proc", flags, NULL); + + if (ret < 0) + goto err; + + ret = mount(NULL, "/sys", "sysfs", flags, NULL); + + if (ret < 0) + goto err; + + ret = mount(NULL, "/dev", "tmpfs", MS_RELATIME, NULL); + + if (ret < 0) + goto err; + + return 0; +err: + ret = errno; + return ret; +} + +struct dev_node_t +{ + const char *mode; + const char *name; + char type; + uint8_t major; + uint8_t minor; +} dev_nodes[] = { + { + .mode = "0666", + .name = "/dev/tty", + .type = 'c', + .major = 5, + .minor = 0, + }, + { + .mode = "0622", + .name = "/dev/console", + .type = 'c', + .major = 5, + .minor = 1, + }, + { + .mode = "0666", + .name = "/dev/null", + .type = 'c', + .major = 1, + .minor = 3, + }, + { + .mode = "0666", + .name = "/dev/zero", + .type = 'c', + .major = 1, + .minor = 5, + }, +}; + +static int make_node(void) +{ + for (int i = 0; i < sizeof(dev_nodes) / sizeof((dev_nodes)[0]); i++) + { + if (do_mknod(dev_nodes[i].mode, dev_nodes[i].name, dev_nodes[i].type, dev_nodes[i].major, dev_nodes[i].minor) < 0) + { + if (errno == EEXIST) + continue; + + fprintf(stderr, "make %s failed:%s\n", dev_nodes[i].name, strerror(errno)); + return -1; + } + } + return 0; +} + +static int insert_kernel_module(const char *path, const char **argv) +{ + int ret; + FILE *fp = NULL; + char module_name[1024] = {0}; + + if (access(path, F_OK) != 0) + { + fprintf(stderr, "%s not found\n", path); + return -1; + } + + fp = fopen(path, "r"); + if (!fp) + { + fprintf(stderr, "open %s failed:%s\n", path, strerror(errno)); + return -1; + } + + while ((fgets(module_name, sizeof(module_name) - 1, fp)) != NULL) + { + for (int i = 0; i < sizeof(module_name); i++) + { + if (module_name[i] == '\n') + { + module_name[i] = '\0'; + break; + } + } + + ret = do_insmod(module_name, argv); + + if (ret) + { + break; + } + } + + fclose(fp); + + return ret; +} + +static void e2fsck(const char *dev_path) +{ + int pid; + pid = fork(); + if (pid < 0) + { + printf("fork failed"); + hang(); + } + if (pid == 0) + { + execl("/bin/e2fsck", "-f", "-y", dev_path); + printf("execl failed"); + hang(); + } + else + { + waitpid(pid); + } +} + +static int mount_rootfs(struct bootargs_t *bootargs) +{ + int ret = 0; + char realroot[PATH_MAX]; + struct fstype *fstype = NULL; + + // OpenWrt dont have /dev/disk/by-* yet, use realpath as workaround. + if (realpath(bootargs->root, realroot) == NULL) + return -1; + + fstype = bootargs->fstype; + + for (struct fstype *next = fstype->next; fstype; next = fstype->next, fstype = next) + { + if (strcmp(fstype->name, "ext4") == 0) + { + e2fsck(realroot); + } + ret = mount(realroot, "/root", fstype->name, MS_RELATIME, NULL); + if (ret == 0) + break; + } + + return ret; +} + +static void hang() +{ + exit(-1); + while (1) + { + } +} + +int main(int argc, const char *argv[]) +{ + int ret; + struct bootargs_t *bootargs = NULL; + + if (getpid() != 1) + { + fprintf(stderr, "must run PID 1\n"); + hang(); + } + + if ((ret = mount_fs()) < 0) + { + fprintf(stderr, "mount ramdisk fs failed:%s\n", strerror(ret)); + hang(); + } + + if (make_node() < 0) + { + fprintf(stderr, "make ramdisk dev node failed\n"); + hang(); + } + + if ((ret = parse_cmdline(&bootargs)) < 0) + { + fprintf(stderr, "cmdline format error\n"); + hang(); + } + + if (insert_kernel_module("/etc/rdloader_list", argv + 1) != 0) + { + fprintf(stderr, "failed to load kmods\n"); + hang(); + } + + printf("Waiting for root: %s\n", bootargs->root); + + do + { + ret = mkdev_node(); + + if (ret) + continue; + + ret = mount_rootfs(bootargs); + } while (ret != 0); + + free_bootargs(&bootargs); + + umount("/dev"); + umount("/proc"); + umount("/sys"); + + switch_root("/root", "/etc/preinit", argv++); + + return 0; +} diff --git a/package/system/rdloader/src/mkdev_node.c b/package/system/rdloader/src/mkdev_node.c new file mode 100644 index 000000000..9207116db --- /dev/null +++ b/package/system/rdloader/src/mkdev_node.c @@ -0,0 +1,272 @@ +// +// Created by juno on 2022/1/10. +// +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mkdev_node.h" +#include "mknod.h" +#include "blkid2.h" + +static int parse_devno(const char *devname, int *maj, int *min) +{ + FILE *fp; + char *major_s, *minor_s; + int major, minor; + char dev_path[1024] = {0}; + char dev_no[32] = {0}; + + snprintf(dev_path, sizeof(dev_path) - 1, "/sys/class/block/%s/dev", devname); + + fp = fopen(dev_path, "r"); + + if (fp == NULL) + return -1; + + if (!fgets(dev_no, 31, fp)) + return -1; + + fclose(fp); + major_s = strtok(dev_no, ":"); + minor_s = strtok(NULL, ":"); + + major = (int)strtoul(major_s, NULL, 0); + + minor = (int)strtoul(minor_s, NULL, 0); + + *maj = major; + *min = minor; + + return 0; +} + +static int mkpartion_node(const char *devname) +{ + int ret = 0; + dev_t part_devno; + dev_t disk_devno; + char *disk_name; + blkid_probe disk_pr; + blkid_partlist ls; + blkid_partition par; + const char *uuid; + char *dev_path = NULL; + + asprintf(&dev_path, "/dev/%s", devname); + + if (dev_path == NULL) + return -1; + + blkid_probe part_pr = blkid_new_probe_from_filename(dev_path); + + if (!part_pr) + { + ret = -1; + goto out1; + } + + part_devno = blkid_probe_get_devno(part_pr); + + if (!part_devno) + { + ret = -1; + goto out2; + } + + disk_devno = blkid_probe_get_wholedisk_devno(part_pr); + + if (!disk_devno) + { + ret = -1; + goto out2; + } + + disk_name = blkid_devno_to_devname(disk_devno); + + if (!disk_name) + { + ret = -1; + goto out2; + } + + disk_pr = blkid_new_probe_from_filename(disk_name); + + if (!disk_pr) + { + ret = -1; + goto out3; + } + + ls = blkid_probe_get_partitions(disk_pr); + + if (!ls) + { + ret = -1; + goto out4; + } + + par = blkid_partlist_devno_to_partition(ls, part_devno); + + uuid = blkid_partition_get_uuid(par); + + if (uuid) + { + char long_path[1024] = {0}; + snprintf(long_path, sizeof(long_path) - 1, "/dev/disk/by-partuuid/%s", uuid); + + if (access(long_path, F_OK) == 0) + goto out4; + + if (access(dev_path, F_OK) != 0) + goto out4; + + symlink(dev_path, long_path); + } + else + { + ret = -1; + } + +out4: + blkid_free_probe(disk_pr); +out3: + free(disk_name); +out2: + blkid_free_probe(part_pr); +out1: + free(dev_path); + return ret; +} + +static int dev_by_partuuit(void) +{ + DIR *dir; + DIR *disk_dir; + struct dirent *filename; + struct dirent *partname; + char *disk = NULL; + + mkdir("/dev/disk/by-partuuid", 0755); + + dir = opendir("/sys/block"); + + if (!dir) + { + return -1; + } + + while ((filename = readdir(dir))) + { + if (filename->d_type != DT_LNK) + continue; + + asprintf(&disk, "/sys/block/%s", filename->d_name); + + disk_dir = opendir(disk); + + if (disk) + free(disk); + + if (disk_dir) + { + while ((partname = readdir(disk_dir))) + { + char *dev = NULL; + asprintf(&dev, "/sys/block/%s/%s/dev", filename->d_name, partname->d_name); + + if (access(dev, F_OK) == 0) + { + mkpartion_node(partname->d_name); + } + + if (dev) + free(dev); + } + } + + closedir(disk_dir); + } + + closedir(dir); + + return 0; +} + +int mkdev_node(void) +{ + int ret; + struct dirent *filename; + DIR *dir = NULL; + char dev_path[1024]; + char uuid_node[1024]; + + dir = opendir("/sys/class/block"); + + ret = mkdir("/dev/disk", 0755); + + if (ret < 0 && errno != EEXIST) + { + fprintf(stderr, "create /dev/disk directory failed:%s\n", strerror(errno)); + return -1; + } + + ret = mkdir("/dev/disk/by-uuid", 0755); + + if (ret < 0 && errno != EEXIST) + { + fprintf(stderr, "create /dev/disk/by-uuid directory failed:%s\n", strerror(errno)); + return -1; + } + + while ((filename = readdir(dir))) + { + if (filename->d_type == DT_LNK) + { + int major, minor; + char *uuid = NULL; + + memset(dev_path, 0, sizeof(dev_path)); + + snprintf(dev_path, sizeof(dev_path) - 1, "/dev/%s", filename->d_name); + + if (access(dev_path, F_OK) == 0) + continue; + + if (parse_devno(filename->d_name, &major, &minor) < 0) + continue; + + ret = do_mknod("0755", dev_path, 'b', major, minor); + + if (ret < 0) + return ret; + + ret = get_blkid(dev_path, &uuid); + + if (ret < 0) + continue; + + memset(uuid_node, 0, sizeof(uuid_node)); + snprintf(uuid_node, sizeof(uuid_node) - 1, "/dev/disk/by-uuid/%s", uuid); + + symlink(dev_path, uuid_node); + if (uuid) + { + free(uuid); + uuid = NULL; + } + } + } + + closedir(dir); + + dev_by_partuuit(); + + return 0; +} \ No newline at end of file diff --git a/package/system/rdloader/src/mkdev_node.h b/package/system/rdloader/src/mkdev_node.h new file mode 100644 index 000000000..998b77be5 --- /dev/null +++ b/package/system/rdloader/src/mkdev_node.h @@ -0,0 +1,10 @@ +// +// Created by juno on 2022/1/10. +// + +#ifndef INIT_MKDEV_NODE_H +#define INIT_MKDEV_NODE_H + +int mkdev_node(void); + +#endif //INIT_MKDEV_NODE_H diff --git a/package/system/rdloader/src/mknod.c b/package/system/rdloader/src/mknod.c new file mode 100644 index 000000000..a1a257368 --- /dev/null +++ b/package/system/rdloader/src/mknod.c @@ -0,0 +1,217 @@ +// +// Created by juno on 2022/1/7. +// + +#include +#include +#include +#include +#include +#include +#include +#include "mknod.h" + +static const mode_t modes_cubp[] = { + S_IFIFO, + S_IFCHR, + S_IFBLK, + S_IFLNK, +}; + +#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) + +static mode_t parse_mode(const char *s) +{ + static const mode_t who_mask[] = { + S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */ + S_ISUID | S_IRWXU, /* u */ + S_ISGID | S_IRWXG, /* g */ + S_IRWXO /* o */ + }; + static const mode_t perm_mask[] = { + S_IRUSR | S_IRGRP | S_IROTH, /* r */ + S_IWUSR | S_IWGRP | S_IWOTH, /* w */ + S_IXUSR | S_IXGRP | S_IXOTH, /* x */ + S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */ + S_ISUID | S_ISGID, /* s */ + S_ISVTX /* t */ + }; + static const char who_chars[] ALIGN1 = "augo"; + static const char perm_chars[] ALIGN1 = "rwxXst"; + + const char *p; + mode_t wholist; + mode_t permlist; + mode_t new_mode; + char op; + + if ((unsigned char)(*s - '0') < 8) + { + unsigned long tmp; + char *e; + + tmp = strtoul(s, &e, 8); + if (*e || (tmp > 07777U)) + { /* Check range and trailing chars. */ + return -1; + } + return tmp; + } + + new_mode = 0666; + + /* Note: we allow empty clauses, and hence empty modes. + * We treat an empty mode as no change to perms. */ + + while (*s) + { /* Process clauses. */ + if (*s == ',') + { /* We allow empty clauses. */ + ++s; + continue; + } + + /* Get a wholist. */ + wholist = 0; + WHO_LIST: + p = who_chars; + do + { + if (*p == *s) + { + wholist |= who_mask[(int)(p - who_chars)]; + if (!*++s) + { + return -1; + } + goto WHO_LIST; + } + } while (*++p); + + do + { /* Process action list. */ + if ((*s != '+') && (*s != '-')) + { + if (*s != '=') + { + return -1; + } + /* Since op is '=', clear all bits corresponding to the + * wholist, or all file bits if wholist is empty. */ + permlist = ~FILEMODEBITS; + if (wholist) + { + permlist = ~wholist; + } + new_mode &= permlist; + } + op = *s++; + + /* Check for permcopy. */ + p = who_chars + 1; /* Skip 'a' entry. */ + do + { + if (*p == *s) + { + int i = 0; + permlist = who_mask[(int)(p - who_chars)] & (S_IRWXU | S_IRWXG | S_IRWXO) & new_mode; + do + { + if (permlist & perm_mask[i]) + { + permlist |= perm_mask[i]; + } + } while (++i < 3); + ++s; + goto GOT_ACTION; + } + } while (*++p); + + /* It was not a permcopy, so get a permlist. */ + permlist = 0; + PERM_LIST: + p = perm_chars; + do + { + if (*p == *s) + { + if ((*p != 'X') || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))) + { + permlist |= perm_mask[(int)(p - perm_chars)]; + } + if (!*++s) + { + break; + } + goto PERM_LIST; + } + } while (*++p); + GOT_ACTION: + if (permlist) + { /* The permlist was nonempty. */ + mode_t tmp = wholist; + if (!wholist) + { + mode_t u_mask = umask(0); + umask(u_mask); + tmp = ~u_mask; + } + permlist &= tmp; + if (op == '-') + { + new_mode &= ~permlist; + } + else + { + new_mode |= permlist; + } + } + } while (*s && (*s != ',')); + } + + return new_mode; +} + +static mode_t char_to_mode(char type) +{ + switch (type) + { + case 'f': + return modes_cubp[0]; + case 'c': + return modes_cubp[1]; + case 'b': + return modes_cubp[2]; + case 'l': + return modes_cubp[3]; + } + + return -1; +} + +int do_mknod(const char *mod, const char *name, char type, int maj, int min) +{ + int ret; + mode_t mode; + dev_t dev; + + mode = parse_mode(mod); + if (mode != (mode_t)-1) + umask(0); + else + { + fprintf(stderr, "mode failed\n"); + return -1; + } + + dev = makedev(maj, min); + + mode |= char_to_mode(type); + + ret = mknod(name, mode, dev); + + if (ret < 0) + ret = errno; + + return ret; +} diff --git a/package/system/rdloader/src/mknod.h b/package/system/rdloader/src/mknod.h new file mode 100644 index 000000000..058095942 --- /dev/null +++ b/package/system/rdloader/src/mknod.h @@ -0,0 +1,11 @@ +// +// Created by juno on 2022/1/7. +// + +#ifndef INIT_MKNOD_H +#define INIT_MKNOD_H + +#define ALIGN1 __attribute__((aligned(1))) +int do_mknod(const char *mod, const char *name, char type, int maj, int min); + +#endif //INIT_MKNOD_H diff --git a/package/system/rdloader/src/switch_root.c b/package/system/rdloader/src/switch_root.c new file mode 100644 index 000000000..45e781cb9 --- /dev/null +++ b/package/system/rdloader/src/switch_root.c @@ -0,0 +1,108 @@ +// +// Created by juno on 2022/1/12. +// + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "switch_root.h" + +static char *last_char_is(const char *s, int c) +{ + if (!s[0]) + return NULL; + while (s[1]) + s++; + + return (*s == (char)c) ? (char *)s : NULL; +} + +static char *concat_path_file(const char *path, const char *filename) +{ + char *lc; + char *ret; + + if (!path) + path = ""; + + lc = last_char_is(path, '/'); + + while (*filename == '/') + filename++; + + asprintf(&ret, "%s/%s/%s", path, (lc == NULL ? "/" : ""), filename); + + return ret; +} + +static void delete_contents(const char *directory, dev_t rootdev) +{ + DIR *dir; + struct dirent *d; + struct stat st; + + if (lstat(directory, &st) || st.st_dev != rootdev) + return; + + if (S_ISDIR(st.st_mode)) + { + dir = opendir(directory); + if (dir) + { + while ((d = readdir(dir))) + { + char *newdir = d->d_name; + + if (DOT_OR_DOTDOT(newdir)) + continue; + + newdir = concat_path_file(directory, newdir); + delete_contents(newdir, rootdev); + free(newdir); + } + closedir(dir); + rmdir(directory); + } + else + { + unlink(directory); + } + } +} + +void switch_root(const char *new_root, const char *prog, char *const argv[]) +{ + struct stat st; + dev_t root_dev; + + chdir(new_root); + stat("/", &st); + + root_dev = st.st_dev; + + stat(".", &st); + + if (st.st_dev == root_dev) + { + fprintf(stderr, "%s must be a mountpoint\n", new_root); + return; + } + + delete_contents("/", root_dev); + if (mount(".", "/", NULL, MS_MOVE, NULL)) + { + fprintf(stderr, "failed to moving root\n"); + return; + } + + chroot("."); + + execv(prog, argv); +} diff --git a/package/system/rdloader/src/switch_root.h b/package/system/rdloader/src/switch_root.h new file mode 100644 index 000000000..d88757a2d --- /dev/null +++ b/package/system/rdloader/src/switch_root.h @@ -0,0 +1,12 @@ +// +// Created by juno on 2022/1/12. +// + +#ifndef INIT_SWITCH_ROOT_H +#define INIT_SWITCH_ROOT_H + +#define DOT_OR_DOTDOT(s) ((s)[0] == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2]))) +void switch_root(const char *newroot, const char *prog, char *const argv[]); + + +#endif //INIT_SWITCH_ROOT_H diff --git a/scripts/gen-rddependencies.sh b/scripts/gen-rddependencies.sh new file mode 100755 index 000000000..509d6a4fa --- /dev/null +++ b/scripts/gen-rddependencies.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +TARGETS=$* +READELF="${READELF:-readelf}" +XARGS="${XARGS:-xargs -r}" + +find $TARGETS -type f -a -exec file {} \; | \ + sed -n -e 's/^\(.*\):.*ELF.*\(executable\|shared object\).*,.*/\1/p' | \ + $XARGS -n1 $READELF -l | grep 'Requesting' | cut -d':' -f2 | tr -d ' ]' | \ + $XARGS basename + +cd `dirname ${0}` +./gen-dependencies.sh ${TARGETS} diff --git a/target/linux/ramips/dts/mt7621_hatlab_gateboard-one.dts b/target/linux/ramips/dts/mt7621_hatlab_gateboard-one.dts new file mode 100644 index 000000000..3fa75d9f8 --- /dev/null +++ b/target/linux/ramips/dts/mt7621_hatlab_gateboard-one.dts @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7621.dtsi" + +#include +#include +#include + +/ { + compatible = "hatlab,gateboard-one", "mediatek,mt7621-soc"; + model = "HATLab GateBoard-One"; + + aliases { + led-boot = &led_sys; + led-failsafe = &led_sys; + led-running = &led_sys; + led-upgrade = &led_sys; + }; + + chosen { + bootargs = "console=ttyS0,115200"; + }; + + leds { + compatible = "gpio-leds"; + + led_sys: sys { + label = "green:sys"; + gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + }; + + usb { + label = "blue:usb"; + gpios = <&gpio 16 GPIO_ACTIVE_HIGH>; + trigger-sources = <&xhci_ehci_port1>; + linux,default-trigger = "usbport"; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + linux,code = ; + }; + }; + + gpio_export { + compatible = "gpio-export"; + #size-cells = <0>; + + power_peripheral { + gpio-export,name = "power_peripheral"; + gpio-export,output = <0>; + gpios = <&gpio 18 GPIO_ACTIVE_LOW>; + }; + }; + + cpu_fan: cpu_fan { + compatible = "gpio-fan"; + gpios = <&gpio 13 GPIO_ACTIVE_HIGH + &gpio 14 GPIO_ACTIVE_HIGH>; + gpio-fan,speed-map = < 0 0 + 2000 1 + 4000 2 + 6000 3>; + #cooling-cells = <2>; + }; + + thermal-zones { + cpu-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + + thermal-sensors = <&cpu_sensor>; + + trips { + cpu_warm: cpu-warm { + temperature = <26000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_hot: cpu-hot { + temperature = <37000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_alert: cpu-alert { + temperature = <75000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpu_crit: cpu-crit { + temperature = <80000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_warm>; + cooling-device = <&cpu_fan THERMAL_NO_LIMIT 2>; + }; + + map1 { + trip = <&cpu_hot>; + cooling-device = <&cpu_fan 3 THERMAL_NO_LIMIT>; + }; + }; + }; + }; + + i2c_sfp: i2c-sfp { + compatible = "i2c-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + sda-gpios = <&expender0 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&expender0 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + }; + + sfp: sfp { + compatible = "sff,sfp"; + i2c-bus = <&i2c_sfp>; + maximum-power-milliwatt = <5000>; + mod-def0-gpios = <&expender0 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; +}; + +&spi0 { + status = "okay"; + + spi-nor@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + + partitions@0 { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x0 0x40000>; + read-only; + }; + + partition@40000 { + label = "u-boot-env"; + reg = <0x40000 0x10000>; + }; + + factory: partition@50000 { + label = "factory"; + reg = <0x50000 0x10000>; + }; + }; + }; +}; + +&i2c { + status = "okay"; + + expender0: pcf8574a@38 { + compatible = "nxp,pcf8574a"; + reg = <0x38>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-parent = <&gpio>; + interrupts = <15 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + cpu_sensor: lm75@4f { + compatible = "national,lm75"; + reg = <0x4f>; + #thermal-sensor-cells = <0>; + }; + + rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; +}; + +&mdio { + ephy7: ethernet-phy@7 { + reg = <7>; + eee-broken-1000t; + }; +}; + +&gmac0 { + label = "dsa"; + mtd-mac-address = <&factory 0x0>; +}; + +&gmac1 { + status = "okay"; + label = "eth5"; + phy-handle = <&ephy7>; + phy-mode = "rgmii-rxid"; + mtd-mac-address = <&factory 0x0>; + mtd-mac-address-increment = <6>; +}; + +&switch0 { + ports { + port@0 { + status = "okay"; + label = "eth0"; + mtd-mac-address = <&factory 0x0>; + mtd-mac-address-increment = <1>; + }; + + port@1 { + status = "okay"; + label = "eth1"; + mtd-mac-address = <&factory 0x0>; + mtd-mac-address-increment = <2>; + }; + + port@2 { + status = "okay"; + label = "eth2"; + mtd-mac-address = <&factory 0x0>; + mtd-mac-address-increment = <3>; + }; + + port@3 { + status = "okay"; + label = "eth3"; + mtd-mac-address = <&factory 0x0>; + mtd-mac-address-increment = <4>; + }; + + port@4 { + status = "okay"; + label = "eth4"; + mtd-mac-address = <&factory 0x0>; + mtd-mac-address-increment = <5>; + }; + }; +}; + +&pcie { + status = "okay"; +}; + +&sdhci { + status = "okay"; + max-frequency = <20000000>; +}; + +&state_default { + gpio { + groups = "wdt", "jtag"; + function = "gpio"; + }; +}; + +&uartlite2 { + status = "okay"; +}; + +&uartlite3 { + status = "okay"; +}; diff --git a/target/linux/ramips/files/drivers/mmc/host/mtk-mmc/sd.c b/target/linux/ramips/files/drivers/mmc/host/mtk-mmc/sd.c index 188e01557..4b84115f1 100644 --- a/target/linux/ramips/files/drivers/mmc/host/mtk-mmc/sd.c +++ b/target/linux/ramips/files/drivers/mmc/host/mtk-mmc/sd.c @@ -99,6 +99,7 @@ #define MAX_SGMT_SZ (MAX_DMA_CNT) #define MAX_REQ_SZ (MAX_SGMT_SZ * 8) +static int host_max_mclk = HOST_MAX_MCLK; static int cd_active_low = 1; //================================= @@ -455,7 +456,7 @@ static void msdc_tasklet_card(struct work_struct *work) host->card_inserted = inserted; if (!host->suspend) { - host->mmc->f_max = HOST_MAX_MCLK; + host->mmc->f_max = host_max_mclk; mmc_detect_change(host->mmc, msecs_to_jiffies(20)); } @@ -2233,10 +2234,13 @@ static int msdc_drv_probe(struct platform_device *pdev) goto host_free; } + if (of_property_read_u32(pdev->dev.of_node, "max-frequency", &ret) == 0) + host_max_mclk = ret; + /* Set host parameters to mmc */ mmc->ops = &mt_msdc_ops; mmc->f_min = HOST_MIN_MCLK; - mmc->f_max = HOST_MAX_MCLK; + mmc->f_max = host_max_mclk; mmc->ocr_avail = MSDC_OCR_AVAIL; mmc->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; diff --git a/target/linux/ramips/image/mt7621.mk b/target/linux/ramips/image/mt7621.mk index dcc5d1231..fd6eb8798 100644 --- a/target/linux/ramips/image/mt7621.mk +++ b/target/linux/ramips/image/mt7621.mk @@ -26,6 +26,71 @@ define Build/gemtek-trailer printf "%s%08X" ".GEMTEK." "$$(cksum $@ | cut -d ' ' -f1)" >> $@ endef +define Build/hatlab-gateboard-combined + rm -fR $@.bootfs.img + + mkfs.fat $@.bootfs.img -C 16384 + mcopy -i $@.bootfs.img $(IMAGE_KERNEL) ::vmlinux.itb + + ( \ + set $$(ptgen -o $@ -h 4 -s 63 -l 1024 -g -p 16M -p "${CONFIG_TARGET_ROOTFS_PARTSIZE}M" -G ${IMG_PART_DISKGUID}); \ + BOOTFSOFFSET="$$(($$1 / 512))"; \ + ROOTFSOFFSET="$$(($$3 / 512))"; \ + dd if="$@.bootfs.img" of="$@" bs=512 seek="$${BOOTFSOFFSET}" conv=notrunc; \ + dd if="${IMAGE_ROOTFS}" of="$@" bs=512 seek="$${ROOTFSOFFSET}" conv=notrunc; \ + ) +endef + +define Build/hatlab-gateboard-kernel + rm -fR $@.initrd + rm -fR $@.initrd.cpio + + mkdir -p $@.initrd/{bin,dev,proc,sys,lib,etc} + mkdir -p $@.initrd/lib/modules/$(LINUX_VERSION) + + $(CP) $(STAGING_DIR)/rdloader/bin/* $@.initrd/bin/ + $(CP) $(STAGING_DIR)/rdloader/lib/* $@.initrd/lib/ + $(CP) $(STAGING_DIR)/rdloader/etc/* $@.initrd/etc/ + + $(RSTRIP) $@.initrd/bin/ + $(RSTRIP) $@.initrd/lib/ + + chmod +x $@.initrd/bin/* + ln -s ./bin/rdloader $@.initrd/init + + ( \ + KMODS=(usb-common nls_base usbcore xhci-hcd xhci-mtk jbd2 mbcache ext4 scsi_mod usb-storage sd_mod mmc_core mmc_block mtk_sd crc32c_generic); \ + for kmod in "$${KMODS[@]}"; do \ + $(CP) \ + $(TARGET_DIR)/lib/modules/$(LINUX_VERSION)/$$kmod.ko \ + $@.initrd/lib/modules/$(LINUX_VERSION)/; \ + echo /lib/modules/$(LINUX_VERSION)/$$kmod.ko \ + >> $@.initrd/etc/rdloader_list; \ + done; \ + ) + + ( \ + if [ -f $(STAGING_DIR_HOST)/bin/cpio ]; then \ + CPIO=$(STAGING_DIR_HOST)/bin/cpio; \ + else \ + CPIO="cpio"; \ + fi; \ + cd $@.initrd; \ + find . | cpio -o -H newc -R 0:0 > $@.initrd.cpio; \ + ) + + $(TOPDIR)/scripts/mkits.sh \ + -D $(DEVICE_NAME) -o $@.its -k $@ \ + -C gzip -d $(KDIR)/image-$(DEVICE_DTS).dtb \ + -i $@.initrd.cpio \ + -a $(KERNEL_LOADADDR) -e $(KERNEL_LOADADDR) \ + -c config-1 -A $(LINUX_KARCH) -v $(LINUX_VERSION) + + PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage -f $@.its $@.new + + @mv $@.new $@ +endef + define Build/iodata-factory $(eval fw_size=$(word 1,$(1))) $(eval fw_type=$(word 2,$(1))) @@ -672,6 +737,28 @@ define Device/gnubee_gb-pc2 endef TARGET_DEVICES += gnubee_gb-pc2 +define Device/hatlab_gateboard-one + $(Device/dsa-migration) + DEVICE_VENDOR := HATLab + DEVICE_MODEL := GateBoard-One + DEVICE_PACKAGES := kmod-fs-ext4 kmod-gpio-pcf857x kmod-hwmon-gpiofan \ + kmod-hwmon-lm75 kmod-i2c-gpio kmod-rtc-pcf8563 kmod-sdhci-mt7620 \ + kmod-sfp kmod-thermal kmod-usb3 kmod-usb-ledtrig-usbport rdloader + KERNEL := kernel-bin | gzip | hatlab-gateboard-kernel + IMAGE/kernel.itb := append-kernel + IMAGE/rootfs.img := append-rootfs | pad-to $(ROOTFS_PARTSIZE) + IMAGE/rootfs.img.gz := append-rootfs | pad-to $(ROOTFS_PARTSIZE) | gzip + IMAGE/combined.img := hatlab-gateboard-combined | append-metadata + IMAGE/combined.img.gz := hatlab-gateboard-combined | gzip | append-metadata + IMAGES := kernel.itb + ifeq ($(CONFIG_TARGET_IMAGES_GZIP),y) + IMAGES += rootfs.img.gz combined.img.gz + else + IMAGES += rootfs.img combined.img + endif +endef +TARGET_DEVICES += hatlab_gateboard-one + define Device/hilink_hlk-7621a IMAGE_SIZE := 32448k DEVICE_VENDOR := HiLink diff --git a/target/linux/ramips/mt7621/base-files/etc/board.d/02_network b/target/linux/ramips/mt7621/base-files/etc/board.d/02_network index 03df7b8a0..7502a9134 100644 --- a/target/linux/ramips/mt7621/base-files/etc/board.d/02_network +++ b/target/linux/ramips/mt7621/base-files/etc/board.d/02_network @@ -57,6 +57,9 @@ ramips_setup_interfaces() gnubee,gb-pc2) ucidef_set_interface_lan "lan1 lan2" ;; + hatlab,gateboard-one) + ucidef_set_interfaces_lan_wan "eth0 eth1 eth2 eth3 eth4" "eth5" + ;; linksys,re6500|\ netgear,wac104) ucidef_set_interface_lan "lan1 lan2 lan3 lan4" diff --git a/target/linux/ramips/mt7621/base-files/lib/upgrade/hatlab.sh b/target/linux/ramips/mt7621/base-files/lib/upgrade/hatlab.sh new file mode 100644 index 000000000..ba5069750 --- /dev/null +++ b/target/linux/ramips/mt7621/base-files/lib/upgrade/hatlab.sh @@ -0,0 +1,88 @@ +. /lib/functions.sh + +hatlab_check_image() { + local diskdev partdev diff + + export_bootdevice && export_partdevice diskdev 0 || { + echo "Unable to determine upgrade device" + return 1 + } + + get_partitions "/dev/$diskdev" bootdisk + + #extract the boot sector from the image + get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b 2>/dev/null + + get_partitions /tmp/image.bs image + + #compare tables + diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)" + + rm -f /tmp/image.bs /tmp/partmap.bootdisk /tmp/partmap.image + + if [ -n "$diff" ]; then + echo "Partition layout has changed. Full image will be written." + ask_bool 0 "Abort" && exit 1 + return 0 + fi +} + +hatlab_copy_config() { + local partdev parttype=ext4 + + if export_partdevice partdev 2; then + mount -t $parttype -o rw,noatime "/dev/$partdev" /mnt + cp -af "$UPGRADE_BACKUP" "/mnt/$BACKUP_FILE" + umount /mnt + fi +} + +hatlab_do_upgrade() { + local diskdev partdev diff + + export_bootdevice && export_partdevice diskdev 0 || { + echo "Unable to determine upgrade device" + return 1 + } + + sync + + if [ "$UPGRADE_OPT_SAVE_PARTITIONS" = "1" ]; then + get_partitions "/dev/$diskdev" bootdisk + + #extract the boot sector from the image + get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b + + get_partitions /tmp/image.bs image + + #compare tables + diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)" + else + diff=1 + fi + + if [ -n "$diff" ]; then + get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync + + # Separate removal and addtion is necessary; otherwise, partition 1 + # will be missing if it overlaps with the old partition 2 + partx -d - "/dev/$diskdev" + partx -a - "/dev/$diskdev" + + return 0 + fi + + #iterate over each partition from the image and write it to the boot disk + while read part start size; do + if export_partdevice partdev $part; then + echo "Writing image to /dev/$partdev..." + get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync + else + echo "Unable to find partition $part device, skipped." + fi + done < /tmp/partmap.image + + #copy partition uuid + echo "Writing new UUID to /dev/$diskdev..." + get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync +} diff --git a/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh b/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh index 27b8793ef..af9dc9ca9 100755 --- a/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh +++ b/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh @@ -9,6 +9,28 @@ RAMFS_COPY_BIN='fw_printenv fw_setenv' RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock' platform_check_image() { + local board=$(board_name) + + case "$board" in + hatlab,gateboard-one) + hatlab_check_image "$1" + return $?; + ;; + esac + + return 0 +} + +platform_copy_config() { + local board=$(board_name) + + case "$board" in + hatlab,gateboard-one) + hatlab_copy_config + return $?; + ;; + esac + return 0 } @@ -86,6 +108,9 @@ platform_do_upgrade() { xiaomi,redmi-router-ac2100) nand_do_upgrade "$1" ;; + hatlab,gateboard-one) + hatlab_do_upgrade "$1" + ;; iodata,wn-ax1167gr2|\ iodata,wn-ax2033gr|\ iodata,wn-dx1167r) diff --git a/target/linux/ramips/mt7621/base-files/sbin/fixup-mac-address b/target/linux/ramips/mt7621/base-files/sbin/fixup-mac-address index dad15c584..35c8c20cf 100755 --- a/target/linux/ramips/mt7621/base-files/sbin/fixup-mac-address +++ b/target/linux/ramips/mt7621/base-files/sbin/fixup-mac-address @@ -9,6 +9,10 @@ YES= board=$(board_name) case $board in + hatlab,gateboard-one) + partname=factory + offset=$((0x0)) + ;; mqmaker,witi) partname=factory offset=$((0xe000)) diff --git a/target/linux/ramips/mt7621/config-5.10 b/target/linux/ramips/mt7621/config-5.10 index a00d4e075..1442700d5 100644 --- a/target/linux/ramips/mt7621/config-5.10 +++ b/target/linux/ramips/mt7621/config-5.10 @@ -233,6 +233,7 @@ CONFIG_RALINK=y CONFIG_RATIONAL=y CONFIG_RCU_NEED_SEGCBLIST=y CONFIG_RCU_STALL_COMMON=y +CONFIG_REALTEK_PHY=y CONFIG_REGMAP=y CONFIG_REGMAP_MMIO=y CONFIG_REGULATOR=y diff --git a/target/linux/ramips/mt7621/config-5.4 b/target/linux/ramips/mt7621/config-5.4 index 32e704231..b823247d7 100644 --- a/target/linux/ramips/mt7621/config-5.4 +++ b/target/linux/ramips/mt7621/config-5.4 @@ -229,6 +229,7 @@ CONFIG_RALINK=y CONFIG_RATIONAL=y CONFIG_RCU_NEED_SEGCBLIST=y CONFIG_RCU_STALL_COMMON=y +CONFIG_REALTEK_PHY=y CONFIG_REGMAP=y CONFIG_REGMAP_I2C=y CONFIG_REGMAP_MMIO=y diff --git a/target/linux/ramips/patches-5.4/304-spi-nor-add-p25d40h.patch b/target/linux/ramips/patches-5.4/304-spi-nor-add-p25d40h.patch new file mode 100644 index 000000000..b51078148 --- /dev/null +++ b/target/linux/ramips/patches-5.4/304-spi-nor-add-p25d40h.patch @@ -0,0 +1,12 @@ +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -2410,6 +2410,9 @@ static const struct flash_info spi_nor_ids[] = { + { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, + { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, + ++ /* PUYA */ ++ { "p25d40h", INFO(0x856013, 0, 64 * 1024, 8, SECT_4K) }, ++ + /* Spansion/Cypress -- single (large) sector size only, at least + * for the chips listed here (without boot sectors). + */ diff --git a/target/linux/ramips/patches-5.4/992-rtl8211x.patch b/target/linux/ramips/patches-5.4/992-rtl8211x.patch new file mode 100644 index 000000000..a7946f1ff --- /dev/null +++ b/target/linux/ramips/patches-5.4/992-rtl8211x.patch @@ -0,0 +1,150 @@ +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -7,6 +7,7 @@ + * Author: Johnson Leung + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. ++ * Copyright (c) 2022 Aodzip + */ + #include + #include +@@ -28,6 +29,12 @@ + + #define RTL8211F_INSR 0x1d + ++#define RTL8211x_FIBER_ESR 0x0F ++#define RTL8211x_MODE_MASK 0xC000 ++ ++#define RTL8211x_MODE_COPPER 0 ++#define RTL8211x_MODE_FIBER 1 ++ + #define RTL8211F_TX_DELAY BIT(8) + #define RTL8211E_TX_DELAY BIT(1) + #define RTL8211E_RX_DELAY BIT(2) +@@ -49,6 +56,10 @@ + + #define RTL_GENERIC_PHYID 0x001cc800 + ++struct rtl8211x_priv { ++ int lastmode; ++}; ++ + MODULE_DESCRIPTION("Realtek PHY driver"); + MODULE_AUTHOR("Johnson Leung"); + MODULE_LICENSE("GPL"); +@@ -443,6 +454,88 @@ static int rtl8125_match_phy_device(struct phy_device *phydev) + rtlgen_supports_2_5gbps(phydev); + } + ++static int rtl8211x_probe(struct phy_device *phydev) ++{ ++ struct device *dev = &phydev->mdio.dev; ++ struct rtl8211x_priv *priv; ++ ++ priv = devm_kzalloc(dev, sizeof(struct rtl8211x_priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ phydev->priv = priv; ++ ++ return 0; ++} ++ ++static void rtl8211x_remove(struct phy_device *phydev) ++{ ++ struct device *dev = &phydev->mdio.dev; ++ struct rtl8211x_priv *priv = phydev->priv; ++ ++ if (priv) ++ devm_kfree(dev, priv); ++} ++ ++static int rtl8211x_mode(struct phy_device *phydev) ++{ ++ u16 val; ++ ++ val = phy_read(phydev, RTL8211x_FIBER_ESR); ++ val &= RTL8211x_MODE_MASK; ++ ++ if(val) ++ return RTL8211x_MODE_FIBER; ++ else ++ return RTL8211x_MODE_COPPER; ++} ++ ++static int rtl8211x_config_aneg(struct phy_device *phydev) ++{ ++ int ret; ++ ++ struct rtl8211x_priv *priv = phydev->priv; ++ ++ ret = genphy_read_abilities(phydev); ++ if(ret < 0) ++ return ret; ++ ++ linkmode_copy(phydev->advertising, phydev->supported); ++ ++ if (rtl8211x_mode(phydev) == RTL8211x_MODE_FIBER) { ++ dev_info(&phydev->mdio.dev, "Fiber Mode"); ++ priv->lastmode = RTL8211x_MODE_FIBER; ++ return genphy_c37_config_aneg(phydev); ++ } ++ ++ dev_info(&phydev->mdio.dev, "Copper Mode"); ++ ++ priv->lastmode = RTL8211x_MODE_COPPER; ++ ++ return genphy_config_aneg(phydev); ++} ++ ++static int rtl8211x_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ struct rtl8211x_priv *priv = phydev->priv; ++ ++ if(rtl8211x_mode(phydev) != priv->lastmode) { ++ ret = rtl8211x_config_aneg(phydev); ++ if(ret < 0) ++ return ret; ++ ++ ret = genphy_restart_aneg(phydev); ++ if(ret < 0) ++ return ret; ++ } ++ ++ if (rtl8211x_mode(phydev) == RTL8211x_MODE_FIBER) ++ return genphy_c37_read_status(phydev); ++ ++ return genphy_read_status(phydev); ++} ++ + static struct phy_driver realtek_drvs[] = { + { + PHY_ID_MATCH_EXACT(0x00008201), +@@ -495,8 +588,12 @@ static struct phy_driver realtek_drvs[] = { + }, { + PHY_ID_MATCH_EXACT(0x001cc914), + .name = "RTL8211DN Gigabit Ethernet", ++ .probe = rtl8211x_probe, ++ .remove = rtl8211x_remove, + .ack_interrupt = rtl821x_ack_interrupt, + .config_intr = rtl8211e_config_intr, ++ .config_aneg = rtl8211x_config_aneg, ++ .read_status = rtl8211x_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = rtl821x_read_page, +@@ -514,9 +611,13 @@ static struct phy_driver realtek_drvs[] = { + }, { + PHY_ID_MATCH_EXACT(0x001cc916), + .name = "RTL8211F Gigabit Ethernet", ++ .probe = rtl8211x_probe, ++ .remove = rtl8211x_remove, + .config_init = &rtl8211f_config_init, + .ack_interrupt = &rtl8211f_ack_interrupt, + .config_intr = &rtl8211f_config_intr, ++ .config_aneg = rtl8211x_config_aneg, ++ .read_status = rtl8211x_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = rtl821x_read_page,