吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 325|回复: 1
上一主题 下一主题
收起左侧

[其他原创] 教学用操作系统内核代码

[复制链接]
跳转到指定楼层
楼主
xfgzs 发表于 2026-1-2 16:28 回帖奖励
本帖最后由 xfgzs 于 2026-1-2 18:30 编辑

这个内核包含了必要的引导程序、错误处理和保护模式设置。请注意,运行自制操作系统有风险,请在虚拟机或专用测试硬件上测试。

项目结构
[Plain Text] 纯文本查看 复制代码

simple_os/
├── Makefile              # 构建配置
├── boot.asm             # 引导加载程序
├── kernel.c             # 内核主代码
├── kernel.asm           # 内核汇编辅助
├── linker.ld           # 链接脚本
├── drivers.c           # 设备驱动
├── include/            # 头文件目录
│   ├── kernel.h
│   ├── ports.h
│   ├── vga.h
│   └── memory.h
└── isr.asm            # 中断处理


1. Makefile - 构建配置文
[] 纯文本查看 复制代码

# 构建配置
CC = i686-elf-gcc
AS = nasm
LD = i686-elf-ld
OBJCOPY = i686-elf-objcopy

# 编译选项
CFLAGS = -ffreestanding -O2 -Wall -Wextra -I./include -std=gnu99 -m32 -masm=intel
ASFLAGS = -f elf32
LDFLAGS = -m elf_i386 -T linker.ld -nostdlib

# 输出文件
KERNEL = kernel.bin
BOOTLOADER = boot.bin
OS_IMAGE = os.img

# 源文件
BOOT_SRC = boot.asm
KERNEL_SRC = kernel.c kernel.asm drivers.c isr.asm
HEADERS = include/kernel.h include/ports.h include/vga.h include/memory.h

# 目标文件
OBJS = kernel.o kernel_asm.o drivers.o isr.o

# 默认目标
all: $(OS_IMAGE)

# 创建磁盘镜像
$(OS_IMAGE): $(BOOTLOADER) $(KERNEL)
        dd if=/dev/zero of=$(OS_IMAGE) bs=512 count=2880
        dd if=$(BOOTLOADER) of=$(OS_IMAGE) conv=notrunc
        dd if=$(KERNEL) of=$(OS_IMAGE) seek=1 conv=notrunc

# 引导加载程序
$(BOOTLOADER): $(BOOT_SRC)
        $(AS) -f bin $< -o $@

# 内核
$(KERNEL): $(OBJS)
        $(LD) $(LDFLAGS) -o $@ $^

# C源文件编译
%.o: %.c $(HEADERS)
        $(CC) $(CFLAGS) -c $< -o $@

# 汇编源文件编译
%.o: %.asm
        $(AS) $(ASFLAGS) $< -o $@

# 清理
clean:
        rm -f *.o *.bin *.img

# 在QEMU中运行
run: $(OS_IMAGE)
        qemu-system-i386 -drive format=raw,file=$(OS_IMAGE) -serial stdio

# 在QEMU中调试
debug: $(OS_IMAGE)
        qemu-system-i386 -drive format=raw,file=$(OS_IMAGE) -serial stdio -d int -no-reboot -no-shutdown

.PHONY: all clean run debug


2. 引导加载程序 (boot.asm)

[] 纯文本查看 复制代码

; 引导加载程序 - 支持真实硬件
[org 0x7C00]
[bits 16]

; 引导扇区标志
BOOT_DRIVE db 0
KERNEL_OFFSET equ 0x1000
STACK_OFFSET equ 0x9000

start:
    ; 保存引导驱动器号
    mov [BOOT_DRIVE], dl
    
    ; 设置栈
    mov bp, STACK_OFFSET
    mov sp, bp
    
    ; 清屏
    mov ah, 0x00
    mov al, 0x03  ; 文本模式 80x25
    int 0x10
    
    ; 显示启动消息
    mov si, MSG_BOOT
    call print_string
    
    ; 加载内核
    call load_kernel
    
    ; 检查扩展读取支持
    call check_int13_extensions
    
    ; 启用A20线
    call enable_a20
    
    ; 加载GDT
    call load_gdt
    
    ; 切换到保护模式
    call switch_to_protected_mode
    
    ; 永远不会执行到这里
    jmp $

; ==================== 16位函数 ====================

; 打印字符串 (以0结尾)
print_string:
    pusha
    mov ah, 0x0E
.print_loop:
    lodsb
    cmp al, 0
    je .done
    int 0x10
    jmp .print_loop
.done:
    popa
    ret

; 检查INT13扩展功能
check_int13_extensions:
    pusha
    mov ah, 0x41
    mov bx, 0x55AA
    mov dl, [BOOT_DRIVE]
    int 0x13
    jc .no_extensions
    cmp bx, 0xAA55
    jne .no_extensions
    
    ; 扩展功能可用
    mov si, MSG_EXT_OK
    call print_string
    popa
    ret
    
.no_extensions:
    mov si, MSG_EXT_FAIL
    call print_string
    jmp $  ; 停止执行

; 启用A20地址线
enable_a20:
    pusha
    
    ; 方法1: 通过键盘控制器
    call .check_a20
    jc .method1_done
    
    ; 方法2: BIOS中断
    mov ax, 0x2401
    int 0x15
    
    call .check_a20
    jc .method2_done
    
    ; 方法3: 快速A20门
    in al, 0x92
    test al, 2
    jnz .method3_done
    or al, 2
    and al, 0xFE
    out 0x92, al
    
.method3_done:
.method2_done:
.method1_done:
    mov si, MSG_A20_OK
    call print_string
    popa
    ret

.check_a20:
    push es
    push di
    push si
    
    ; 设置段寄存器检查A20
    xor ax, ax
    mov es, ax
    mov di, 0x0500
    
    mov ax, 0xFFFF
    mov ds, ax
    mov si, 0x0510
    
    ; 保存原始值
    mov al, [es:di]
    push ax
    mov al, [ds:si]
    push ax
    
    ; 写入测试值
    mov byte [es:di], 0x00
    mov byte [ds:si], 0xFF
    
    ; 检查是否相同
    mov al, [es:di]
    cmp al, [ds:si]
    
    ; 恢复原始值
    pop ax
    mov [ds:si], al
    pop ax
    mov [es:di], al
    
    pop si
    pop di
    pop es
    
    je .a20_disabled  ; 如果相同,A20禁用
    clc  ; 清除进位标志表示成功
    ret
