UEFI
统一可扩展固件接口(Unified Extensible Firmware Interface,简称 UEFI,EFI 的后继者)是操作系统和固件之间的接口。UEFI 提供了启动操作系统或运行预启动程序的标准环境。
UEFI 有别于传统 BIOS 系统所使用的“MBR 引导代码”。二者的区别和使用 UEFI 启动的过程见 Arch 的启动流程。要配置 UEFI 引导加载程序,请参见 Arch 的启动流程#引导加载程序。
UEFI 版本[编辑 | 编辑源代码]
- 1.x 版本的 UEFI 起始于 Intel 的 EFI。
- 后来,一个名为 UEFI Forum 的公司组织接管了其开发工作,他们从 2.0 版本起将其更名为 Unified EFI。
- 除非特别指明是 EFI 1.x,EFI 和 UEFI 均指代 UEFI 2.x 固件。
- Apple 的 EFI 实现既不是 EFI 1.x 版本也不是 UEFI 2.x 版本,而是这两者的混合体。这类固件不被归入到任何 (U)EFI 规格中,因而不是标准的 UEFI 固件。除非特别指明,以下说明可通用,但部分内容在 Apple Macs 上可能无效或有所不同。
最新的 UEFI 标准位于 https://uefi.org/specifications 。
UEFI 固件架构[编辑 | 编辑源代码]
UEFI 下每一个程序,无论它是某个 OS 引导器还是某个内存测试或数据恢复的工具,都要兼容于 EFI 固件位数或体系结构。
目前主流的 UEFI 固件,包括近期的 Apple Macs,都采用了 x86_64 EFI 固件。目前还在用 IA32 即 32 位的 EFI 的已知设备只有于 2008 年前生产的 Apple Macs,一些 Intel Cloverfield 超级本和采用 EFI 1.10 固件的 Intel 服务器主板。
x86_64 EFI 不能兼容 32 位 EFI 程序。所以 UEFI 应用程序必须依固件处理器位数/体系结构编译而成。
i386-efi
模块的GRUB。检查系统位数[编辑 | 编辑源代码]
Linux 系统[编辑 | 编辑源代码]
在运行Linux 4.0及以上内核的发行版中,可以通过 sysfs 接口查看 UEFI 系统位数。试着运行:
$ cat /sys/firmware/efi/fw_platform_size
如果返回 64
则代表 64 位(x86_64) UEFI 系统,如果返回 32
则代表 32 位(IA32) UEFI 系统。如果文件不存在,那么代表并没有进入 UEFI 模式。
macOS 系统[编辑 | 编辑源代码]
2008年以前的 Mac 大都使用 i386-efi 固件, 2008年以后大都使用 x86_64-efi 。有能力运行 Mac OS X Snow Leopard 64位内核的 Mac 都是 x86_64 EFI 1.x 版的固件。 在 Mac OS 下输入以下命令可以找出该 Mac 的 efi 固件:
$ ioreg -l -p IODeviceTree | grep firmware-abi
如果命令返回 EFI32 则对应的是 i386 EFI 1.x 版本的固件,返回 EFI64 对应的则是 x86_64 EFI 1.x 版的固件. Mac 没有 UEFI 2.x 固件,Apple的 EFI 实现也不完全跟 UEFI 标准兼容。
Windows 系统[编辑 | 编辑源代码]
64 位的 Windows 系统不支持在 32 位 UEFI 上启动。所以如果你在 UEFI 模式下启动了 32 位 Windows,那么你使用的是 32 位 UEFI。
可以通过运行 msinfo32.exe
来查看系统位数。请看系统摘要条目下“系统类型”和“BIOS模式”对应的值。
如果是 64 位 UEFI 上的 64 位 Windows,则会有 系统类型:基于x64的电脑
和 BIOS 模式:UEFI
;如果是 32 位 UEFI 上的 32 位 Windows,则会有 系统类型:基于x86的电脑
和 BIOS 模式:UEFI
.如果“BIOS”模式不是 UEFI
,那么 Windows 并没有用 UEFI 模式启动.
Linux 内核中有关 UEFI 的配置选项[编辑 | 编辑源代码]
UEFI 系统所要求的 Linux 内核配置选项[1]如下:
CONFIG_RELOCATABLE=y CONFIG_EFI=y CONFIG_EFI_STUB=y CONFIG_X86_SYSFB=y CONFIG_FB_SIMPLE=y CONFIG_FRAMEBUFFER_CONSOLE=y
UEFI 运行时变量支持(efivarfs 文件系统——/sys/firmware/efi/efivars
)。该选项十分重要,因为它是使用如 /usr/bin/efibootmgr
的工具操作 UEFI 运行时变量所必须的。下面的选项已添加进了 3.10 及更新版本的内核中。
CONFIG_EFIVAR_FS=y
UEFI 运行时变量支持(老式 efivars sysfs 接口——/sys/firmware/efi/vars
))。应当禁用该选项来避免同时启用 efivarfs 和 sysfs-efivars 所导致的潜在问题。
CONFIG_EFI_VARS=n
GUID 分区表 (GPT) 配置选项——UEFI 支持的强制需求
CONFIG_EFI_PARTITION=y
EFI 混合模式支持——在 IA32 UEFI 上启动 x86_64 内核。
CONFIG_EFI_MIXED=y
UEFI 变量[编辑 | 编辑源代码]
UEFI 定义了变量,通过它们操作系统可以与固件进行交互。 UEFI 引导变量只在早期系统启动时由引导加载程序和操作系统使用。UEFI运行时变量允许操作系统来管理固件的某些设置(如UEFI引导管理器)或 UEFI Secure Boot 协议的密钥。你可通过下面的命令来获得变量列表:
$ efivar -l
Linux 内核中的 UEFI 变量支持[编辑 | 编辑源代码]
Linux 内核通过两个接口来把 EFI 变量数据传递给用户空间:
- 老式 sysfs-efivars 接口 (CONFIG_EFI_VARS) - 由位于
/sys/firmware/efi/vars
的内核模块efivars
生成 - 每个变量数据最大大小为1024B, 不支持 UEFI Secure Boot 变量(由于大小限制),并再也不被上游推荐使用。现仍被上游支持但在 Arch 官方内核中已完全禁用。
- 新式 efivarfs (EFI VARiable FileSystem) 接口 (CONFIG_EFIVAR_FS) - 由位于
/sys/firmware/efi/efivars
的efivarfs
内核模块挂载使用 - 老式 sysfs-efivars 接口的替代品,不限制变量数据大小,支持 UEFI Secure Boot 变量并被上游推荐使用。在3.8版的内核中引入,新的efivarfs
模块在3.10版内核中从旧的efivars
内核模块中分离。
efivarfs 和 sysfs-efivars 的不一致[编辑 | 编辑源代码]
同时启用老式的 sysfs-efivars 和新式的 efivarfs 会导致数据不一致的问题(更多信息见 https://lore.kernel.org/lkml/1366148520-29954-4-git-send-email-matt@console-pimps.org/ )。由于(自从 core/linux包-3.11 和 core/linux-lts包-3.10)老式的 sysfs-efivars 在 Arch 官方内核中已完全禁用,新式的 efivarfs 将会被继续地启用/支持下去。自2013年10月1日起,在官方源中所有与 UEFI 变量相关的工具都支持 efivarfs.
efi_pstore
在 Arch 官方内核中也被禁用,因为 EFI pstore 功能依赖老式 sysfs-efivars 支持。如果在使用任何用户空间工具访问 EFI VAR 数据前你同时开启了这两者,请禁用其中之一并重新开启另一个接口 (为了刷新数据和防止不一致) :
禁用 sysfs-efivars 并刷新 efivarfs:
# modprobe -r efivars # umount /sys/firmware/efi/efivars # modprobe -r efivarfs # modprobe efivarfs # mount -t efivarfs efivarfs /sys/firmware/efi/efivars
禁用 efivarfs 并刷新 sysfs-efivars:
# umount /sys/firmware/efi/efivars # modprobe -r efivarfs # modprobe -r efivars # modprobe efivars
UEFI 变量正常工作的需求[编辑 | 编辑源代码]
- 内核处理器的位数应该与 EFI 处理器的位数相符。
- 内核应以 EFI 模式(通过 EFISTUB 或 EFI 引导器,而不是 BIOS/CSM 或者同为 BIOS/CSM 的"bootcamp")启动。
- EFI 运行时服务支持应出现在内核中 (
CONFIG_EFI=y
, 运行zgrep CONFIG_EFI /proc/config.gz
来核对是否共存 ). - EFI 运行时服务在内核命令行中不应被禁用,即不应使用内核参数
noefi
. efivarfs
文件系统应被挂载在/sys/firmware/efi/efivars
, 否则参考下文 #挂载 efivarfs 部分。efivar
应无错列出 (选项-l
) EFI 变量。参见输出内容 #UEFI 变量.
如果 EFI 变量支持在满足以上条件后仍有问题,尝试以下解决方案:
- 如果所有的用户空间工具都不能修改 EFI 变量数据,检查
/sys/firmware/efi/efivars/dump-*
文件是否存在。如果是,删掉,重启,再试一次。 - 如果上面的步骤没有解决问题,尝试以内核参数
efi_no_storage_paranoia
启动以禁用内核 EFI 变量存储空间来防止对 EFI 变量的写入/修改。
efi_no_storage_paranoia
仅当需要时使用且不应留下作为正常启动参数。该内核参数的效果是关闭正在实施的安全保护,来避免 NVRAM 过满时机器故障。挂载 efivarfs[编辑 | 编辑源代码]
如果 efivarfs
启动时并没有被 systemd 自动挂载在 /sys/firmware/efi/efivars
, 你需要手动挂载来把 EFI 变量支持传递给像 efibootmgr
等的用户空间工具:
# mount -t efivarfs efivarfs /sys/firmware/efi/efivars
如下通过 /etc/fstab
来自动挂载 efivarfs
也是极好的:
/etc/fstab
efivarfs /sys/firmware/efi/efivars efivarfs defaults 0 0
用户空间工具[编辑 | 编辑源代码]
只有少量工具能够访问/修改 UEFI 变量,即
- efivar — 操作 UEFI 变量的库和工具 (被 efibootmgr 用到)
- efibootmgr — 操作 UEFI 固件启动管理器设置的工具
- uefivars — 转储 UEFI 变量和 PCI 相关信息 (内部使用 efibootmgr 源码)
- efitools — 创建与设置自己的 UEFI Secure Boot 证书,密钥和签名过的程序的工具 (需要 efivarfs)
- Ubuntu的固件测试套件 — 固件检查工具
efibootmgr[编辑 | 编辑源代码]
- 如果
efibootmgr
完全无效,你可以重启进入 UEFI Shell 使用bcfg
命令来给引导器创建一个启动条目。 - 如果你不能使用
efibootmgr
, 某些 UEFI 固件允许用户用内建的启动时界面管理启动条目。例如,某些华硕机有 "Add New Boot Option" 选项,能让你选择本地 EFI 系统分区并手动进入 EFI 存根位置 (例如\EFI\refind\refind_x64.efi
). - 下面的命令用 rEFInd 引导器作为例子。
要通过 efibootmgr 添加新的启动参数,需要确认:
- 包含 ESP 的磁盘编号:
/dev/sdX
- ESP 在第几个分区
/dev/sdXY
中的Y
- UEFI 程序相对 ESP 根目录的路径
假设要启动的引导器文件是 /boot/efi/EFI/refind/refind_x64.efi
,/boot/efi
是 ESP 的挂载目录
$ findmnt /boot/efi
TARGET SOURCE FSTYPE OPTIONS /boot/efi /dev/sda1 vfat rw,flush,tz=UTC
上面结果说明 ESP 位于 /dev/sda
,分区编号是 1. UEFI 程序相对于 ESP 根的路径是/EFI/refind/refind_x64.efi
. 应该用下面 efibootmgr 语句创建:
# efibootmgr --create --disk /dev/sda --part 1 --loader /EFI/refind/refind_x64.efi --label "rEFInd Boot Manager"
参考efibootmgr(8) 或 efibootmgr README。
\
作为路径分隔符 (类似于 Windows 路径),Efibootmgr 解析路径之前内部会把 /
转换为 \
.UEFI Shell[编辑 | 编辑源代码]
UEFI Shell 是固件的终端,可用于启动包括引导器的 UEFI 程序。除此之外, Shell也可用于采集固件和系统的各种信息,例如内存映射 (memmap), 修改启动管理器变量 (bcfg), 运行分区程序 (diskpart), 加载 UEFI 驱动,编辑文本文件 (edit), 十六进制编辑等等。
获取 UEFI Shell[编辑 | 编辑源代码]
你可从 Intel 的 Tianocore UDK/EDK2 Sourceforge.net 工程下载以 BSD 许可证发布的 UEFI Shell.
- uefi-shell-gitAUR 包 (推荐) - 为 x86_64 系统提供 x86_64 Shell 以及为 i686 系统提供 IA32 Shell - 直接从 Tianocore EDK2 最新的源码编译
- Precompiled UEFI Shell v2 binaries[失效链接 2020-08-06 ⓘ] (may not be up-to-date)
- Precompiled UEFI Shell v1 binaries[失效链接 2020-08-06 ⓘ] (not updated anymore upstream)
- UEFI Shell v2 binary with bcfg modified to work with UEFI pre-2.3 firmware[失效链接 2020-08-06 ⓘ] - from Clover EFI bootloader
Shell v2 在 UEFI 2.3+ 系统上表现最好,并比 Shell v1 优先推荐。Shell v1 应该在所有 UEFI 系统上有效并且与它们遵循的 UEFI 标准版本无关。更多信息见 ShellPkg。
启动 UEFI Shell[编辑 | 编辑源代码]
部分基于 AMI Aptio x86_64 UEFI 固件的主板 (从 Sandy Bridge 起,尤其是华硕) 提供了一个叫做 "Launch EFI Shell from filesystem device"
的选项。对于这些主板,下载 x86_64 UEFI Shell ,复制进 EFI 系统分区,命名为 <EFI_SYSTEM_PARTITION>/shellx64.efi
(大部分是 /boot/efi/shellx64.efi
) .
Phoenix SecureCore Tiano UEFI 固件已内嵌 UEFI Shell, 可按 F6
, F11
或 F12
键来启动。
Shell.efi
复制到 (USB)/efi/boot/bootx64.efi
. 这个 USB 会出现在固件的启动菜单里。启动它就会启动到 UEFI Shell.重要 UEFI Shell 命令[编辑 | 编辑源代码]
UEFI Shell 命令通常支持 -b
选项,它在输出的每页末尾暂停. 运行 help -b
来列出所有可用命令。
更多信息见 https://software.intel.com/en-us/articles/efi-shells-and-scripting/
bcfg[编辑 | 编辑源代码]
bcfg
命令用于修改 UEFI NVRAM 条目,它能让用户改变启动条目或驱动器选项。在[https://www.uefi.org/sites/default/files/resources/UEFI_Shell_Spec_2_0.pdf
UEFI Shell Specification 2.0] PDF 文档的 83 页(Section 5.3) 有详细说明。
- 仅当
efibootmgr
无法创建启动条目时才推荐尝试bcfg
. - UEFI Shell v1 官方二进制文件不支持
bcfg
命令。你可以下载一个 modified UEFI Shell v2 二进制文件[失效链接 2020-08-06 ⓘ],它在 UEFI 2.3前的固件有效。
转储当前启动条目:
Shell> bcfg boot dump -v
为 rEFInd (作为例子) 添加一个启动菜单条目,在启动菜单里是第4个 (从0开始计数) 选项:
Shell> bcfg boot add 3 fs0:\EFI\refind\refind_x64.efi "rEFInd"
fs0:
映射到 EFI 系统分区,fs0:\EFI\refind\refind_x64.efi
i是要启动的文件。
To add an entry to boot directly into your system without a bootloader, configure a boot option using your kernel as an EFISTUB}:
Shell> bcfg boot add N fsV:\vmlinuz-linux "Arch Linux" Shell> bcfg boot -opt N "root=/dev/sdX# initrd=\initramfs-linux.img"
where N
is the priority, V
is the volume number of your EFI partition, and /dev/sdX#
is your root partition.
删除第4个启动选项:
Shell> bcfg boot rm 3
把第3个启动选项移动到第0 (也就是说第1个是 UEFI 启动菜单的默认启动选项):
Shell> bcfg boot mv 3 0
bcfg 帮助文档:
Shell> help bcfg -v -b
或:
Shell> bcfg -? -v -b
map[编辑 | 编辑源代码]
map
displays a list of device mappings i.e. the names of available file systems (fs0
) and storage devices (blk0
).
Before running file system commands such as cd
or ls
, you need to change the shell to the appropriate file system by typing its name:
Shell> fs0: fs0:\> cd EFI/
edit[编辑 | 编辑源代码]
EDIT 命令提供了类似于 nano 界面的基本编辑器,但是功能略少一点。它以 UTF-8 编码并且行尾结束符兼容 LF 和 CRLF.
本例中,编辑在固件 EFI 系统分区 (fs0:
中 rEFInd 的 refind.conf
Shell> edit FS0:\EFI\refind\refind.conf
输入 Ctrl-E
以获得帮助。
UEFI 可启动介质[编辑 | 编辑源代码]
从 ISO 创建 UEFI 可启动 USB[编辑 | 编辑源代码]
教程见 USB flash installation medium#Using the ISO as is (BIOS and UEFI).
从光学介质里移除 UEFI 启动支持[编辑 | 编辑源代码]
大部分32位 EFI Mac 机和部分64位 EFI Mac 机无法从 UEFI(X64)+BIOS 可启动 CD/DVD 启动。如果希望使用光学介质完成安装,可能首先需要移除 UEFI 启动支持。
- 挂载官方安装介质并如前所述获取
archisolabel
.
# mount -o loop input.iso /mnt/iso
- 然后重建 ISO, 使用 libisoburn包 的
xorriso
移除 UEFI 光学介质启动支持。确认已设置正确的 archisolabel, 例如 "ARCH_201411"或类似的:
$ xorriso -as mkisofs -iso-level 3 \ -full-iso9660-filenames\ -volid "archisolabel" \ -appid "Arch Linux CD" \ -publisher "Arch Linux <https://archlinux.org>" \ -preparer "prepared by $USER" \ -eltorito-boot isolinux/isolinux.bin \ -eltorito-catalog isolinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -isohybrid-mbr "/mnt/iso/isolinux/isohdpfx.bin" \ -output output.iso /mnt/iso/
- 把
output.iso
烧制进光学介质并照常完成安装。
原生无支持情况下测试 UEFI[编辑 | 编辑源代码]
虚拟机使用 OVMF[编辑 | 编辑源代码]
OVMF 是一个将 UEFI 添加到虚拟机的 tianocore 项目。OVMF 包含了一个 QEMU 使用的示例 UEFI 固件。
安装 edk2-ovmf包.
建议先将虚拟机的非易逝变量本地保存一份。
$ cp /usr/share/ovmf/ovmf_vars_x64.bin my_uefi_vars.bin
然后在 QEME 命令中加入:
-drive if=pflash,format=raw,readonly,file=/usr/share/ovmf/ovmf_code_x64.bin \ -drive if=pflash,format=raw,file=my_uefi_vars.bin
示例:
$ qemu-system-x86_64 -enable-kvm -m 1G -drive if=pflash,format=raw,readonly,file=/usr/share/ovmf/ovmf_code_x64.bin -drive if=pflash,format=raw,file=efi_vars.bin …
仅 BIOS 的系统使用 DUET[编辑 | 编辑源代码]
DUET 是一个 tianocore 工程用以从 BIOS 启动到完整 UEFI 环境,这与 BIOS 启动操作系统相似。在 https://www.insanelymac.com/forum/topic/186440-linux-and-windows-uefi-boot-using-tianocore-duet-firmware/ 里有广泛讨论。预建立的 DUET 镜像可从其中一个源 https://gitorious.org/tianocore_uefi_duet_builds[失效链接 2020-08-06 ⓘ] 下载。教程见 https://gitorious.org/tianocore_uefi_duet_builds/tianocore_uefi_duet_installer/blobs/raw/master/Migle_BootDuet_INSTALL.txt[失效链接 2020-08-06 ⓘ].
也可考虑 https://sourceforge.net/projects/cloverefiboot/ , 它提供的 DUET 镜像可能包含了一些系统的专用补丁,并且比 gitorious 源更新得更频繁。
疑难问题[编辑 | 编辑源代码]
困在 Windows 时启动到 Arch Linux[编辑 | 编辑源代码]
当被困在 Windows 时,要启动到 Arch Linux,可以通过 Windows PowerShell 命令 shutdown /r /o
或者通过设置 > 更新与安全 > 恢复 > 高级启动,选择现在重启到达 Windows 的高级启动。当你到达高级启动菜单时,选择使用设备,这个菜单实际上包含你的 UEFI 启动选项(不限于 USB 或 CD,也可以启动硬盘中的操作系统),并选择“Arch Linux”。
Windows 7 无法以 UEFI 模式启动[编辑 | 编辑源代码]
如果你把 Windows 安装进了另一个 GPT 格式的硬盘并且你电脑里还有一个 MBR 格式的硬盘,那么可能 UEFI 固件启动了 CSM 支持(为从 MBR 分区启动的支持) 因而 Windows 无法启动。为解决问题,把 MBR 硬盘的内容合并到 GPT 硬盘中并禁用 MBR 硬盘使用的 SATA 接口或者直接把硬盘拔下来。
有此类问题的主板:
Gigabyte Z77X-UD3H rev. 1.1 (UEFI 版本 F19e)
- 固件启动选项 "UEFI Only" 并不妨碍以 CSM 启动。
Windows 改变了启动次序[编辑 | 编辑源代码]
例如你升级 Windows 后直接启动了Windows而不是选择启动菜单:
- 确定UEFI固件设置中的"安全启动"(Secure Boot) 和 Windows 中的"快速启动" 选项没有启用.
- 确定UEFI固件设置的启动顺序中Linux Boot Manager 先于 Windows Boot Manager.
你可以通过组策略和一个批处理文件(".bat")来阻止Windows更改启动设置,在Windows上这样做:
- 以管理员身份打开命令提示符,运行
bcdedit /enum firmware
- 寻找描述中带有"linux"的启动选项,例如 "Linux Boot Manager"
- 复制带大括号的描述符, 例如
{31d0d5f4-22ad-11e5-b30b-806e6f6e6963}
- 创建一个批处理文件 (例如
bootorder.bat
) ,包含下列的内容:bcdedit /set {fwbootmgr} DEFAULT {这里是你在第三步中获得的描述符}
(例如bcdedit /set {fwbootmgr} DEFAULT {31d0d5f4-22ad-11e5-b30b-806e6f6e6963}
). - 运行 gpedit (组策略对象编辑器) 在本地计算机策略 > 计算机设置 > Windows 设置 > 脚本(启动/关机)中,选择"启动,会打开一个名为"启动选项:的对话框.
- 添加第四步中创建的批处理文件到"脚本"列表中.
或者让Windows 启动管理器加载systemd-boot的EFI应用程序,要这样做的话在Windows上以管理员身份运行:
bcdedit /set {bootmgr} path \EFI\systemd\systemd-bootx64.efi
USB 介质卡在黑屏界面[编辑 | 编辑源代码]
可能是 KMS 的问题。从 USB 启动时尝试 Disabling KMS.
参见[编辑 | 编辑源代码]
- Wikipedia:UEFI
- UEFI Forum - contains the official UEFI Specifications - GUID Partition Table is part of UEFI Specification
- UEFI boot: how does that actually work, then? - A blog post by AdamW
- Linux Kernel x86_64 UEFI Documentation
- Intel's page on EFI
- Intel Architecture Firmware Resource Center
- Matt Fleming - The Linux EFI Boot Stub
- Matt Fleming - Accessing UEFI Variables from Linux
- Rod Smith - Linux on UEFI: A Quick Installation Guide
- UEFI Boot problems on some newer machines (LKML)
- LPC 2012 Plumbing UEFI into Linux[失效链接 2021-05-17 ⓘ]
- LPC 2012 UEFI Tutorial : part 1[失效链接 2021-05-17 ⓘ]
- LPC 2012 UEFI Tutorial : part 2[失效链接 2021-05-17 ⓘ]
- Intel's TianoCore Project for Open-Source UEFI firmware which includes DuetPkg for direct BIOS based booting and OvmfPkg used in QEMU and Oracle VirtualBox
- FGA: The EFI boot process
- Microsoft's Windows and GPT FAQ
- Convert Windows x64 from BIOS-MBR mode to UEFI-GPT mode without Reinstall
- Create a Linux BIOS+UEFI and Windows x64 BIOS+UEFI bootable USB drive
- Rod Smith - A BIOS to UEFI Transformation
- EFI Shells and Scripting - Intel Documentation
- UEFI Shell - Intel Documentation
- UEFI Shell - bcfg command info
- The bootstrap process on EFI systems