Linux + Windows 10 多系统安装 U 盘

Update: Windows 的引导程序似乎有些问题,如果在同一块 U 盘上写入多个 ISO 分区的话,似乎引导会错乱,最终启动的安装程序版本不是引导程序所在分区的版本。所以暂时一个 U 盘还是只能放一个 Windows 版本。垃圾巨硬。

日常折腾中总免不了要用 LiveCD 修理一下系统,或者是重装一下 Windows 之类的。这时候制作一个引导用的 U 盘基本是最方便的选项了。有不少工具都能创建 U 盘引导,比如 ArchLinux 的 ISO 镜像可以直接用dd写入,Windows 的安装盘也能用 Rufus 创建。不过在使用上还是有些不便,比如dd会覆盖整个U盘,在ISO之外不能再存储其他文件。Rufus 只能在 Windows 上运行,而且一只 U 盘也只能放一份 ISO。于是尝试搞明白怎么把 Linux 的 LiveCD 和 Windows 的安装 ISO 写入到同一只 U 盘就很有必要了。

我个人使用的设备都支持 UEFI,所以这里制作的启动盘也只支持 UEFI 启动,需要 MBR 模式启动的读者请往它处寻。当然,Secure Boot 是要关掉的。制作过程我使用 Linux,纯 Windows 用户现在也可以退出了。基本上,我们需要创建一个 EFI 系统分区(EFI System Partition, ESP),其中包含基本的引导程序(Grub2)和 Linux LiveCD 的 ISO 文件。由于 Windows 的安装程序无法以 ISO 形式被引导,因此我们需要给每个 Windows ISO 文件创建一个分区,并将 ISO 中的内容解压进去。但是分区一旦创建不像文件那么好修改,所以创建每个 Windows ISO 分区的时候我都留了一些额外空间,以备以后 ISO 大小变化,这也意味着这些空间就基本浪费了。That's sad but I guess it's how things work.

另外,购买一个优质的 U 盘还是有必要的,不然不管是创建启动盘还是安装系统都会慢得让你痛不欲生。建议用之前先给 U 盘测一下速,什么拷贝速度只有 2MB/s 的金士顿可以直接进垃圾桶了。至于 U 盘大小取决于你要放多少个 ISO 文件和多少个 Windows 分区,一般 Linux 镜像大小在 500MB~3GB 的都有,Windows 10 的分区一般每个需要 5~6GB.

在 Raspberry Pi 4B 上安装 ArchLinux

Neofetch
很久之前就买了一个树莓派,不过一直在吃灰,正好最近有空就再拿出来折腾一下。原装系统是 32 位的,那么就必定要换一个 64 位的啦,不然对不起这 64 位的 CPU 呀。秉承“Arch大法好”的理念,我就决定用 Archlinux ARM 了。我非常建议先用原版系统更新 Bootloader 和 EEPROM到最新版本。这样可以避免各种奇怪的 bug 和使用一些新加入的功能,比如从网络启动什么的。

ArchLinux ARM 其实已经提供了树莓派的安装教程,基本上只要跟着做即可,我用的是 AArch64 镜像,并且把根文件系统从 ext4 换成了 f2fs,希望在 SD 卡上能有一点点加成效果。装完以后发现串口没有输出,自然不能忍,继续折腾。RPi 4B 一共有两个串口控制器,一个 PL011,另一个被称作 MiniUART。默认情况下,PL011 连接到蓝牙模块,并且 MiniUART 被禁用,但是我们可以通过 config.txt 加载 dtb overlay 来调整。一些常见的配置有:

  • 启用 MiniUART 串口,PL011 继续负责蓝牙
  • 禁用蓝牙,让 PL011 负责串口通信
  • 启用 MiniUART,让 MiniUART 负责蓝牙,PL011 负责串口

但是 ArchLinux ARM 使用 U-Boot 来启动内核,并不遵循 config.txt (╯°Д°)╯ ┻━┻

那么我们只能把 U-Boot 干掉了 (<ゝω・)☆

MikroTik RB4011 访客网络配置备忘

前言