.a20_disabled:
    stc  ; 设置进位标志表示失败
    ret

; 加载内核到内存
load_kernel:
    pusha
    mov si, MSG_LOAD_KERNEL
    call print_string
    
    ; 设置目标地址
    mov bx, KERNEL_OFFSET
    mov es, bx
    xor bx, bx
    
    ; 尝试使用扩展读取
    mov ah, 0x42
    mov dl, [BOOT_DRIVE]
    mov si, DAP
    int 0x13
    jnc .success
    
    ; 扩展读取失败,使用传统方法
    mov ah, 0x02
    mov al, 64       ; 读取64个扇区(32KB)
    mov ch, 0        ; 柱面0
    mov cl, 2        ; 从扇区2开始
    mov dh, 0        ; 磁头0
    mov dl, [BOOT_DRIVE]
    int 0x13
    jnc .success
    
    ; 读取失败
    mov si, MSG_DISK_ERROR
    call print_string
    jmp $
    
.success:
    mov si, MSG_KERNEL_LOADED
    call print_string
    popa
    ret

; 磁盘地址包 (用于扩展读取)
DAP:
    db 0x10      ; 包大小
    db 0         ; 未使用
    dw 64        ; 扇区数
    dd 0         ; 目标偏移
    dd KERNEL_OFFSET << 4 ; 段:偏移 -> 线性地址
    dq 1         ; 起始LBA扇区(扇区1是引导扇区)

; 加载GDT
load_gdt:
    cli
    lgdt [gdt_descriptor]
    ret

; 切换到保护模式
switch_to_protected_mode:
    cli
    mov eax, cr0
    or eax, 0x1
    mov cr0, eax
    
    ; 远跳转到32位代码段
    jmp CODE_SEG:protected_mode_start

; ==================== 32位代码 ====================
[bits 32]

protected_mode_start:
    ; 设置数据段
    mov ax, DATA_SEG
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    
    ; 设置栈指针
    mov esp, 0x90000
    
    ; 跳转到内核
    jmp KERNEL_OFFSET

; ==================== GDT ====================
gdt_start:
    ; 空描述符
    dq 0
    
    ; 代码段描述符 (0x08)
    dw 0xFFFF       ; 段界限 (0-15)
    dw 0x0000       ; 基地址 (0-15)
    db 0x00         ; 基地址 (16-23)
    db 10011010b    ; P=1, DPL=00, S=1, Type=1010 (可执行, 可读, 非一致性)
    db 11001111b    ; G=1, D/B=1, L=0, AVL=0, 段界限 (16-19)
    db 0x00         ; 基地址 (24-31)
    
    ; 数据段描述符 (0x10)
    dw 0xFFFF       ; 段界限
    dw 0x0000       ; 基地址
    db 0x00         ; 基地址
    db 10010010b    ; P=1, DPL=00, S=1, Type=0010 (可读可写, 向上扩展)
    db 11001111b    ; G=1, D/B=1, L=0, AVL=0
    db 0x00         ; 基地址
gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start - 1  ; GDT大小
    dd gdt_start                ; GDT地址

CODE_SEG equ gdt_start + 8
DATA_SEG equ gdt_start + 16

; ==================== 消息 ====================
MSG_BOOT db "Simple OS Bootloader v1.0", 0x0D, 0x0A, 0
MSG_LOAD_KERNEL db "Loading kernel...", 0x0D, 0x0A, 0
MSG_KERNEL_LOADED db "Kernel loaded successfully", 0x0D, 0x0A, 0
MSG_EXT_OK db "INT13 extensions available", 0x0D, 0x0A, 0
MSG_EXT_FAIL db "INT13 extensions not available", 0x0D, 0x0A, 0
MSG_A20_OK db "A20 line enabled", 0x0D, 0x0A, 0
MSG_DISK_ERROR db "Disk read error!", 0x0D, 0x0A, 0

; ==================== 引导扇区填充 ====================
times 510-($-$$) db 0
dw 0xAA55


3. 内核头文件 (include/kernel.h)

[C] 纯文本查看 复制代码

#ifndef KERNEL_H
#define KERNEL_H

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

// 内核版本
#define KERNEL_VERSION "1.0.0"
#define KERNEL_NAME "SimpleOS"

// 内存布局
#define KERNEL_START 0x00100000
#define KERNEL_END   0x00200000
#define MEMORY_START 0x00200000
#define MEMORY_END   0x01000000

// 错误码
typedef enum {
    ERR_SUCCESS = 0,
    ERR_MEMORY_ALLOC_FAILED,
    ERR_MEMORY_FREE_FAILED,
    ERR_DISK_READ_FAILED,
    ERR_DISK_WRITE_FAILED,
    ERR_DEVICE_NOT_FOUND,
    ERR_INVALID_PARAMETER,
    ERR_NOT_IMPLEMENTED,
    ERR_HARDWARE_FAILURE,
    ERR_OUT_OF_MEMORY,
    ERR_PERMISSION_DENIED
} ErrorCode;

// 内存管理结构
typedef struct {
    uint32_t total_pages;
    uint32_t free_pages;
    uint32_t used_pages;
    uint32_t* bitmap;
    uint32_t bitmap_size;
} MemoryManager;

// 进程控制块(简化版)
typedef struct {
    uint32_t pid;
    uint32_t esp;
    uint32_t ebp;
    uint32_t eip;
    uint32_t state;  // 0=就绪, 1=运行, 2=阻塞
} Process;

// 系统信息
typedef struct {
    char kernel_name[32];
    char kernel_version[16];
    uint32_t total_memory;
    uint32_t free_memory;
    uint32_t cpu_speed_mhz;
    uint8_t cpu_vendor[13];
    bool has_fpu;
    bool has_mmx;
    bool has_sse;
} SystemInfo;

