用 Go 编写简单操作系统
Go 标准编译器依赖运行时,不太适合裸机开发。以下是两种方案:
方案一:使用 TinyGo(推荐)
1. 环境准备
# 安装 TinyGo wget https://github.com/tinygo-org/tinygo/releases/download/v0.30.0/tinygo_0.30.0_amd64.deb sudo dpkg -i tinygo_0.30.0_amd64.deb # 安装必要工具 sudo apt install nasm qemu-system-x86 xorriso
2. 引导加载程序 (boot.asm)
; boot.asm - 16位引导扇区
[BITS 16]
[ORG 0x7C00]
start:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
; 加载内核到内存
mov bx, 0x1000 ; 加载到 0x1000
mov ah, 0x02 ; 读取扇区
mov al, 20 ; 读取 20 个扇区
mov ch, 0 ; 柱面 0
mov cl, 2 ; 从扇区 2 开始
mov dh, 0 ; 磁头 0
int 0x13
; 跳转到保护模式
jmp 0x1000:0x0000
times 510-($-$$) db 0
dw 0xAA55 ; 引导签名 3. Go 内核代码 (kernel.go)
package main
// 禁用 Go 运行时
//go:build tinygo
const (
VGA_WIDTH = 80
VGA_HEIGHT = 25
VGA_MEMORY = 0xB8000
)
type Color uint8
const (
Black Color = 0
Blue Color = 1
Green Color = 2
Cyan Color = 3
Red Color = 4
Magenta Color = 5
Brown Color = 6
LightGray Color = 7
White Color = 15
)
var (
row uint8
column uint8
color uint8
)
//go:export _start
func _start() {
row = 0
column = 0
color = makeColor(White, Blue)
clearScreen()
print("Hello from Go OS!\n")
print("This is a simple OS written in Go\n")
print("Running in VirtualBox!\n")
// 无限循环,防止系统退出
for {
// CPU 休眠
halt()
}
}
func makeColor(fg, bg Color) uint8 {
return uint8(fg) | uint8(bg)<<4
}
func clearScreen() {
vgaBuffer := (*[VGA_WIDTH * VGA_HEIGHT]uint16)(uintptr(VGA_MEMORY))
blank := uint16(' ') | uint16(color)<<8
for i := 0; i < VGA_WIDTH*VGA_HEIGHT; i++ {
vgaBuffer[i] = blank
}
row = 0
column = 0
}
func print(s string) {
for i := 0; i < len(s); i++ {
putChar(s[i])
}
}
func putChar(c byte) {
if c == '\n' {
column = 0
row++
if row >= VGA_HEIGHT {
row = 0
}
return
}
vgaBuffer := (*[VGA_WIDTH * VGA_HEIGHT]uint16)(uintptr(VGA_MEMORY))
index := int(row)*VGA_WIDTH + int(column)
vgaBuffer[index] = uint16(c) | uint16(color)<<8
column++
if column >= VGA_WIDTH {
column = 0
row++
if row >= VGA_HEIGHT {
row = 0
}
}
}
//go:inline
func halt() {
asm("hlt")
}
// 编译器需要的符号
//go:export memset
func memset(ptr uintptr, val byte, size uintptr) {
for i := uintptr(0); i < size; i++ {
*(*byte)(unsafe.Pointer(ptr + i)) = val
}
}
//go:export memcpy
func memcpy(dst, src uintptr, size uintptr) {
for i := uintptr(0); i < size; i++ {
*(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i))
}
} 4. 链接脚本 (linker.ld)
ENTRY(_start)
SECTIONS
{
. = 0x1000;
.text : {
*(.text)
}
.rodata : {
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
} 5. 构建脚本 (build.sh)
#!/bin/bash
# 编译引导加载程序
nasm -f bin boot.asm -o boot.bin
# 编译 Go 内核
tinygo build -o kernel.elf \
-target=none \
-opt=z \
-no-debug \
-panic=trap \
-scheduler=none \
-gc=none \
-ldflags="-T linker.ld" \
kernel.go
# 提取二进制
objcopy -O binary kernel.elf kernel.bin
# 创建磁盘镜像
dd if=/dev/zero of=os.img bs=512 count=2880
dd if=boot.bin of=os.img conv=notrunc
dd if=kernel.bin of=os.img bs=512 seek=1 conv=notrunc
echo "构建完成!使用以下命令测试:"
echo "qemu-system-x86_64 -drive format=raw,file=os.img"
echo "或导入到 VirtualBox" 6. VirtualBox 配置
# 创建虚拟机
VBoxManage createvm --name "GoOS" --register
VBoxManage modifyvm "GoOS" --memory 128 --boot1 disk --nic1 nat
VBoxManage storagectl "GoOS" --name "IDE" --add ide
VBoxManage storageattach "GoOS" --storagectl "IDE" --port 0 \
--device 0 --type hdd --medium os.img 方案二:Go + Multiboot
使用 GRUB 引导(更简单)
// 使用 Multiboot 规范
package main
const MULTIBOOT_HEADER_MAGIC = 0x1BADB002
//go:section .multiboot
var multibootHeader = [...]uint32{
MULTIBOOT_HEADER_MAGIC,
0x00000000,
-(MULTIBOOT_HEADER_MAGIC + 0x00000000),
}
func main() {
// 你的 OS 代码
} 关键注意事项
内存管理:需要自己实现分配器
中断处理:需要设置 IDT
驱动程序:键盘、磁盘等需要自己写
调试困难:建议先用 QEMU 测试
测试运行
# 构建 chmod +x build.sh ./build.sh # QEMU 测试 qemu-system-x86_64 -drive format=raw,file=os.img # VirtualBox 运行 VBoxManage startvm "GoOS"
这是一个最小化示例,实际操作系统需要实现更多功能(内存管理、进程调度、文件系统等)。建议先从简单的"Hello World"开始,逐步添加功能。
网友回复
如何让ai帮我自动在小红书或抖音上自动根据需求截流与潜在客户聊天拉客?
如果用go编写一个在virtualbox中启动的简单操作系统?
go如何搭建一个零信任网络?
如何用python实现一个公网代理访问软件?
如何用go实现一个公网代理访问软件?
如何用python实现一个内网穿透打洞程序,实现内网的80端口暴露到公网上可以访问?
如何用go实现一个内网穿透打洞程序,实现内网的80端口暴露到公网上可以访问?
何为Shadowsocks 代理?
python如何实现类似php的opendir目录相互隔离的fastcgi多租户虚拟空间?
nodejs如何实现类似php的opendir目录相互隔离的fastcgi多租户虚拟空间?