Speedtest
由于之前陆陆续续添置了不少电子设备,以及更换 ISP 的原因,机架上连了5台设备,每台各负责一点点事情,不管是配置还是调试都很麻烦。再加上旧路由器不能很好同时处理千兆 NAT 和 VLAN,于是最近入手了一台 RB4011iGS+5HacQ2HnD-IN,把这一堆乱七八糟的设备统统换掉。主要需求有三点:

  1. 划分2个 VLAN,一个内部网络,一个访客网络。
  2. IPv4 和 IPv6 双栈接入。
  3. 因为路由器直接暴露在 Internet 上了,所以防火墙一定要配好,包括 VLAN 之间的访问也是靠防火墙来控制的。

WinRAR 恢复记录添加及使用教程

本文中的所有图片及文字均使用 CC0 发布,可任意转载使用。

本文属于疫情期间的摸鱼之作,旨在推广 RAR 压缩格式的正确压缩方法,让资源分享更轻松一些。

获取 WinRAR

先说一下为什么用 WinRAR 而不用 7zip, 因为 7zip 没有恢复记录。在百度网盘等平台分享文件时,文件可能发生损坏,没有恢复记录的话只能尝试重新下载浪费时间,而有恢复记录的话有大概率可以成功修复,正确解压。

国内特供版的 WinRAR 可以免费使用,但是有广告。如果不想要广告,你可以从以下链接下载官方无广告简体中文版

https://www.win-rar.com/fileadmin/winrar-versions/sc/sc20200409/rrlb/winrar-x64-590sc.exe

注意,如果你没有rarreg.key文件进行注册的话依然是有广告的。至于具体的注册方法请自行搜寻。

CMake 项目生成脚本

C++ 比较尴尬的一点就是缺少比较“傻瓜”的工具库,不得不依靠第三方来补充。想快速开始写个小的 Demo 的时候光找库就花去不少时间。于是糊了一个脚本去自动生成这些基础的东西。放在这里方便自己以后参考。

用到的库列表:

  • {fmt}: 字符串格式化库
  • spdlog: 日志
  • backward-cpp: 崩溃时的堆栈输出
  • benchmark: 快速性能测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/bin/bash

print_help() {
echo "Usage:"
echo " cproject <type> <name>"
echo "Types:"
echo " bin, bench"
}

die() {
echo "Unexpected error"
exit 2
}

# Ninja does not work with backward-cpp
new_bin() {
local name="$1"
mkdir "$name" || die
cd "$name" || die
git clone 'https://github.com/fmtlib/fmt.git' third_party/fmt || die
git clone 'https://github.com/bombela/backward-cpp.git' third_party/backward-cpp || die
git clone 'https://github.com/gabime/spdlog.git' third_party/spdlog || die
cat << EOF > CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(${name})

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_FLAGS "\${CMAKE_CXX_FLAGS} -Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "\${CMAKE_CXX_FLAGS_DEBUG} -ggdb -O0")
set(CMAKE_EXE_LINKER_FLAGS "\${CMAKE_EXE_LINKER_FLAGS} -rdynamic")

add_subdirectory(third_party/fmt)
add_subdirectory(third_party/spdlog)
add_subdirectory(third_party/backward-cpp)

add_executable(main)
target_sources(main PRIVATE main.cpp \${BACKWARD_ENABLE})
target_link_libraries(main PRIVATE fmt spdlog -ldw)
EOF

cat << 'EOF' > main.cpp
#include <iostream>
#include <string>
#include "fmt/format.h"
#include "spdlog/spdlog.h"

#define CRASH(...) \
{ ::spdlog::critical(__VA_ARGS__); \
int _ [[maybe_unused]] = \
*reinterpret_cast<int*>(0); }

inline int get_return_code() {
CRASH("unimplemented function: {}", __func__);
return 0;
}

int main(int argc, char* argv[]) {
fmt::print("{}, {}\n\n", "hello", "world");

spdlog::set_level(spdlog::level::debug);
spdlog::debug("debug message");
spdlog::info("info message");
spdlog::warn("warning message");
spdlog::error("Some error message with arg: {}", 1);
return get_return_code();
}
EOF
echo
echo "Skeleton generated. Run the command and you shall see " \
"the stacktrace demo."
echo " cd ${name} && cmake -B build && " \
"make -C build -j main && build/main"
}