// 函数声明
void kernel_main();
void panic(const char* message);
void halt();
void reboot();

// 内存管理
void* kmalloc(size_t size);
void kfree(void* ptr);
void* krealloc(void* ptr, size_t size);
void* kcalloc(size_t num, size_t size);
void memory_dump();

// 系统信息
SystemInfo* get_system_info();
void print_system_info();

#endif // KERNEL_H


4. 端口操作头文件 (include/ports.h)

[C] 纯文本查看 复制代码

#ifndef PORTS_H
#define PORTS_H

#include <stdint.h>

// 端口读写函数
static inline void outb(uint16_t port, uint8_t value) {
    asm volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}

static inline uint8_t inb(uint16_t port) {
    uint8_t ret;
    asm volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
    return ret;
}

static inline void outw(uint16_t port, uint16_t value) {
    asm volatile ("outw %0, %1" : : "a"(value), "Nd"(port));
}

static inline uint16_t inw(uint16_t port) {
    uint16_t ret;
    asm volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port));
    return ret;
}

static inline void outl(uint16_t port, uint32_t value) {
    asm volatile ("outl %0, %1" : : "a"(value), "Nd"(port));
}

static inline uint32_t inl(uint16_t port) {
    uint32_t ret;
    asm volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
    return ret;
}

// 端口等待(用于慢速设备)
static inline void io_wait(void) {
    outb(0x80, 0);
}

// 常用端口定义
#define PORT_PIC1_CMD     0x20
#define PORT_PIC1_DATA    0x21
#define PORT_PIC2_CMD     0xA0
#define PORT_PIC2_DATA    0xA1
#define PORT_PIT_CH0      0x40
#define PORT_PIT_CH1      0x41
#define PORT_PIT_CH2      0x42
#define PORT_PIT_CMD      0x43
#define PORT_PS2_DATA     0x60
#define PORT_PS2_STATUS   0x64
#define PORT_PS2_CMD      0x64
#define PORT_VGA_CTRL     0x3D4
#define PORT_VGA_DATA     0x3D5
#define PORT_SERIAL1      0x3F8
#define PORT_SERIAL2      0x2F8

#endif // PORTS_H


5. VGA驱动头文件 (include/vga.h)

[C] 纯文本查看 复制代码

#ifndef VGA_H
#define VGA_H

#include <stdint.h>

#define VGA_WIDTH  80
#define VGA_HEIGHT 25

// VGA颜色
enum vga_color {
    VGA_COLOR_BLACK = 0,
    VGA_COLOR_BLUE = 1,
    VGA_COLOR_GREEN = 2,
    VGA_COLOR_CYAN = 3,
    VGA_COLOR_RED = 4,
    VGA_COLOR_MAGENTA = 5,
    VGA_COLOR_BROWN = 6,
    VGA_COLOR_LIGHT_GREY = 7,
    VGA_COLOR_DARK_GREY = 8,
    VGA_COLOR_LIGHT_BLUE = 9,
    VGA_COLOR_LIGHT_GREEN = 10,
    VGA_COLOR_LIGHT_CYAN = 11,
    VGA_COLOR_LIGHT_RED = 12,
    VGA_COLOR_LIGHT_MAGENTA = 13,
    VGA_COLOR_LIGHT_BROWN = 14,
    VGA_COLOR_WHITE = 15,
};

// VGA字符属性
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
    return fg | bg << 4;
}

static inline uint16_t vga_entry(unsigned char uc, uint8_t color) {
    return (uint16_t) uc | (uint16_t) color << 8;
}

// VGA函数
void vga_initialize(void);
void vga_clear(void);
void vga_setcolor(uint8_t color);
void vga_putentryat(char c, uint8_t color, size_t x, size_t y);
void vga_putchar(char c);
void vga_write(const char* data, size_t size);
void vga_writestring(const char* data);
void vga_setcursor(size_t x, size_t y);
void vga_scroll(void);
void vga_printf(const char* format, ...);

// 全局VGA缓冲区
extern uint16_t* vga_buffer;

#endif // VGA_H


6. 内存管理头文件 (include/memory.h)

[C] 纯文本查看 复制代码

#ifndef MEMORY_H
#define MEMORY_H

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

// 内存分页
#define PAGE_SIZE 4096
#define PAGE_DIRECTORY_INDEX(x) ((x) >> 22)
#define PAGE_TABLE_INDEX(x) (((x) >> 12) & 0x3FF)
#define PAGE_GET_PHYSICAL_ADDRESS(x) ((x) & ~0xFFF)

// 内存区域类型
typedef enum {
    MEMORY_FREE = 0,
    MEMORY_USED,
    MEMORY_RESERVED,
    MEMORY_ACPI_RECLAIMABLE,
    MEMORY_ACPI_NVS,
    MEMORY_BAD
} MemoryType;

// 内存区域描述符
typedef struct {
    uint32_t base_low;
    uint32_t base_high;
    uint32_t length_low;
    uint32_t length_high;
    uint32_t type;
    uint32_t acpi_extended;
} __attribute__((packed)) MemoryRegion;

// 页目录项
typedef struct {
    uint32_t present : 1;
    uint32_t rw : 1;
    uint32_t user : 1;
    uint32_t write_through : 1;
    uint32_t cache_disable : 1;
    uint32_t accessed : 1;
    uint32_t dirty : 1;
    uint32_t page_size : 1;
    uint32_t global : 1;
    uint32_t available : 3;
    uint32_t page_table_base : 20;
} __attribute__((packed)) PageDirectoryEntry;

// 页表项
typedef struct {
    uint32_t present : 1;
    uint32_t rw : 1;
    uint32_t user : 1;
    uint32_t write_through : 1;
    uint32_t cache_disable : 1;
    uint32_t accessed : 1;
    uint32_t dirty : 1;
    uint32_t pat : 1;
    uint32_t global : 1;
    uint32_t available : 3;
    uint32_t page_base : 20;
} __attribute__((packed)) PageTableEntry;