new_bench() {
local name="$1"
mkdir "$name" || die
cd "$name" || die
git clone 'https://github.com/fmtlib/fmt.git' third_party/fmt || die
git clone 'https://github.com/bombela/backward-cpp.git' third_party/backward-cpp || die
git clone 'https://github.com/gabime/spdlog.git' third_party/spdlog || die
git clone 'https://github.com/google/benchmark.git' third_party/benchmark || die
git clone 'https://github.com/google/googletest.git' third_party/benchmark/googletest || die
cat << EOF > CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(${name})

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_FLAGS "\${CMAKE_CXX_FLAGS} -Wall -Wextra -g")
set(CMAKE_EXE_LINKER_FLAGS "\${CMAKE_EXE_LINKER_FLAGS} -rdynamic")

set(BENCHMARK_ENABLE_LTO true)

add_subdirectory(third_party/fmt)
add_subdirectory(third_party/spdlog)
add_subdirectory(third_party/backward-cpp)
add_subdirectory(third_party/benchmark)

add_executable(bench)
target_sources(bench PRIVATE bench.cpp \${BACKWARD_ENABLE})
target_link_libraries(bench PRIVATE fmt spdlog benchmark::benchmark_main -ldw)
EOF

cat << 'EOF' > bench.cpp
#include "benchmark/benchmark.h"
#include <cinttypes>
#include <cstdlib>

constexpr size_t ARRAY_LEN = 1024*64;
static void BM_SeqArrayAccess(benchmark::State& state) {
int stride = state.range(0);
uint64_t arr[ARRAY_LEN];
for (auto _ : state) {
for (size_t idx = 0; idx < ARRAY_LEN; idx += stride) {
arr[idx] = random();
}
}
}
BENCHMARK(BM_SeqArrayAccess)
->Arg(1)
->Arg(2)
->Arg(3)
->Arg(4)
->Arg(5)
->Arg(6)
->Arg(7)
->Arg(8);
EOF
echo
echo "Skeleton generated."
echo " cd ${name} && cmake -B build && " \
"make -C build -j bench && build/bench"
echo "You may also need to change your CPU scheduler:"
echo " sudo cpupower frequency-set -g performance"
}

if [[ "$2" == "" ]]; then
echo "Missing project name"
echo
print_help
exit 1
fi

if [[ -e "$2" ]]; then
echo "File \"$2\" already exists"
exit 1
fi

if [[ "$1" == "bin" ]]; then
new_bin "$2"
elif [[ "$1" == "bench" ]]; then
new_bench "$2"
else
echo "Unknown type: $1"
echo
print_help
exit 1
fi

简易内核开发环境

近期尝试了一下写 Linux 内核代码,于是把折腾过程记录一下,方便以后参考。本文默认使用 x86_64 架构以及 Linux 作为宿主系统。

使用 QEMU 运行 Linux 内核

在开始写代码之前,我们需要先准备好模拟器用于运行 Linux。我这里用了QEMU,你也可以用 VirtualBox 之类的虚拟机。一般来说,我们需要一个内核可执行文件(内核本体)和一个 initramfs 镜像(提供用户态程序)。当内核被加载后,它会自动载入 initramfs 镜像,并执行其中的/init程序。由于这一节的重点是 QEMU 配置,所以我直接使用宿主机的内核和 initramfs。以我的 Archlinux 系统为例,内核文件是/boot/vmlinuz-linux,initramfs 文件是/boot/initramfs-linux.img。使用以下命令启动 QEMU,按Ctrl-A x退出。

1
2
3
4
5
6
7
qemu-system-x86_64 \
-kernel /boot/vmlinuz-linux \
-initrd /boot/initramfs-linux.img \
-nographic -append "console=ttyS0" \
-m 512 \
--enable-kvm \
-cpu host
  • -kernel 指定内核可执行文件。
  • -initrd 指定 initramfs disk 镜像文件。
  • -nographic -append "console=ttyS0" 禁用视频输出并使用串口作为终端。
  • -m 512 设定内存。
  • --enable-kvm 使用KVM。
  • -cpu host 使用宿主机的 CPU 特性。

你应该能看到一些系统启动的信息以及无法挂载根分区的报错,这是正常现象,因为我们没有提供任何磁盘文件。你应该可以进入一个紧急修复 Shell, 执行一些简单的如 ls cd 之类的命令。