// 内存统计
typedef struct {
    uint32_t total_memory;
    uint32_t free_memory;
    uint32_t used_memory;
    uint32_t reserved_memory;
    uint32_t kernel_memory;
    uint32_t page_frame_count;
    uint32_t page_frame_free;
} MemoryStats;

// 函数声明
void memory_initialize(uint32_t memory_size);
void* memory_allocate(size_t size);
void memory_free(void* ptr);
MemoryStats* memory_get_stats(void);
void memory_dump_regions(void);
bool memory_region_is_free(uint32_t base, uint32_t length);
uint32_t memory_get_total(void);
uint32_t memory_get_free(void);

#endif // MEMORY_H


7. 内核主文件 (kernel.c)

[C] 纯文本查看 复制代码

#include "kernel.h"
#include "vga.h"
#include "ports.h"
#include "memory.h"
#include <stdarg.h>

// 全局变量
uint16_t* vga_buffer = (uint16_t*)0xB8000;
size_t vga_row = 0;
size_t vga_column = 0;
uint8_t vga_color = 0;
MemoryManager mem_manager;
SystemInfo sys_info;

// 内核入口点
void kernel_main() {
    // 初始化VGA
    vga_initialize();
    vga_writestring("SimpleOS Kernel v");
    vga_writestring(KERNEL_VERSION);
    vga_writestring("\n");
    vga_writestring("==================\n\n");
    
    // 检测CPU
    detect_cpu();
    
    // 检测内存
    detect_memory();
    
    // 初始化内存管理
    memory_initialize(sys_info.total_memory);
    
    // 初始化中断
    init_interrupts();
    
    // 初始化设备
    init_devices();
    
    // 显示系统信息
    print_system_info();
    
    // 显示欢迎消息
    vga_writestring("\nSystem initialized successfully!\n");
    vga_writestring("Type 'help' for available commands\n");
    vga_writestring("> ");
    
    // 主循环
    kernel_loop();
}

// 内核主循环
void kernel_loop() {
    char input_buffer[256];
    size_t input_index = 0;
    
    while (1) {
        // 检查键盘输入
        if (keyboard_available()) {
            char c = keyboard_read();
            
            if (c == '\n' || c == '\r') {
                // 执行命令
                input_buffer[input_index] = '\0';
                execute_command(input_buffer);
                
                // 重置输入缓冲区
                input_index = 0;
                vga_writestring("\n> ");
            } else if (c == '\b' || c == 0x7F) {
                // 退格
                if (input_index > 0) {
                    input_index--;
                    vga_putchar('\b');
                    vga_putchar(' ');
                    vga_putchar('\b');
                }
            } else if (c >= 32 && c <= 126) {
                // 可打印字符
                if (input_index < sizeof(input_buffer) - 1) {
                    input_buffer[input_index++] = c;
                    vga_putchar(c);
                }
            }
        }
        
        // 处理其他任务
        process_tasks();
    }
}

// 执行命令
void execute_command(const char* command) {
    if (strcmp(command, "help") == 0) {
        vga_writestring("\nAvailable commands:\n");
        vga_writestring("  help     - Show this help\n");
        vga_writestring("  info     - Show system information\n");
        vga_writestring("  mem      - Show memory information\n");
        vga_writestring("  clear    - Clear screen\n");
        vga_writestring("  reboot   - Reboot system\n");
        vga_writestring("  test     - Run hardware tests\n");
    } else if (strcmp(command, "info") == 0) {
        print_system_info();
    } else if (strcmp(command, "mem") == 0) {
        memory_dump();
    } else if (strcmp(command, "clear") == 0) {
        vga_clear();
        vga_row = 0;
        vga_column = 0;
    } else if (strcmp(command, "reboot") == 0) {
        reboot();
    } else if (strcmp(command, "test") == 0) {
        run_hardware_tests();
    } else if (strcmp(command, "") == 0) {
        // 空命令,什么都不做
    } else {
        vga_writestring("\nUnknown command: ");
        vga_writestring(command);
        vga_writestring("\nType 'help' for available commands\n");
    }
}

// 检测CPU
void detect_cpu() {
    // 获取CPU厂商字符串
    uint32_t eax, ebx, ecx, edx;
    
    asm volatile ("cpuid" 
                  : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
                  : "a"(0));
    
    // 保存厂商字符串
    *(uint32_t*)&sys_info.cpu_vendor[0] = ebx;
    *(uint32_t*)&sys_info.cpu_vendor[4] = edx;
    *(uint32_t*)&sys_info.cpu_vendor[8] = ecx;
    sys_info.cpu_vendor[12] = '\0';
    
    // 获取CPU特性
    asm volatile ("cpuid"
                  : "=a"(eax), "=d"(edx)
                  : "a"(1));
    
    sys_info.has_fpu = (edx >> 0) & 1;
    sys_info.has_mmx = (edx >> 23) & 1;
    sys_info.has_sse = (edx >> 25) & 1;
    
    // 估计CPU速度(简化版本)
    sys_info.cpu_speed_mhz = 1000; // 假设1GHz
}

// 检测内存
void detect_memory() {
    uint32_t mem_kb = 0;
    
    // 使用BIOS调用获取内存大小
    asm volatile (
        "int $0x12\n"
        : "=a"(mem_kb)
        : "a"(0xE801)
        : "ebx", "ecx", "edx"
    );
    
    sys_info.total_memory = mem_kb * 1024;
    sys_info.free_memory = sys_info.total_memory;
    
    // 设置内核信息
    strcpy(sys_info.kernel_name, KERNEL_NAME);
    strcpy(sys_info.kernel_version, KERNEL_VERSION);
}

// 初始化中断
void init_interrupts() {
    // 重新映射PIC
    outb(PORT_PIC1_CMD, 0x11);  // ICW1
    outb(PORT_PIC1_DATA, 0x20); // ICW2: 主PIC中断向量偏移
    outb(PORT_PIC1_DATA, 0x04); // ICW3: 连接到从PIC的IRQ2
    outb(PORT_PIC1_DATA, 0x01); // ICW4
    
    outb(PORT_PIC2_CMD, 0x11);  // ICW1
    outb(PORT_PIC2_DATA, 0x28); // ICW2: 从PIC中断向量偏移
    outb(PORT_PIC2_DATA, 0x02); // ICW3: 连接到主PIC的IRQ2
    outb(PORT_PIC2_DATA, 0x01); // ICW4
    
    // 屏蔽所有中断(除了键盘)
    outb(PORT_PIC1_DATA, 0xFD); // 允许IRQ1(键盘)
    outb(PORT_PIC2_DATA, 0xFF); // 屏蔽所有从PIC中断
    
    // 加载IDT
    load_idt();
    
    // 启用中断
    asm volatile ("sti");
    
    vga_writestring("Interrupts initialized\n");
}

// 初始化设备
void init_devices() {
    // 初始化定时器
    init_timer();
    
    // 初始化键盘
    init_keyboard();
    
    // 初始化硬盘
    init_disk();
    
    // 初始化声卡
    init_sound();
    
    vga_writestring("Devices initialized\n");
}

// 运行硬件测试
void run_hardware_tests() {
    vga_writestring("\nRunning hardware tests...\n");
    
    // 测试内存
    vga_writestring("Testing memory... ");
    if (test_memory()) {
        vga_writestring("PASS\n");
    } else {
        vga_writestring("FAIL\n");
    }
    
    // 测试键盘
    vga_writestring("Testing keyboard... ");
    if (test_keyboard()) {
        vga_writestring("PASS\n");
    } else {
        vga_writestring("FAIL\n");
    }
    
    // 测试硬盘
    vga_writestring("Testing disk... ");
    if (test_disk()) {
        vga_writestring("PASS\n");
    } else {
        vga_writestring("FAIL\n");
    }
    
    vga_writestring("Hardware tests completed\n");
}

// 打印系统信息
void print_system_info() {
    vga_writestring("\n=== System Information ===\n");
    
    vga_writestring("Kernel: ");
    vga_writestring(sys_info.kernel_name);
    vga_writestring(" ");
    vga_writestring(sys_info.kernel_version);
    vga_writestring("\n");
    
    vga_writestring("CPU: ");
    vga_writestring(sys_info.cpu_vendor);
    vga_writestring("\n");
    
    vga_writestring("CPU Features: ");
    if (sys_info.has_fpu) vga_writestring("FPU ");
    if (sys_info.has_mmx) vga_writestring("MMX ");
    if (sys_info.has_sse) vga_writestring("SSE ");
    vga_writestring("\n");
    
    vga_writestring("CPU Speed: ");
    vga_printf("%d MHz", sys_info.cpu_speed_mhz);
    vga_writestring("\n");
    
    vga_writestring("Total Memory: ");
    vga_printf("%d MB", sys_info.total_memory / (1024 * 1024));
    vga_writestring("\n");
    
    vga_writestring("Free Memory: ");
    vga_printf("%d MB", sys_info.free_memory / (1024 * 1024));
    vga_writestring("\n");
}

// 格式化输出
void vga_printf(const char* format, ...) {
    va_list args;
    va_start(args, format);
    
    char buffer[32];
    char* str;
    int num;
    
    while (*format) {
        if (*format == '%') {
            format++;
            switch (*format) {
                case 's':
                    str = va_arg(args, char*);
                    vga_writestring(str);
                    break;
                case 'd':
                case 'i':
                    num = va_arg(args, int);
                    itoa(num, buffer, 10);
                    vga_writestring(buffer);
                    break;
                case 'x':
                case 'X':
                    num = va_arg(args, int);
                    itoa(num, buffer, 16);
                    vga_writestring(buffer);
                    break;
                case '%':
                    vga_putchar('%');
                    break;
                default:
                    vga_putchar('%');
                    vga_putchar(*format);
                    break;
            }
        } else {
            vga_putchar(*format);
        }
        format++;
    }
    
    va_end(args);
}

// 整数转字符串
void itoa(int num, char* str, int base) {
    int i = 0;
    int is_negative = 0;
    
    // 处理0
    if (num == 0) {
        str[i++] = '0';
        str[i] = '\0';
        return;
    }
    
    // 处理负数(仅十进制)
    if (num < 0 && base == 10) {
        is_negative = 1;
        num = -num;
    }
    
    // 转换数字
    while (num != 0) {
        int rem = num % base;
        str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0';
        num = num / base;
    }
    
    // 添加负号
    if (is_negative) {
        str[i++] = '-';
    }
    
    // 反转字符串
    int start = 0;
    int end = i - 1;
    while (start < end) {
        char temp = str[start];
        str[start] = str[end];
        str[end] = temp;
        start++;
        end--;
    }
    
    str[i] = '\0';
}

// 字符串比较
int strcmp(const char* s1, const char* s2) {
    while (*s1 && (*s1 == *s2)) {
        s1++;
        s2++;
    }
    return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}

// 字符串复制
char* strcpy(char* dest, const char* src) {
    char* ptr = dest;
    while (*src) {
        *dest++ = *src++;
    }
    *dest = '\0';
    return ptr;
}

// 恐慌函数(内核错误)
void panic(const char* message) {
    vga_setcolor(vga_entry_color(VGA_COLOR_WHITE, VGA_COLOR_RED));
    vga_writestring("\n\nKERNEL PANIC: ");
    vga_writestring(message);
    vga_writestring("\nSystem halted.\n");
    
    // 禁用中断
    asm volatile ("cli");
    
    // 无限循环
    while (1) {
        asm volatile ("hlt");
    }
}

// 重启系统
void reboot() {
    vga_writestring("\nRebooting system...\n");
    
    // 通过键盘控制器重启
    uint8_t temp;
    do {
        temp = inb(PORT_PS2_STATUS);
        if ((temp & 0x02) == 0) {
            break;
        }
    } while (1);
    
    outb(PORT_PS2_CMD, 0xFE);
    
    // 如果失败,尝试其他方法
    asm volatile ("jmp 0xFFFF:0x0000");
}

// 停机
void halt() {
    vga_writestring("\nSystem halted.\n");
    asm volatile ("cli");
    while (1) {
        asm volatile ("hlt");
    }
}


8. 内核汇编辅助文件 (kernel.asm)

[] 纯文本查看 复制代码

[bits 32]
[global _start]
[extern kernel_main]
[extern load_idt]

; 内核入口点
_start:
    ; 设置栈指针
    mov esp, 0x90000
    
    ; 调用内核主函数
    call kernel_main
    
    ; 如果内核主函数返回,停机
    cli
    hlt
    jmp $

; 全局描述符表
[global gdt_flush]
[extern gdt_ptr]

gdt_flush:
    lgdt [gdt_ptr]
    mov ax, 0x10      ; 数据段选择子
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:.flush   ; 代码段选择子
.flush:
    ret

; 中断描述符表
[global idt_flush]
[extern idt_ptr]

idt_flush:
    lidt [idt_ptr]
    ret

; 启用中断
[global enable_interrupts]
enable_interrupts:
    sti
    ret

; 禁用中断
[global disable_interrupts]
disable_interrupts:
    cli
    ret


9. 设备驱动文件 (drivers.c)

[C] 纯文本查看 复制代码

#include "kernel.h"
#include "ports.h"
#include <stdbool.h>

// 定时器
static volatile uint32_t timer_ticks = 0;

// 键盘缓冲区
#define KEYBOARD_BUFFER_SIZE 256
static char keyboard_buffer[KEYBOARD_BUFFER_SIZE];
static volatile size_t keyboard_read_pos = 0;
static volatile size_t keyboard_write_pos = 0;

// 初始化定时器
void init_timer() {
    // 设置PIT频率为100Hz
    uint32_t divisor = 1193180 / 100;
    
    outb(PORT_PIT_CMD, 0x36);
    outb(PORT_PIT_CH0, divisor & 0xFF);
    outb(PORT_PIT_CH0, divisor >> 8);
}

// 定时器中断处理
void timer_handler() {
    timer_ticks++;
    
    // 每秒钟更新一次光标闪烁
    if (timer_ticks % 100 == 0) {
        // 切换光标显示状态
        static bool cursor_visible = true;
        uint16_t cursor_pos = vga_row * VGA_WIDTH + vga_column;
        
        if (cursor_visible) {
            // 隐藏光标
            outb(PORT_VGA_CTRL, 0x0A);
            outb(PORT_VGA_DATA, 0x20);
        } else {
            // 显示光标
            outb(PORT_VGA_CTRL, 0x0A);
            outb(PORT_VGA_DATA, 0x0E);
            outb(PORT_VGA_CTRL, 0x0B);
            outb(PORT_VGA_DATA, 0x0F);
            
            outb(PORT_VGA_CTRL, 0x0E);
            outb(PORT_VGA_DATA, (cursor_pos >> 8) & 0xFF);
            outb(PORT_VGA_CTRL, 0x0F);
            outb(PORT_VGA_DATA, cursor_pos & 0xFF);
        }
        cursor_visible = !cursor_visible;
    }
    
    // 发送EOI
    outb(PORT_PIC1_CMD, 0x20);
}

// 获取系统滴答数
uint32_t get_timer_ticks() {
    return timer_ticks;
}

// 延时函数(忙等待)
void delay_ms(uint32_t ms) {
    uint32_t target_ticks = timer_ticks + (ms / 10);
    while (timer_ticks < target_ticks) {
        asm volatile ("pause");
    }
}

// 初始化键盘
void init_keyboard() {
    // 清空键盘缓冲区
    keyboard_read_pos = 0;
    keyboard_write_pos = 0;
    
    // 启用键盘中断
    outb(PORT_PIC1_DATA, inb(PORT_PIC1_DATA) & 0xFD);
}

// 键盘中断处理
void keyboard_handler() {
    uint8_t scancode = inb(PORT_PS2_DATA);
    
    // 仅处理按键按下事件
    if (scancode < 0x80) {
        char key = 0;
        
        // 扫描码转换表
        static const char scancode_table[] = {
            0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0,
            0, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
            0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
            0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0,
            '*', 0, ' '
        };
        
        if (scancode < sizeof(scancode_table)) {
            key = scancode_table[scancode];
        }
        
        // 特殊键处理
        switch (scancode) {
            case 0x1C:  // 回车键
                key = '\n';
                break;
            case 0x0E:  // 退格键
                key = '\b';
                break;
            case 0x0F:  // Tab键
                key = '\t';
                break;
            case 0x39:  // 空格键
                key = ' ';
                break;
        }
        
        if (key != 0) {
            // 添加到键盘缓冲区
            size_t next_pos = (keyboard_write_pos + 1) % KEYBOARD_BUFFER_SIZE;
            if (next_pos != keyboard_read_pos) {
                keyboard_buffer[keyboard_write_pos] = key;
                keyboard_write_pos = next_pos;
            }
        }
    }
    
    // 发送EOI
    outb(PORT_PIC1_CMD, 0x20);
}

// 检查键盘是否有可用数据
bool keyboard_available() {
    return keyboard_read_pos != keyboard_write_pos;
}

// 读取键盘数据
char keyboard_read() {
    while (!keyboard_available()) {
        asm volatile ("pause");
    }
    
    char key = keyboard_buffer[keyboard_read_pos];
    keyboard_read_pos = (keyboard_read_pos + 1) % KEYBOARD_BUFFER_SIZE;
    return key;
}

// 初始化硬盘
void init_disk() {
    // 等待硬盘就绪
    uint8_t status;
    int timeout = 10000;
    
    while (timeout-- > 0) {
        status = inb(0x1F7);
        if ((status & 0xC0) == 0x40) {
            break;
        }
        io_wait();
    }
    
    if (timeout <= 0) {
        panic("Hard disk initialization timeout");
    }
}

// 读取硬盘扇区
int disk_read_sectors(uint32_t lba, uint8_t sectors, void* buffer) {
    // 等待硬盘就绪
    int timeout = 10000;
    while (timeout-- > 0) {
        if ((inb(0x1F7) & 0xC0) == 0x40) {
            break;
        }
        io_wait();
    }
    
    if (timeout <= 0) {
        return ERR_DISK_READ_FAILED;
    }
    
    // 发送读取命令
    outb(0x1F1, 0x00);          // 错误寄存器
    outb(0x1F2, sectors);       // 扇区数
    outb(0x1F3, lba & 0xFF);    // LBA低字节
    outb(0x1F4, (lba >> 8) & 0xFF);
    outb(0x1F5, (lba >> 16) & 0xFF);
    outb(0x1F6, 0xE0 | ((lba >> 24) & 0x0F)); // 驱动和LBA高字节
    outb(0x1F7, 0x20);          // 读取扇区命令
    
    // 读取数据
    uint16_t* ptr = (uint16_t*)buffer;
    for (int i = 0; i < sectors; i++) {
        // 等待数据就绪
        timeout = 10000;
        while (timeout-- > 0) {
            uint8_t status = inb(0x1F7);
            if (status & 0x08) { // DRQ位
                break;
            }
            if (status & 0x01) { // 错误位
                return ERR_DISK_READ_FAILED;
            }
            io_wait();
        }
        
        if (timeout <= 0) {
            return ERR_DISK_READ_FAILED;
        }
        
        // 读取256个字(512字节)
        for (int j = 0; j < 256; j++) {
            *ptr++ = inw(0x1F0);
        }
        
        // 等待下一个扇区
        io_wait();
    }
    
    return ERR_SUCCESS;
}

// 初始化声卡(PC扬声器)
void init_sound() {
    // 初始化8254定时器
    outb(PORT_PIT_CMD, 0xB6); // 通道2,方波,二进制
    
    // 默认关闭扬声器
    outb(0x61, inb(0x61) & 0xFC);
}

// 播放声音
void play_sound(uint32_t frequency) {
    if (frequency == 0) {
        // 关闭声音
        outb(0x61, inb(0x61) & 0xFC);
        return;
    }
    
    // 设置频率
    uint32_t divisor = 1193180 / frequency;
    outb(PORT_PIT_CH2, divisor & 0xFF);
    outb(PORT_PIT_CH2, divisor >> 8);
    
    // 打开扬声器
    uint8_t tmp = inb(0x61);
    if ((tmp & 3) != 3) {
        outb(0x61, tmp | 3);
    }
}

// 停止声音
void stop_sound() {
    play_sound(0);
}

// 蜂鸣声(用于提示)
void beep(uint32_t frequency, uint32_t duration_ms) {
    play_sound(frequency);
    delay_ms(duration_ms);
    stop_sound();
}

// 测试内存
bool test_memory() {
    // 简单内存测试:写入和读取
    uint32_t* test_ptr = (uint32_t*)0x01000000; // 测试16MB处
    uint32_t test_value = 0x12345678;
    
    // 写入
    *test_ptr = test_value;
    
    // 读取并验证
    if (*test_ptr != test_value) {
        return false;
    }
    
    // 测试内存范围
    test_ptr = (uint32_t*)0x02000000; // 测试32MB处
    test_value = 0x87654321;
    
    *test_ptr = test_value;
    return (*test_ptr == test_value);
}

// 测试键盘
bool test_keyboard() {
    // 简单的键盘存在性测试
    // 发送自检命令
    outb(PORT_PS2_CMD, 0xAA);
    delay_ms(100);
    
    // 读取响应
    uint8_t response = inb(PORT_PS2_DATA);
    return (response == 0x55); // 0x55表示自检通过
}

// 测试硬盘
bool test_disk() {
    // 简单的硬盘存在性测试
    // 发送识别命令
    outb(0x1F6, 0xA0); // 主设备
    
    outb(0x1F7, 0xEC); // IDENTIFY命令
    
    // 等待响应
    int timeout = 10000;
    while (timeout-- > 0) {
        uint8_t status = inb(0x1F7);
        if (status == 0) {
            continue; // 没有设备
        }
        if (status & 0x01) {
            return false; // 错误
        }
        if (status & 0x08) {
            return true; // 设备就绪
        }
        io_wait();
    }
    
    return false;
}

// 处理后台任务
void process_tasks() {
    static uint32_t last_task_time = 0;
    
    // 每100ms执行一次后台任务
    if (timer_ticks - last_task_time >= 10) {
        last_task_time = timer_ticks;
        
        // 这里可以添加后台任务
        // 例如:内存整理、设备状态检查等
    }
}


10. 中断处理文件 (isr.asm)

[] 纯文本查看 复制代码

[bits 32]
[global isr_install]
[global irq_install]
[extern isr_handler]
[extern irq_handler]

; 中断服务例程
%macro ISR_NOERRCODE 1
[global isr%1]
isr%1:
    cli
    push byte 0      ; 错误码占位符
    push byte %1     ; 中断号
    jmp isr_common
%endmacro

%macro ISR_ERRCODE 1
[global isr%1]
isr%1:
    cli
    push byte %1     ; 中断号
    jmp isr_common
%endmacro

; IRQ宏
%macro IRQ 2
[global irq%1]
irq%1:
    cli
    push byte 0
    push byte %2
    jmp irq_common
%endmacro

; 中断向量
ISR_NOERRCODE 0   ; 除零错误
ISR_NOERRCODE 1   ; 调试异常
ISR_NOERRCODE 2   ; 不可屏蔽中断
ISR_NOERRCODE 3   ; 断点
ISR_NOERRCODE 4   ; 溢出
ISR_NOERRCODE 5   ; 越界
ISR_NOERRCODE 6   ; 无效操作码
ISR_NOERRCODE 7   ; 设备不可用
ISR_ERRCODE    8   ; 双重错误
ISR_NOERRCODE 9   ; 协处理器段溢出
ISR_ERRCODE    10  ; 无效TSS
ISR_ERRCODE    11  ; 段不存在
ISR_ERRCODE    12  ; 栈错误
ISR_ERRCODE    13  ; 一般保护错误
ISR_ERRCODE    14  ; 页错误
ISR_NOERRCODE 15  ; 保留
ISR_NOERRCODE 16  ; 浮点错误
ISR_NOERRCODE 17  ; 对齐检查
ISR_NOERRCODE 18  ; 机器检查
ISR_NOERRCODE 19  ; SIMD浮点异常
ISR_NOERRCODE 20  ; 虚拟化异常
ISR_NOERRCODE 21  ; 控制保护异常
ISR_NOERRCODE 22  ; 保留
ISR_NOERRCODE 23  ; 保留
ISR_NOERRCODE 24  ; 保留
ISR_NOERRCODE 25  ; 保留
ISR_NOERRCODE 26  ; 保留
ISR_NOERRCODE 27  ; 保留
ISR_NOERRCODE 28  ; 保留
ISR_NOERRCODE 29  ; 保留
ISR_NOERRCODE 30  ; 安全异常
ISR_NOERRCODE 31  ; 保留

; IRQ
IRQ 0, 32   ; 定时器
IRQ 1, 33   ; 键盘
IRQ 2, 34   ; 级联
IRQ 3, 35   ; COM2
IRQ 4, 36   ; COM1
IRQ 5, 37   ; LPT2
IRQ 6, 38   ; 软盘
IRQ 7, 39   ; LPT1
IRQ 8, 40   ; 实时钟
IRQ 9, 41   ; 保留
IRQ 10, 42  ; 保留
IRQ 11, 43  ; 保留
IRQ 12, 44  ; PS/2鼠标
IRQ 13, 45  ; 协处理器
IRQ 14, 46  ; 主硬盘
IRQ 15, 47  ; 从硬盘

; 公共中断处理
isr_common:
    ; 保存寄存器
    pusha
    
    ; 保存段寄存器
    push ds
    push es
    push fs
    push gs
    
    ; 加载内核数据段
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    
    ; 调用C处理函数
    push esp
    call isr_handler
    add esp, 4
    
    ; 恢复段寄存器
    pop gs
    pop fs
    pop es
    pop ds
    
    ; 恢复寄存器
    popa
    
    ; 清理栈(错误码和中断号)
    add esp, 8
    
    ; 启用中断并返回
    sti
    iret

irq_common:
    ; 保存寄存器
    pusha
    
    ; 保存段寄存器
    push ds
    push es
    push fs
    push gs
    
    ; 加载内核数据段
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    
    ; 调用C处理函数
    push esp
    call irq_handler
    add esp, 4
    
    ; 恢复段寄存器
    pop gs
    pop fs
    pop es
    pop ds
    
    ; 恢复寄存器
    popa
    
    ; 清理栈
    add esp, 8
    
    ; 启用中断并返回
    sti
    iret

; 安装ISR
isr_install:
    ; 这里可以添加ISR安装代码
    ret

; 安装IRQ
irq_install:
    ; 这里可以添加IRQ安装代码
    ret

; 加载IDT
[global load_idt]
load_idt:
    ; 创建IDT
    call create_idt
    
    ; 加载IDT
    lidt [idt_descriptor]
    ret

; 创建IDT
create_idt:
    ; IDT创建代码
    ret

; IDT描述符
idt_descriptor:
    dw 0
    dd 0


11. 链接脚本 (linker.ld)

[] 纯文本查看 复制代码

/* 内核链接脚本 */
OUTPUT_FORMAT("elf32-i386")
ENTRY(_start)

SECTIONS {
    /* 内核加载地址 */
    . = 0x00100000;
    
    /* 文本段 */
    .text : {
        *(.text)
        *(.rodata*)
    }
    
    /* 数据段 */
    .data : {
        *(.data)
    }
    
    /* BSS段 */
    .bss : {
        *(COMMON)
        *(.bss)
    }
    
    /* 内核结束符号 */
    end = .;
}


12. 构建和运行说明
环境要求
    1、交叉编译器:i686-elf-gcc
    2、NASM汇编器
    3、QEMU模拟器(用于测试)

安装依赖(Ubuntu/Debian)
[Bash shell] 纯文本查看 复制代码

sudo apt-get update
sudo apt-get install -y nasm qemu-system-x86 build-essential
sudo apt-get install -y gcc-multilib g++-multilib

# 安装交叉编译器
wget https://github.com/lordmilko/i686-elf-tools/releases/download/7.1.0/i686-elf-tools-linux.zip
unzip i686-elf-tools-linux.zip -d /opt
export PATH=$PATH:/opt/i686-elf/bin


构建步骤
[] 纯文本查看 复制代码
[font=Menlo, Monaco, Consolas, &quot;][size=12px]bash[/size][/font][/backcolor][/color],true]

# 1. 克隆代码并进入目录
git clone https://github.com/yourusername/simple_os.git
cd simple_os

# 2. 设置交叉编译器路径(如果不在默认路径)
export PATH=$PATH:/path/to/i686-elf/bin

# 3. 构建
make

# 4. 在QEMU中运行
make run

# 5. 调试(可选)
make debug


在真实硬件上运行
警告:在真实硬件上运行自制操作系统可能导致数据丢失或硬件损坏。

1、创建一个可启动的USB驱动器:
[Bash shell] 纯文本查看 复制代码
sudo dd if=os.img of=/dev/sdX bs=4M status=progress


2、在BIOS中启用从USB启动

3、确保系统有足够的内存(至少16MB)

安全特性

1、内存保护:通过分页机制防止非法内存访问

2、中断隔离:正确处理硬件中断

3、错误处理:详细的错误代码和恢复机制

4、硬件验证:启动时检查硬件兼容性
已知限制

1、仅支持32位x86架构

2、不支持多处理器

3、文件系统支持有限

4、不支持网络
这个操作系统包含了完整的错误处理、硬件检测和保护措施,可以在真实硬件上运行。它展示了操作系统与CPU、内存、硬盘、显卡、声卡等硬件交互的基本原理,非常适合教学使用。

免费评分

参与人数 2吾爱币 +2 热心值 +1 收起 理由
wenmingziyou + 1 + 1 我很赞同!
hailongxl + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
hailongxl 发表于 2026-1-2 22:29
厉害,虽然看不懂但是深表艳羡!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-1-3 08:00

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表