寒假学习笔记1.19

一、 操作系统内核基础

  1. 内核架构与引导过程
    引导加载器(Bootloader)
    python
    class Bootloader:
    def init(self):
    self.boot_sector_size = 512 # 传统MBR大小
    self.boot_signature = 0xAA55 # 引导扇区签名
    self.kernel_entry_point = None

    def load_mbr(self, disk_image):
    """模拟BIOS加载MBR"""
    # 检查引导签名
    if disk_image[510] != 0x55 or disk_image[511] != 0xAA:
    raise BootError("无效的引导扇区签名")

     # 读取引导代码
     boot_code = disk_image[:446]
     
     # 读取分区表(简化,只处理一个活动分区)
     partition_table = disk_image[446:510]
     active_partition = None
     
     for i in range(0, len(partition_table), 16):
         entry = partition_table[i:i+16]
         if entry[0] == 0x80:  # 活动分区
             active_partition = {
                 'bootable': True,
                 'start_lba': int.from_bytes(entry[8:12], 'little'),
                 'sector_count': int.from_bytes(entry[12:16], 'little')
             }
             break
     
     if not active_partition:
         raise BootError("未找到活动分区")
     
     return active_partition
    

    def load_kernel(self, disk_image, start_lba, sector_count):
    """加载内核到内存"""
    # 计算内核在磁盘映像中的位置
    sector_size = 512
    kernel_offset = start_lba * sector_size
    kernel_size = sector_count * sector_size

     if kernel_offset + kernel_size > len(disk_image):
         raise BootError("内核超出磁盘范围")
     
     # 读取内核代码
     kernel_code = disk_image[kernel_offset:kernel_offset + kernel_size]
     
     # 解析内核头部
     kernel_header = self.parse_kernel_header(kernel_code)
     
     # 加载到内存
     load_address = kernel_header['load_address']
     code_size = kernel_header['code_size']
     entry_point = kernel_header['entry_point']
     
     # 将内核代码复制到内存
     for i in range(min(code_size, len(kernel_code))):
         memory.write_byte(load_address + i, kernel_code[i])
     
     self.kernel_entry_point = entry_point
     return entry_point
    

    def parse_kernel_header(self, kernel_code):
    """解析内核头部信息"""
    # 假设内核头部格式:
    # 0-3: 魔数 "KRNL"
    # 4-7: 入口点
    # 8-11: 加载地址
    # 12-15: 代码大小
    # 16-: 内核代码

     magic = kernel_code[0:4].decode('ascii', errors='ignore')
     if magic != 'KRNL':
         raise BootError("无效的内核魔数")
     
     return {
         'magic': magic,
         'entry_point': int.from_bytes(kernel_code[4:8], 'little'),
         'load_address': int.from_bytes(kernel_code[8:12], 'little'),
         'code_size': int.from_bytes(kernel_code[12:16], 'little')
     }
    

    def execute(self):
    """跳转到内核入口点"""
    if self.kernel_entry_point is None:
    raise BootError("内核未加载")

     # 设置CPU状态
     cpu.registers['CS'] = 0x08  # 内核代码段选择子
     cpu.registers['DS'] = 0x10  # 内核数据段选择子
     cpu.registers['SS'] = 0x10  # 内核堆栈段选择子
     cpu.registers['ESP'] = 0x90000  # 内核栈顶
     cpu.registers['EIP'] = self.kernel_entry_point
     
     # 开启保护模式(简化)
     cpu.cr0 = 0x80000001  # 设置PE位和PG位
    
  2. 全局描述符表(GDT)与保护模式
    python
    class GlobalDescriptorTable:
    def init(self):
    self.gdt = []
    self.gdtr = {'base': 0, 'limit': 0}
    self.current_index = 0

     # 添加空描述符(索引0)
     self.add_descriptor(0, 0, 0, 0)
     
     # 内核代码段
     self.kernel_code_segment = self.add_descriptor(
         base=0x00000000,
         limit=0xFFFFFFFF,
         access=0x9A,  # 可执行,可读,DPL=0
         flags=0xCF    # 粒度=4KB,32位
     )
     
     # 内核数据段
     self.kernel_data_segment = self.add_descriptor(
         base=0x00000000,
         limit=0xFFFFFFFF,
         access=0x92,  # 可读可写,DPL=0
         flags=0xCF
     )
     
     # 用户代码段
     self.user_code_segment = self.add_descriptor(
         base=0x00000000,
         limit=0xFFFFFFFF,
         access=0xFA,  # 可执行,可读,DPL=3
         flags=0xCF
     )
     
     # 用户数据段
     self.user_data_segment = self.add_descriptor(
         base=0x00000000,
         limit=0xFFFFFFFF,
         access=0xF2,  # 可读可写,DPL=3
         flags=0xCF
     )
     
     # 任务状态段(TSS)
     self.tss_segment = None
    

    def add_descriptor(self, base, limit, access, flags):
    """添加描述符到GDT"""
    descriptor = GDTDescriptor()
    descriptor.base = base
    descriptor.limit = limit
    descriptor.access = access
    descriptor.flags = flags

     self.gdt.append(descriptor)
     self.current_index += 1
     
     return (self.current_index - 1) * 8  # 返回选择子
    

    def setup_tss(self, tss_address):
    """设置任务状态段"""
    self.tss_segment = self.add_descriptor(
    base=tss_address,
    limit=103, # TSS大小
    access=0x89, # 32位TSS,DPL=0
    flags=0x00
    )

    def load_gdtr(self):
    """加载GDTR寄存器"""
    self.gdtr['base'] = id(self.gdt) # 简化:用ID作为地址
    self.gdtr['limit'] = len(self.gdt) * 8 - 1

class GDTDescriptor:
"""GDT描述符"""
def init(self):
self.base = 0
self.limit = 0
self.access = 0
self.flags = 0

def encode(self):
    """编码为8字节"""
    # 编码规则:
    # 字节0-1: limit低16位
    # 字节2-4: base低24位
    # 字节5: access字节
    # 字节6-7: limit高4位 + flags低4位 + base高8位
    
    encoded = bytearray(8)
    
    # limit低16位
    encoded[0] = self.limit & 0xFF
    encoded[1] = (self.limit >> 8) & 0xFF
    
    # base低24位
    encoded[2] = self.base & 0xFF
    encoded[3] = (self.base >> 8) & 0xFF
    encoded[4] = (self.base >> 16) & 0xFF
    
    # access字节
    encoded[5] = self.access
    
    # limit高4位 + flags低4位
    encoded[6] = ((self.limit >> 16) & 0x0F) | ((self.flags << 4) & 0xF0)
    
    # base高8位
    encoded[7] = (self.base >> 24) & 0xFF
    
    return bytes(encoded)

二、 进程管理与调度

  1. 进程控制块扩展
    python
    class ProcessControlBlock:
    def init(self, pid, name, priority=1):
    self.pid = pid
    self.name = name
    self.priority = priority
    self.state = 'NEW' # NEW, READY, RUNNING, BLOCKED, TERMINATED

     # 寄存器上下文
     self.context = {
         'eax': 0, 'ebx': 0, 'ecx': 0, 'edx': 0,
         'esi': 0, 'edi': 0, 'ebp': 0, 'esp': 0,
         'eip': 0, 'eflags': 0x202,  # 中断启用
         'cs': 0x1B,  # 用户代码段选择子 (DPL=3)
         'ds': 0x23,  # 用户数据段选择子 (DPL=3)
         'es': 0x23,
         'fs': 0x23,
         'gs': 0x23,
         'ss': 0x23,
     }
     
     # 内存信息
     self.page_directory = None
     self.memory_pages = []  # 分配的物理页列表
     
     # 文件描述符
     self.file_descriptors = [None] * 20  # 文件描述符表
     self.file_descriptors[0] = stdin   # 标准输入
     self.file_descriptors[1] = stdout  # 标准输出
     self.file_descriptors[2] = stderr  # 标准错误
     
     # 进程关系
     self.parent_pid = None
     self.children = []
     self.exit_code = None
     
     # 资源使用
     self.cpu_time = 0
     self.memory_usage = 0
     self.start_time = time.time()
     
     # 信号处理
     self.signal_handlers = {}
     self.pending_signals = []
     
     # 工作目录
     self.working_directory = '/'
     
     # 用户和组
     self.uid = 0  # root用户
     self.gid = 0
     self.euid = 0  # 有效用户ID
     
     # 能力集
     self.capabilities = set()
    
  2. 调度器扩展
    python
    class Scheduler:
    def init(self):
    self.processes = {} # pid -> PCB
    self.ready_queue = [] # 就绪队列
    self.blocked_queue = [] # 阻塞队列
    self.current_pid = None
    self.next_pid = 1000 # 从1000开始分配PID

     # 调度策略
     self.scheduler_policy = 'RR'  # Round Robin
     self.time_slice = 100  # 时间片(毫秒)
     self.ticks = 0
     
     # 多级反馈队列
     self.multi_level_queues = {
         0: [],  # 最高优先级,时间片最短
         1: [],  # 中等优先级
         2: [],  # 最低优先级,时间片最长
     }
     self.priority_time_slices = {0: 50, 1: 100, 2: 200}
     
     # 统计信息
     self.context_switches = 0
     self.total_processes = 0
     self.average_wait_time = 0
    

    def create_process(self, program_path, name=None, priority=1):
    """创建新进程"""
    pid = self.next_pid
    self.next_pid += 1

     if name is None:
         name = f"process_{pid}"
     
     # 创建PCB
     pcb = ProcessControlBlock(pid, name, priority)
     
     # 加载程序到内存
     self.load_program(pcb, program_path)
     
     # 设置初始上下文
     pcb.context['eip'] = pcb.entry_point
     pcb.context['esp'] = pcb.stack_top
     
     # 添加到就绪队列
     self.processes[pid] = pcb
     self.ready_queue.append(pcb)
     
     # 更新统计
     self.total_processes += 1
     
     return pid
    

    def load_program(self, pcb, program_path):
    """加载程序到进程地址空间"""
    # 读取可执行文件
    with open(program_path, 'rb') as f:
    exec_data = f.read()

     # 解析ELF头部(简化)
     if exec_data[0:4] != b'\x7fELF':
         raise LoadError("不是有效的ELF文件")
     
     # 分配内存页
     code_pages = self.allocate_pages(pcb, 4)  # 分配4页用于代码
     data_pages = self.allocate_pages(pcb, 2)  # 分配2页用于数据
     stack_pages = self.allocate_pages(pcb, 1)  # 分配1页用于栈
     
     # 设置入口点和栈顶
     pcb.entry_point = 0x08048000  # Linux默认的ELF入口地址
     pcb.stack_top = 0xC0000000 - 4  # 栈顶(向下生长)
     
     # 复制代码和数据
     self.copy_to_user_space(pcb, pcb.entry_point, exec_data)
    

    def schedule(self):
    """调度下一个进程"""
    if not self.ready_queue and not self.multi_level_queues[0]:
    return None

     # 根据调度策略选择下一个进程
     if self.scheduler_policy == 'RR':
         return self.round_robin_schedule()
     elif self.scheduler_policy == 'MLFQ':
         return self.mlfq_schedule()
     elif self.scheduler_policy == 'PRIORITY':
         return self.priority_schedule()
     else:
         return self.round_robin_schedule()
    

    def round_robin_schedule(self):
    """轮转调度"""
    if not self.ready_queue:
    return None

     # 保存当前进程
     if self.current_pid and self.current_pid in self.processes:
         current_pcb = self.processes[self.current_pid]
         if current_pcb.state == 'RUNNING':
             current_pcb.state = 'READY'
             self.ready_queue.append(current_pcb)
     
     # 选择下一个进程
     next_pcb = self.ready_queue.pop(0)
     next_pcb.state = 'RUNNING'
     self.current_pid = next_pcb.pid
     
     # 更新统计
     self.context_switches += 1
     next_pcb.cpu_time += self.time_slice
     
     return next_pcb
    

    def mlfq_schedule(self):
    """多级反馈队列调度"""
    # 检查最高优先级队列
    for level in range(3):
    if self.multi_level_queues[level]:
    # 保存当前进程
    if self.current_pid and self.current_pid in self.processes:
    current_pcb = self.processes[self.current_pid]
    if current_pcb.state == 'RUNNING':
    # 如果进程用完了时间片,降低优先级
    if current_pcb.remaining_time <= 0:
    current_pcb.priority = min(current_pcb.priority + 1, 2)
    current_pcb.state = 'READY'
    self.multi_level_queues[current_pcb.priority].append(current_pcb)

             # 选择下一个进程
             next_pcb = self.multi_level_queues[level].pop(0)
             next_pcb.state = 'RUNNING'
             next_pcb.remaining_time = self.priority_time_slices[level]
             self.current_pid = next_pcb.pid
             
             self.context_switches += 1
             return next_pcb
     
     return None
    

    def timer_tick(self):
    """时钟中断处理"""
    self.ticks += 1

     # 更新当前进程的时间片
     if self.current_pid and self.current_pid in self.processes:
         pcb = self.processes[self.current_pid]
         pcb.remaining_time -= 1
         
         # 如果时间片用完,强制调度
         if pcb.remaining_time <= 0:
             self.schedule()
    

    def send_signal(self, pid, signal):
    """向进程发送信号"""
    if pid not in self.processes:
    return False

     pcb = self.processes[pid]
     pcb.pending_signals.append(signal)
     
     # 如果进程被阻塞,尝试唤醒
     if pcb.state == 'BLOCKED' and signal in [signal.SIGCONT, signal.SIGUSR1]:
         self.unblock_process(pcb)
     
     return True
    
  3. 虚拟内存管理
    python
    class VirtualMemoryManager:
    def init(self):
    # 页表结构
    self.page_size = 4096 # 4KB页
    self.page_directory = {} # 页目录
    self.page_tables = {} # 页表

     # 物理内存管理
     self.physical_pages = []  # 物理页帧列表
     self.free_pages = []      # 空闲页帧
     self.allocated_pages = {}  # pid -> 页帧列表
     
     # 页表缓存(TLB)
     self.tlb = {}
     self.tlb_hits = 0
     self.tlb_misses = 0
     
     # 页面置换算法
     self.page_replacement_algorithm = 'LRU'  # LRU, FIFO, CLOCK
    

    def init_memory(self, total_memory):
    """初始化内存"""
    total_pages = total_memory // self.page_size
    self.physical_pages = [None] * total_pages # None表示空闲

     # 初始化空闲页列表
     self.free_pages = list(range(total_pages))
     
     # 分配内核空间
     kernel_pages = 16  # 内核使用16个页
     for i in range(kernel_pages):
         if self.free_pages:
             page_frame = self.free_pages.pop(0)
             self.physical_pages[page_frame] = 'KERNEL'
     
     # 设置内核页表
     self.setup_kernel_page_table()
    

    def setup_kernel_page_table(self):
    """设置内核页表"""
    # 内核空间:0x80000000以上
    kernel_base = 0x80000000

     for i in range(1024):  # 1MB内核空间
         virtual_address = kernel_base + i * self.page_size
         physical_address = i * self.page_size  # 恒等映射
         
         self.map_page(0, virtual_address, physical_address, 
                      is_kernel=True, writable=True, executable=True)
    

    def create_address_space(self, pid):
    """为进程创建地址空间"""
    if pid not in self.page_directory:
    # 创建页目录
    self.page_directory[pid] = {}

         # 分配页目录自身的页
         pd_page = self.allocate_physical_page()
         self.page_directory[pid]['_pd_page'] = pd_page
         
         # 复制内核映射
         self.copy_kernel_mappings(pid)
    

    def map_page(self, pid, virtual_addr, physical_addr,
    is_kernel=False, writable=True, executable=False, user=True):
    """映射虚拟页到物理页"""
    # 计算页目录索引和页表索引
    pde_index = (virtual_addr >> 22) & 0x3FF # 10位
    pte_index = (virtual_addr >> 12) & 0x3FF # 10位
    offset = virtual_addr & 0xFFF # 12位

     # 获取或创建页表
     if pid not in self.page_tables:
         self.page_tables[pid] = {}
     
     if pde_index not in self.page_tables[pid]:
         # 分配新页表
         pt_page = self.allocate_physical_page()
         self.page_tables[pid][pde_index] = {
             'page_frame': pt_page,
             'entries': [None] * 1024
         }
     
     # 创建页表项
     pte = PageTableEntry()
     pte.present = 1
     pte.writable = 1 if writable else 0
     pte.user = 1 if user else 0
     pte.executable = 1 if executable else 0
     pte.page_frame = physical_addr // self.page_size
     
     # 存储页表项
     self.page_tables[pid][pde_index]['entries'][pte_index] = pte
     
     # 更新TLB
     tlb_key = (pid, virtual_addr >> 12)  # 按页对齐
     self.tlb[tlb_key] = physical_addr
    

    def translate_address(self, pid, virtual_addr):
    """地址转换(虚拟到物理)"""
    # 检查TLB
    tlb_key = (pid, virtual_addr >> 12)
    if tlb_key in self.tlb:
    self.tlb_hits += 1
    physical_base = self.tlb[tlb_key]
    return physical_base + (virtual_addr & 0xFFF)

     self.tlb_misses += 1
     
     # 正常页表查找
     pde_index = (virtual_addr >> 22) & 0x3FF
     pte_index = (virtual_addr >> 12) & 0x3FF
     offset = virtual_addr & 0xFFF
     
     if pid not in self.page_tables or pde_index not in self.page_tables[pid]:
         raise PageFaultError(f"页目录不存在: PID={pid}, PDE={pde_index}")
     
     pte = self.page_tables[pid][pde_index]['entries'][pte_index]
     if pte is None or not pte.present:
         raise PageFaultError(f"页面不存在: PID={pid}, VA=0x{virtual_addr:08X}")
     
     physical_base = pte.page_frame * self.page_size
     physical_addr = physical_base + offset
     
     # 更新TLB
     self.tlb[tlb_key] = physical_base
     
     return physical_addr
    

    def handle_page_fault(self, pid, virtual_addr, error_code):
    """处理页错误"""
    # 检查是否是写保护错误
    is_write = (error_code & 0x02) != 0
    is_user = (error_code & 0x04) != 0

     # 分配新物理页
     physical_page = self.allocate_physical_page()
     if physical_page is None:
         # 需要页面置换
         physical_page = self.page_replacement()
     
     # 清零新页面
     self.zero_page(physical_page)
     
     # 建立映射
     self.map_page(pid, virtual_addr, physical_page, 
                  user=is_user, writable=True)
     
     return True
    

    def page_replacement(self):
    """页面置换算法"""
    if self.page_replacement_algorithm == 'LRU':
    return self.lru_replacement()
    elif self.page_replacement_algorithm == 'FIFO':
    return self.fifo_replacement()
    elif self.page_replacement_algorithm == 'CLOCK':
    return self.clock_replacement()
    else:
    return self.lru_replacement()

    def lru_replacement(self):
    """LRU页面置换"""
    # 找到最近最少使用的页面
    lru_page = None
    lru_time = float('inf')

     for pid in self.page_tables:
         for pde_index in self.page_tables[pid]:
             pt_info = self.page_tables[pid][pde_index]
             for pte_index, pte in enumerate(pt_info['entries']):
                 if pte and pte.present and pte.recently_used:
                     if pte.last_access_time < lru_time:
                         lru_time = pte.last_access_time
                         lru_page = (pid, pde_index, pte_index, pte)
     
     if lru_page:
         pid, pde_index, pte_index, pte = lru_page
         # 写回脏页
         if pte.dirty:
             self.write_back_page(pid, pte.page_frame)
         
         # 清除映射
         pte.present = 0
         freed_page = pte.page_frame
         
         # 添加到空闲列表
         self.free_pages.append(freed_page)
         
         return freed_page
     
     return None
    

class PageTableEntry:
"""页表项"""
def init(self):
self.present = 0 # 页面是否在内存中
self.writable = 0 # 是否可写
self.user = 0 # 用户模式访问
self.executable = 0 # 是否可执行
self.dirty = 0 # 是否被修改
self.accessed = 0 # 是否被访问
self.recently_used = 0 # 最近使用位(用于clock算法)
self.page_frame = 0 # 物理页帧号
self.last_access_time = 0 # 最后访问时间
三、 文件系统实现

  1. 虚拟文件系统(VFS)
    python
    class VirtualFileSystem:
    def init(self):
    self.root_fs = None
    self.mounted_fs = {} # 挂载点 -> 文件系统
    self.open_files = {} # 文件描述符 -> 文件对象
    self.next_fd = 3 # 0,1,2已被标准流占用

     # 文件系统类型注册
     self.fs_types = {
         'ext2': Ext2FileSystem,
         'fat32': FAT32FileSystem,
         'tmpfs': TmpFileSystem,
         'procfs': ProcFileSystem,
     }
    

    def mount(self, source, target, fs_type, options=None):
    """挂载文件系统"""
    if target in self.mounted_fs:
    raise MountError(f"挂载点 {target} 已在使用")

     if fs_type not in self.fs_types:
         raise MountError(f"不支持的文件系统类型: {fs_type}")
     
     # 创建文件系统实例
     fs_class = self.fs_types[fs_type]
     fs_instance = fs_class(source, options)
     
     # 挂载
     self.mounted_fs[target] = fs_instance
     
     # 如果是根文件系统
     if target == '/':
         self.root_fs = fs_instance
     
     return True
    

    def open(self, pathname, flags, mode=0o666):
    """打开文件"""
    # 解析路径
    fs, real_path = self.resolve_path(pathname)
    if fs is None:
    raise FileNotFoundError(f"找不到文件: {pathname}")

     # 打开文件
     file_obj = fs.open(real_path, flags, mode)
     
     # 分配文件描述符
     fd = self.next_fd
     self.next_fd += 1
     
     self.open_files[fd] = {
         'file': file_obj,
         'path': pathname,
         'flags': flags,
         'position': 0,
         'fs': fs
     }
     
     return fd
    

    def read(self, fd, size):
    """从文件读取数据"""
    if fd not in self.open_files:
    raise BadFileDescriptorError(f"无效的文件描述符: {fd}")

     file_info = self.open_files[fd]
     file_obj = file_info['file']
     position = file_info['position']
     
     # 检查访问权限
     if not (file_info['flags'] & os.O_RDONLY):
         raise PermissionError("文件未以读取模式打开")
     
     # 读取数据
     data = file_obj.read(position, size)
     
     # 更新位置
     file_info['position'] += len(data)
     
     return data
    

    def write(self, fd, data):
    """向文件写入数据"""
    if fd not in self.open_files:
    raise BadFileDescriptorError(f"无效的文件描述符: {fd}")

     file_info = self.open_files[fd]
     file_obj = file_info['file']
     position = file_info['position']
     
     # 检查访问权限
     if not (file_info['flags'] & os.O_WRONLY):
         raise PermissionError("文件未以写入模式打开")
     
     # 写入数据
     bytes_written = file_obj.write(position, data)
     
     # 更新位置
     file_info['position'] += bytes_written
     
     return bytes_written
    

    def close(self, fd):
    """关闭文件"""
    if fd not in self.open_files:
    raise BadFileDescriptorError(f"无效的文件描述符: {fd}")

     file_info = self.open_files[fd]
     file_obj = file_info['file']
     
     # 关闭文件
     file_obj.close()
     
     # 从打开文件表中移除
     del self.open_files[fd]
     
     return True
    

    def resolve_path(self, pathname):
    """解析路径,返回文件系统和实际路径"""
    # 规范化路径
    normalized = os.path.normpath(pathname)

     # 查找最长的匹配挂载点
     best_match = None
     best_fs = None
     
     for mount_point, fs in self.mounted_fs.items():
         if normalized.startswith(mount_point):
             if best_match is None or len(mount_point) > len(best_match):
                 best_match = mount_point
                 best_fs = fs
     
     if best_fs is None:
         return None, None
     
     # 计算在文件系统中的实际路径
     relative_path = normalized[len(best_match):]
     if not relative_path:
         relative_path = '/'
     
     return best_fs, relative_path
    

class Ext2FileSystem:
"""EXT2文件系统实现(简化版)"""
def init(self, device, options=None):
self.device = device
self.block_size = 4096
self.block_groups = []
self.inode_table = {}
self.superblock = None

    # 读取超级块
    self.read_superblock()
    
    # 读取块组描述符表
    self.read_block_group_descriptors()

def read_superblock(self):
    """读取超级块"""
    # 超级块位于1024字节偏移处
    superblock_data = self.read_block(1)  # 第1个块(假设块大小>=1024)
    
    self.superblock = Ext2Superblock()
    self.superblock.decode(superblock_data)
    
    # 计算块大小
    self.block_size = 1024 << self.superblock.log_block_size

def open(self, path, flags, mode):
    """打开文件"""
    # 查找inode
    inode = self.lookup_path(path)
    if inode is None:
        # 如果文件不存在且需要创建
        if flags & os.O_CREAT:
            inode = self.create_file(path, mode)
        else:
            raise FileNotFoundError(f"文件不存在: {path}")
    
    # 检查权限
    if not self.check_permission(inode, flags):
        raise PermissionError("权限不足")
    
    return Ext2File(inode, self)

def lookup_path(self, path):
    """通过路径查找inode"""
    components = path.strip('/').split('/')
    if not components or components[0] == '':
        # 根目录
        return self.read_inode(2)  # 根目录的inode编号通常是2
    
    current_inode = self.read_inode(2)
    
    for component in components:
        # 在目录中查找条目
        found = False
        for entry in self.read_directory(current_inode):
            if entry.name == component:
                current_inode = self.read_inode(entry.inode)
                found = True
                break
        
        if not found:
            return None
    
    return current_inode

def read_inode(self, inode_num):
    """读取inode"""
    if inode_num in self.inode_table:
        return self.inode_table[inode_num]
    
    # 计算inode所在块组
    block_group = (inode_num - 1) // self.superblock.inodes_per_group
    index_in_group = (inode_num - 1) % self.superblock.inodes_per_group
    
    # 读取inode表块
    bg_desc = self.block_groups[block_group]
    inode_table_block = bg_desc.inode_table_start
    inode_offset = index_in_group * self.superblock.inode_size
    
    block_index = inode_table_block + (inode_offset // self.block_size)
    offset_in_block = inode_offset % self.block_size
    
    block_data = self.read_block(block_index)
    inode_data = block_data[offset_in_block:offset_in_block + self.superblock.inode_size]
    
    # 解码inode
    inode = Ext2Inode()
    inode.decode(inode_data)
    inode.inode_number = inode_num
    
    self.inode_table[inode_num] = inode
    return inode

class Ext2File:
"""EXT2文件对象"""
def init(self, inode, fs):
self.inode = inode
self.fs = fs
self.size = inode.size
self.blocks = self.get_blocks()

def read(self, position, size):
    """从指定位置读取数据"""
    if position >= self.size:
        return b''
    
    # 限制读取大小
    read_size = min(size, self.size - position)
    
    # 计算起始块和偏移
    start_block = position // self.fs.block_size
    offset_in_block = position % self.fs.block_size
    
    data = bytearray()
    remaining = read_size
    
    while remaining > 0:
        # 获取物理块号
        if start_block >= len(self.blocks):
            break
        
        physical_block = self.blocks[start_block]
        
        # 读取块
        block_data = self.fs.read_block(physical_block)
        
        # 计算本次读取的大小
        chunk_size = min(self.fs.block_size - offset_in_block, remaining)
        
        # 复制数据
        data.extend(block_data[offset_in_block:offset_in_block + chunk_size])
        
        # 更新状态
        remaining -= chunk_size
        start_block += 1
        offset_in_block = 0
    
    return bytes(data)

四、 设备驱动程序

  1. 设备驱动框架
    python
    class DeviceDriver:
    """设备驱动基类"""
    def init(self, name, device_id):
    self.name = name
    self.device_id = device_id
    self.major = 0 # 主设备号
    self.minor = 0 # 次设备号
    self.status = 'UNINITIALIZED'
    self.irq = None # 中断请求号
    self.io_base = 0 # I/O基地址

    def init(self):
    """初始化设备"""
    self.status = 'INITIALIZING'

     try:
         self._probe()
         self._setup()
         self.status = 'READY'
         return True
     except Exception as e:
         self.status = 'ERROR'
         print(f"设备 {self.name} 初始化失败: {e}")
         return False
    

    def read(self, offset, size):
    """从设备读取数据"""
    raise NotImplementedError

    def write(self, offset, data):
    """向设备写入数据"""
    raise NotImplementedError

    def ioctl(self, command, arg):
    """设备控制"""
    raise NotImplementedError

    def handle_interrupt(self):
    """处理中断"""
    pass

    def _probe(self):
    """探测设备"""
    pass

    def _setup(self):
    """设置设备"""
    pass

class DeviceManager:
"""设备管理器"""
def init(self):
self.devices = {} # major:minor -> driver
self.char_devices = {} # 字符设备
self.block_devices = {} # 块设备
self.net_devices = {} # 网络设备

    # 设备号分配
    self.next_major = 1
    
    # 注册标准设备
    self.register_standard_devices()

def register_driver(self, driver):
    """注册设备驱动"""
    # 分配设备号
    if driver.major == 0:
        driver.major = self.next_major
        self.next_major += 1
    
    # 生成设备标识
    device_key = f"{driver.major}:{driver.minor}"
    
    # 根据设备类型存储
    if isinstance(driver, CharDeviceDriver):
        self.char_devices[device_key] = driver
    elif isinstance(driver, BlockDeviceDriver):
        self.block_devices[device_key] = driver
    elif isinstance(driver, NetworkDeviceDriver):
        self.net_devices[device_key] = driver
    
    self.devices[device_key] = driver
    return device_key

def open_device(self, device_path):
    """打开设备文件"""
    # 解析设备号
    # 格式: /dev/xxx 或 major:minor
    if ':' in device_path:
        major, minor = map(int, device_path.split(':'))
        device_key = f"{major}:{minor}"
    else:
        # 从/dev路径解析(简化)
        if device_path == '/dev/tty':
            device_key = "5:0"  # 控制台
        elif device_path == '/dev/sda':
            device_key = "8:0"  # 第一个SCSI磁盘
        else:
            raise DeviceNotFoundError(f"未知设备: {device_path}")
    
    if device_key not in self.devices:
        raise DeviceNotFoundError(f"设备未注册: {device_key}")
    
    driver = self.devices[device_key]
    
    # 打开设备
    return driver.open()

def register_standard_devices(self):
    """注册标准设备"""
    # 控制台设备
    console_driver = ConsoleDriver()
    console_driver.major = 5
    console_driver.minor = 0
    self.register_driver(console_driver)
    
    # 空设备
    null_driver = NullDeviceDriver()
    null_driver.major = 1
    null_driver.minor = 3
    self.register_driver(null_driver)
    
    # 零设备
    zero_driver = ZeroDeviceDriver()
    zero_driver.major = 1
    zero_driver.minor = 5
    self.register_driver(zero_driver)
  1. 具体设备驱动实现
    python
    class ConsoleDriver(CharDeviceDriver):
    """控制台驱动"""
    def init(self):
    super().init("console", "tty0")
    self.input_buffer = []
    self.output_buffer = []
    self.cursor_x = 0
    self.cursor_y = 0
    self.video_memory = None

    def _setup(self):
    """设置控制台"""
    # 初始化视频内存
    self.video_memory = bytearray(80 * 25 * 2) # 80x25文本模式

     # 清屏
     self.clear_screen()
     
     # 设置光标位置
     self.update_cursor()
    

    def clear_screen(self):
    """清屏"""
    for i in range(0, len(self.video_memory), 2):
    self.video_memory[i] = ord(' ')
    self.video_memory[i + 1] = 0x07 # 灰色前景,黑色背景

    def write_char(self, char):
    """写入字符到控制台"""
    if char == '\n':
    self.cursor_x = 0
    self.cursor_y += 1
    elif char == '\r':
    self.cursor_x = 0
    elif char == '\t':
    self.cursor_x = (self.cursor_x + 8) & ~7
    elif char == '\b':
    if self.cursor_x > 0:
    self.cursor_x -= 1
    else:
    # 计算视频内存位置
    pos = (self.cursor_y * 80 + self.cursor_x) * 2
    if pos < len(self.video_memory):
    self.video_memory[pos] = ord(char)
    self.video_memory[pos + 1] = 0x07

         self.cursor_x += 1
     
     # 检查是否需要滚动
     if self.cursor_x >= 80:
         self.cursor_x = 0
         self.cursor_y += 1
     
     if self.cursor_y >= 25:
         self.scroll_screen()
         self.cursor_y = 24
     
     self.update_cursor()
    

    def scroll_screen(self):
    """滚动屏幕"""
    # 将第2-25行上移一行
    for i in range(80 * 24):
    src_pos = (i + 80) * 2
    dst_pos = i * 2
    self.video_memory[dst_pos] = self.video_memory[src_pos]
    self.video_memory[dst_pos + 1] = self.video_memory[src_pos + 1]

     # 清空最后一行
     last_line_start = 80 * 24 * 2
     for i in range(0, 80 * 2, 2):
         self.video_memory[last_line_start + i] = ord(' ')
         self.video_memory[last_line_start + i + 1] = 0x07
    

    def update_cursor(self):
    """更新光标位置"""
    # 在真实硬件中,这会通过I/O端口设置光标
    pass

    def read(self, offset, size):
    """从控制台读取(非阻塞)"""
    if not self.input_buffer:
    return b''

     data = bytearray()
     while self.input_buffer and len(data) < size:
         char = self.input_buffer.pop(0)
         data.append(ord(char))
     
     return bytes(data)
    

    def write(self, offset, data):
    """向控制台写入"""
    for byte in data:
    char = chr(byte)
    self.write_char(char)

     return len(data)
    

class IDEHardDiskDriver(BlockDeviceDriver):
"""IDE硬盘驱动"""
def init(self, controller_base=0x1F0):
super().init("ide", "hda")
self.controller_base = controller_base
self.sector_size = 512
self.drive_number = 0 # 主设备
self.identify_data = None

def _probe(self):
    """探测IDE设备"""
    # 发送IDENTIFY命令
    self.write_port(6, 0xA0 | (self.drive_number << 4))  # 选择驱动器
    self.write_port(7, 0xEC)  # IDENTIFY命令
    
    # 等待设备就绪
    if not self.wait_ready():
        return False
    
    # 读取IDENTIFY数据
    self.identify_data = bytearray(512)
    for i in range(256):
        data = self.read_port(0)
        self.identify_data[i * 2] = data & 0xFF
        self.identify_data[i * 2 + 1] = (data >> 8) & 0xFF
    
    return True

def read_sector(self, lba, count=1):
    """读取磁盘扇区"""
    if not self.identify_data:
        raise DeviceError("设备未初始化")
    
    sectors = []
    for i in range(count):
        sector = self._read_single_sector(lba + i)
        sectors.append(sector)
    
    return b''.join(sectors) if count > 1 else sectors[0]

def _read_single_sector(self, lba):
    """读取单个扇区"""
    # 设置LBA地址
    self.write_port(6, 0xE0 | (self.drive_number << 4) | ((lba >> 24) & 0x0F))
    self.write_port(2, 1)  # 扇区数
    self.write_port(3, lba & 0xFF)
    self.write_port(4, (lba >> 8) & 0xFF)
    self.write_port(5, (lba >> 16) & 0xFF)
    
    # 发送读命令
    self.write_port(7, 0x20)
    
    # 等待数据就绪
    if not self.wait_data():
        raise DeviceError("读取超时")
    
    # 读取数据
    sector_data = bytearray(self.sector_size)
    for i in range(0, self.sector_size, 2):
        data = self.read_port(0)
        sector_data[i] = data & 0xFF
        sector_data[i + 1] = (data >> 8) & 0xFF
    
    return bytes(sector_data)

def write_port(self, reg, value):
    """写I/O端口"""
    port = self.controller_base + reg
    # 在真实系统中,这里会使用out指令
    print(f"写入端口 0x{port:03X}: 0x{value:02X}")

def read_port(self, reg):
    """读I/O端口"""
    port = self.controller_base + reg
    # 在真实系统中,这里会使用in指令
    # 返回模拟数据
    return 0

def wait_ready(self):
    """等待设备就绪"""
    for _ in range(1000):
        status = self.read_port(7)
        if not (status & 0x80):  # 等待BSY位清除
            return True
    return False

五、 系统调用接口

  1. 系统调用表
    python
    class SystemCallTable:
    """系统调用表"""
    def init(self):
    self.syscalls = {}
    self.syscall_numbers = {}

     # 注册系统调用
     self.register_syscalls()
    

    def register_syscall(self, number, handler, name):
    """注册系统调用"""
    self.syscalls[number] = handler
    self.syscall_numbers[name] = number

    def register_syscalls(self):
    """注册所有系统调用"""
    # 进程控制
    self.register_syscall(1, self.sys_fork, "fork")
    self.register_syscall(2, self.sys_exit, "exit")
    self.register_syscall(3, self.sys_wait, "wait")
    self.register_syscall(4, self.sys_execve, "execve")
    self.register_syscall(5, self.sys_getpid, "getpid")

     # 文件操作
     self.register_syscall(10, self.sys_open, "open")
     self.register_syscall(11, self.sys_read, "read")
     self.register_syscall(12, self.sys_write, "write")
     self.register_syscall(13, self.sys_close, "close")
     self.register_syscall(14, self.sys_lseek, "lseek")
     
     # 内存管理
     self.register_syscall(20, self.sys_brk, "brk")
     self.register_syscall(21, self.sys_mmap, "mmap")
     self.register_syscall(22, self.sys_munmap, "munmap")
     
     # 进程间通信
     self.register_syscall(30, self.sys_pipe, "pipe")
     self.register_syscall(31, self.sys_kill, "kill")
     self.register_syscall(32, self.sys_signal, "signal")
     
     # 系统信息
     self.register_syscall(40, self.sys_gettimeofday, "gettimeofday")
     self.register_syscall(41, self.sys_uname, "uname")
    

    def dispatch(self, syscall_number, *args):
    """分发系统调用"""
    if syscall_number not in self.syscalls:
    return -errno.ENOSYS # 系统调用未实现

     try:
         handler = self.syscalls[syscall_number]
         result = handler(*args)
         return result
     except Exception as e:
         print(f"系统调用 {syscall_number} 错误: {e}")
         return -errno.EFAULT
    

    def sys_fork(self):
    """创建新进程"""
    current_pcb = scheduler.current_pcb

     # 复制进程
     child_pid = scheduler.create_child_process(current_pcb)
     
     # 在子进程中返回0,在父进程中返回子进程PID
     return child_pid if current_pcb.pid != child_pid else 0
    

    def sys_exit(self, status):
    """进程退出"""
    current_pcb = scheduler.current_pcb
    current_pcb.exit_code = status
    current_pcb.state = 'TERMINATED'

     # 通知父进程
     if current_pcb.parent_pid:
         parent_pcb = scheduler.processes.get(current_pcb.parent_pid)
         if parent_pcb:
             # 如果父进程在等待,唤醒它
             if parent_pcb.state == 'BLOCKED':
                 scheduler.unblock_process(parent_pcb)
     
     # 释放资源
     memory_manager.free_process_memory(current_pcb.pid)
     
     # 调度下一个进程
     scheduler.schedule()
     
     # 这里永远不会返回
     return 0
    

    def sys_open(self, pathname, flags, mode=0o666):
    """打开文件"""
    try:
    fd = vfs.open(pathname, flags, mode)
    return fd
    except FileNotFoundError:
    return -errno.ENOENT
    except PermissionError:
    return -errno.EACCES
    except Exception as e:
    return -errno.EIO

    def sys_read(self, fd, buf, count):
    """从文件描述符读取"""
    try:
    data = vfs.read(fd, count)

         # 将数据复制到用户空间
         current_pcb = scheduler.current_pcb
         user_buffer = buf
         
         for i, byte in enumerate(data):
             if i >= count:
                 break
             memory_manager.write_byte(user_buffer + i, byte)
         
         return len(data)
     except BadFileDescriptorError:
         return -errno.EBADF
     except Exception as e:
         return -errno.EIO
    

    def sys_write(self, fd, buf, count):
    """向文件描述符写入"""
    try:
    # 从用户空间读取数据
    current_pcb = scheduler.current_pcb
    user_buffer = buf

         data = bytearray()
         for i in range(count):
             byte = memory_manager.read_byte(user_buffer + i)
             data.append(byte)
         
         bytes_written = vfs.write(fd, bytes(data))
         return bytes_written
     except BadFileDescriptorError:
         return -errno.EBADF
     except PermissionError:
         return -errno.EPERM
     except Exception as e:
         return -errno.EIO
    
  2. 系统调用门
    python
    class SystemCallGate:
    """系统调用门"""
    def init(self):
    self.syscall_table = SystemCallTable()
    self.sysenter_eip = 0 # SYSENTER入口点
    self.sysenter_cs = 0 # SYSENTER代码段

    def setup_sysenter(self):
    """设置SYSENTER机制"""
    # 设置MSR寄存器(在真实硬件中)
    # WRMSR(0x174, 0x08) # SYSENTER_CS_MSR
    # WRMSR(0x175, sysenter_eip) # SYSENTER_EIP_MSR
    # WRMSR(0x176, sysenter_esp) # SYSENTER_ESP_MSR

     # 在我们的模拟器中,设置内部变量
     self.sysenter_eip = id(self.handle_sysenter)
     self.sysenter_cs = 0x08  # 内核代码段
    

    def handle_interrupt_0x80(self, cpu_state):
    """处理int 0x80系统调用"""
    # 获取系统调用号和参数
    syscall_number = cpu_state.eax
    arg1 = cpu_state.ebx
    arg2 = cpu_state.ecx
    arg3 = cpu_state.edx
    arg4 = cpu_state.esi
    arg5 = cpu_state.edi

     # 分发系统调用
     result = self.syscall_table.dispatch(syscall_number, arg1, arg2, arg3, arg4, arg5)
     
     # 设置返回值
     cpu_state.eax = result
     
     # 返回用户空间
     return cpu_state
    

    def handle_sysenter(self, cpu_state):
    """处理SYSENTER系统调用"""
    # 保存用户栈
    user_esp = cpu_state.esp
    user_ss = cpu_state.ss

     # 切换到内核栈
     cpu_state.esp = kernel_stack_top
     cpu_state.ss = 0x10  # 内核数据段
     
     # 保存用户空间上下文
     kernel_stack.push(user_esp)
     kernel_stack.push(user_ss)
     kernel_stack.push(cpu_state.eflags)
     kernel_stack.push(cpu_state.eip)  # 返回地址
     
     # 获取系统调用参数(从寄存器)
     syscall_number = cpu_state.eax
     arg1 = cpu_state.ebx
     arg2 = cpu_state.ecx
     arg3 = cpu_state.edx
     
     # 分发系统调用
     result = self.syscall_table.dispatch(syscall_number, arg1, arg2, arg3)
     
     # 设置返回值
     cpu_state.eax = result
     
     # 准备返回用户空间
     cpu_state.eip = kernel_stack.pop()  # 返回地址
     eflags = kernel_stack.pop()
     user_ss = kernel_stack.pop()
     user_esp = kernel_stack.pop()
     
     # 恢复用户栈
     cpu_state.esp = user_esp
     cpu_state.ss = user_ss
     cpu_state.eflags = eflags
     
     # 执行SYSEXIT(在真实硬件中)
     return cpu_state
    

六、 用户空间与Shell

  1. 用户程序加载器
    python
    class UserProgramLoader:
    """用户程序加载器"""
    def init(self):
    self.elf_parser = ELFParser()
    self.library_loader = LibraryLoader()
    self.dynamic_linker = DynamicLinker()

    def load_program(self, path, argv=None, envp=None):
    """加载并执行用户程序"""
    # 读取可执行文件
    with open(path, 'rb') as f:
    elf_data = f.read()

     # 解析ELF文件
     elf_info = self.elf_parser.parse(elf_data)
     
     # 检查架构
     if elf_info.arch != 'i386':
         raise LoadError(f"不支持的架构: {elf_info.arch}")
     
     # 检查类型
     if elf_info.type != 'EXEC' and elf_info.type != 'DYN':
         raise LoadError(f"不是可执行文件: {elf_info.type}")
     
     # 创建进程地址空间
     pcb = self.create_process_address_space()
     
     # 加载段
     self.load_segments(pcb, elf_info)
     
     # 处理重定位(如果是动态链接)
     if elf_info.is_dynamic:
         self.dynamic_linker.link(pcb, elf_info)
     
     # 设置堆栈
     self.setup_stack(pcb, argv, envp)
     
     # 设置入口点
     pcb.context['eip'] = elf_info.entry_point
     
     return pcb
    

    def load_segments(self, pcb, elf_info):
    """加载程序段到内存"""
    for segment in elf_info.segments:
    if segment.type == 'LOAD':
    # 计算内存权限
    readable = segment.flags & 0x4
    writable = segment.flags & 0x2
    executable = segment.flags & 0x1

             # 分配内存页
             pages = self.allocate_pages_for_segment(pcb, segment)
             
             # 复制数据
             for i in range(segment.file_size):
                 if i < len(segment.data):
                     addr = segment.virtual_address + i
                     byte = segment.data[i]
                     memory_manager.write_byte_to_user(pcb.pid, addr, byte)
             
             # 对于.bss段,清零剩余部分
             if segment.memory_size > segment.file_size:
                 for i in range(segment.file_size, segment.memory_size):
                     addr = segment.virtual_address + i
                     memory_manager.write_byte_to_user(pcb.pid, addr, 0)
    

    def setup_stack(self, pcb, argv, envp):
    """设置用户栈"""
    # 栈顶地址(假设为0xC0000000)
    stack_top = 0xC0000000

     # 构建栈帧
     # 从高地址向低地址生长
     
     # 环境变量字符串
     env_strings = []
     env_pointers = []
     
     if envp:
         for env in envp:
             env_strings.append(env.encode('utf-8') + b'\x00')
     
     # 参数字符串
     arg_strings = []
     arg_pointers = []
     
     if argv:
         for arg in argv:
             arg_strings.append(arg.encode('utf-8') + b'\x00')
     
     # 计算总大小
     total_size = 0
     
     # 环境变量和参数字符串
     for env in env_strings:
         total_size += len(env)
     for arg in arg_strings:
         total_size += len(arg)
     
     # 环境变量指针数组
     total_size += (len(env_strings) + 1) * 4  # 包括null终止符
     
     # 参数指针数组
     total_size += (len(arg_strings) + 1) * 4  # 包括null终止符
     
     # argc
     total_size += 4
     
     # 对齐到16字节边界
     total_size = (total_size + 15) & ~15
     
     # 设置栈指针
     stack_pointer = stack_top - total_size
     pcb.context['esp'] = stack_pointer
     
     # 写入栈数据
     current_ptr = stack_pointer
     
     # 写入argc
     argc = len(arg_strings)
     memory_manager.write_dword_to_user(pcb.pid, current_ptr, argc)
     current_ptr += 4
     
     # 写入argv指针
     argv_ptr = current_ptr + (len(arg_strings) + 1) * 4 + (len(env_strings) + 1) * 4
     arg_pointers_start = current_ptr
     
     for i in range(len(arg_strings)):
         memory_manager.write_dword_to_user(pcb.pid, current_ptr, argv_ptr)
         current_ptr += 4
         
         # 写入参数字符串
         for byte in arg_strings[i]:
             memory_manager.write_byte_to_user(pcb.pid, argv_ptr, byte)
             argv_ptr += 1
         
         # 添加null终止符
         memory_manager.write_byte_to_user(pcb.pid, argv_ptr, 0)
         argv_ptr += 1
     
     # argv终止符null
     memory_manager.write_dword_to_user(pcb.pid, current_ptr, 0)
     current_ptr += 4
     
     # 写入envp指针
     envp_ptr = argv_ptr
     env_pointers_start = current_ptr
     
     for i in range(len(env_strings)):
         memory_manager.write_dword_to_user(pcb.pid, current_ptr, envp_ptr)
         current_ptr += 4
         
         # 写入环境变量字符串
         for byte in env_strings[i]:
             memory_manager.write_byte_to_user(pcb.pid, envp_ptr, byte)
             envp_ptr += 1
         
         # 添加null终止符
         memory_manager.write_byte_to_user(pcb.pid, envp_ptr, 0)
         envp_ptr += 1
     
     # envp终止符null
     memory_manager.write_dword_to_user(pcb.pid, current_ptr, 0)
     current_ptr += 4
     
     # 写入参数字符串
     # 已经在上面的循环中写入
     
     # 设置argv和envp寄存器(在某些调用约定中)
     pcb.context['ebx'] = arg_pointers_start
    
  2. 简单Shell实现
    python
    class SimpleShell:
    """简单的命令行Shell"""
    def init(self):
    self.prompt = "$ "
    self.current_dir = "/"
    self.user = "user"
    self.hostname = "localhost"
    self.environment = {
    'PATH': '/bin:/usr/bin',
    'HOME': '/home/user',
    'USER': self.user,
    'SHELL': '/bin/sh',
    'PWD': self.current_dir,
    }

     # 内建命令
     self.builtin_commands = {
         'cd': self.cd_command,
         'pwd': self.pwd_command,
         'echo': self.echo_command,
         'export': self.export_command,
         'exit': self.exit_command,
         'help': self.help_command,
         'jobs': self.jobs_command,
         'fg': self.fg_command,
         'bg': self.bg_command,
     }
     
     # 作业控制
     self.jobs = []  # 后台作业列表
     self.current_job = None
    

    def run(self):
    """运行Shell主循环"""
    print(f"欢迎使用 SimpleShell v1.0")
    print(f"输入 'help' 获取帮助")

     while True:
         try:
             # 显示提示符
             prompt = self.get_prompt()
             line = input(prompt)
             
             # 解析命令
             if not line.strip():
                 continue
             
             # 处理命令
             self.execute_command(line)
             
         except KeyboardInterrupt:
             print("^C")
             continue
         except EOFError:
             print("\n退出")
             break
         except Exception as e:
             print(f"错误: {e}")
    

    def get_prompt(self):
    """生成提示符"""
    # 格式: user@hostname:current_dir$
    return f"{self.user}@{self.hostname}:{self.current_dir}{self.prompt}"

    def parse_command(self, line):
    """解析命令行"""
    # 分割命令和参数
    parts = self.split_line(line)
    if not parts:
    return None, []

     command = parts[0]
     args = parts[1:]
     
     # 处理重定向和管道
     parsed = self.parse_redirections(args)
     
     return command, parsed
    

    def split_line(self, line):
    """分割命令行,处理引号"""
    parts = []
    current = ""
    in_quote = None # ' 或 "
    escape_next = False

     for char in line:
         if escape_next:
             current += char
             escape_next = False
         elif char == '\\':
             escape_next = True
         elif in_quote:
             if char == in_quote:
                 in_quote = None
             else:
                 current += char
         elif char in ('\'', '"'):
             in_quote = char
         elif char in (' ', '\t'):
             if current:
                 parts.append(current)
                 current = ""
         else:
             current += char
     
     if current:
         parts.append(current)
     
     return parts
    

    def parse_redirections(self, args):
    """解析重定向和管道"""
    parsed = {
    'command': None,
    'args': [],
    'stdin': None,
    'stdout': None,
    'stderr': None,
    'append': False,
    'background': False,
    'pipe': None,
    }

     i = 0
     while i < len(args):
         arg = args[i]
         
         if arg == '<':
             # 输入重定向
             if i + 1 < len(args):
                 parsed['stdin'] = args[i + 1]
                 i += 2
             else:
                 raise ParseError("输入重定向缺少文件名")
         
         elif arg == '>':
             # 输出重定向(覆盖)
             if i + 1 < len(args):
                 parsed['stdout'] = args[i + 1]
                 i += 2
             else:
                 raise ParseError("输出重定向缺少文件名")
         
         elif arg == '2>':
             # 错误重定向
             if i + 1 < len(args):
                 parsed['stderr'] = args[i + 1]
                 i += 2
             else:
                 raise ParseError("错误重定向缺少文件名")
         
         elif arg == '>>':
             # 输出重定向(追加)
             if i + 1 < len(args):
                 parsed['stdout'] = args[i + 1]
                 parsed['append'] = True
                 i += 2
             else:
                 raise ParseError("输出重定向缺少文件名")
         
         elif arg == '|':
             # 管道
             if i + 1 < len(args):
                 parsed['pipe'] = args[i + 1:]
                 break
             else:
                 raise ParseError("管道缺少命令")
         
         elif arg == '&':
             # 后台执行
             parsed['background'] = True
             i += 1
         
         else:
             if parsed['command'] is None:
                 parsed['command'] = arg
             else:
                 parsed['args'].append(arg)
             i += 1
     
     return parsed
    

    def execute_command(self, line):
    """执行命令"""
    command_info = self.parse_command(line)
    if not command_info[0]:
    return

     command, info = command_info
     
     # 检查是否是内建命令
     if command in self.builtin_commands:
         self.builtin_commands[command](info)
     else:
         # 外部命令
         self.execute_external_command(command, info)
    

    def execute_external_command(self, command, info):
    """执行外部命令"""
    # 搜索可执行文件
    executable_path = self.find_executable(command)
    if not executable_path:
    print(f"{command}: 命令未找到")
    return

     try:
         # 创建子进程
         pid = scheduler.create_process(executable_path, 
                                       argv=[command] + info['args'])
         
         if info['background']:
             # 后台执行
             self.jobs.append({
                 'pid': pid,
                 'command': command,
                 'args': info['args'],
                 'status': 'RUNNING'
             })
             print(f"[{len(self.jobs)}] {pid}")
         else:
             # 前台执行
             self.current_job = pid
             scheduler.wait_pid(pid)
             self.current_job = None
     
     except Exception as e:
         print(f"执行命令失败: {e}")
    

    def find_executable(self, command):
    """在PATH中查找可执行文件"""
    # 如果是绝对路径或相对路径
    if '/' in command:
    if os.path.exists(command) and os.access(command, os.X_OK):
    return command
    return None

     # 在PATH中查找
     path_dirs = self.environment.get('PATH', '').split(':')
     
     for dir_path in path_dirs:
         if not dir_path:
             continue
         
         full_path = os.path.join(dir_path, command)
         if os.path.exists(full_path) and os.access(full_path, os.X_OK):
             return full_path
     
     return None
    

    内建命令实现

    def cd_command(self, info):
    """改变当前目录"""
    if not info['args']:
    target = self.environment.get('HOME', '/')
    else:
    target = info['args'][0]

     # 解析路径
     if target.startswith('/'):
         new_dir = target
     else:
         new_dir = os.path.join(self.current_dir, target)
     
     # 规范化路径
     new_dir = os.path.normpath(new_dir)
     
     # 检查目录是否存在
     if os.path.isdir(new_dir):
         self.current_dir = new_dir
         self.environment['PWD'] = new_dir
     else:
         print(f"cd: {target}: 目录不存在")
    

    def echo_command(self, info):
    """回显参数"""
    print(' '.join(info['args']))

    def exit_command(self, info):
    """退出Shell"""
    code = 0
    if info['args']:
    try:
    code = int(info['args'][0])
    except ValueError:
    print(f"exit: {info['args'][0]}: 需要数字参数")
    return

     raise SystemExit(code)
    

七、 综合示例:小型操作系统

  1. 内核初始化
    python
    class MicroKernel:
    """微型操作系统内核"""
    def init(self):
    # 初始化核心组件
    self.gdt = GlobalDescriptorTable()
    self.idt = InterruptDescriptorTable()
    self.scheduler = Scheduler()
    self.memory_manager = VirtualMemoryManager()
    self.vfs = VirtualFileSystem()
    self.device_manager = DeviceManager()
    self.syscall_gate = SystemCallGate()

     # 系统状态
     self.initialized = False
     self.running = False
     self.system_time = 0
     
     # 内核线程
     self.idle_thread = None
     self.kernel_threads = []
    

    def initialize(self):
    """初始化内核"""
    print("正在初始化微型操作系统内核...")

     # 1. 初始化硬件抽象层
     self.init_hardware()
     
     # 2. 初始化内存管理
     self.init_memory()
     
     # 3. 初始化中断系统
     self.init_interrupts()
     
     # 4. 初始化设备驱动
     self.init_devices()
     
     # 5. 初始化文件系统
     self.init_filesystem()
     
     # 6. 初始化进程管理
     self.init_process_manager()
     
     # 7. 启动空闲线程
     self.start_idle_thread()
     
     self.initialized = True
     print("内核初始化完成")
    

    def init_hardware(self):
    """初始化硬件"""
    print(" 初始化硬件...")

     # 检测CPU
     self.detect_cpu()
     
     # 初始化时钟
     self.init_clock()
     
     # 初始化控制台
     self.init_console()
    

    def init_memory(self):
    """初始化内存管理"""
    print(" 初始化内存管理...")

     # 假设有64MB物理内存
     self.memory_manager.init_memory(64 * 1024 * 1024)
     
     # 初始化GDT
     self.gdt.load_gdtr()
     
     # 设置内核内存映射
     self.setup_kernel_mappings()
    

    def init_interrupts(self):
    """初始化中断"""
    print(" 初始化中断系统...")

     # 设置IDT
     self.idt.setup()
     
     # 注册中断处理程序
     self.register_interrupt_handlers()
     
     # 开启中断
     self.enable_interrupts()
    

    def init_devices(self):
    """初始化设备驱动"""
    print(" 初始化设备驱动...")

     # 探测并初始化设备
     self.device_manager.scan_devices()
     
     # 注册中断处理
     for driver in self.device_manager.devices.values():
         if driver.irq:
             self.idt.register_handler(driver.irq, driver.handle_interrupt)
    

    def init_filesystem(self):
    """初始化文件系统"""
    print(" 初始化文件系统...")

     # 挂载根文件系统
     root_device = self.device_manager.get_device_by_name("rootfs")
     if root_device:
         self.vfs.mount(root_device, '/', 'ext2')
     else:
         # 使用内存文件系统作为后备
         self.vfs.mount(None, '/', 'tmpfs')
     
     # 创建必要的目录结构
     self.create_default_directories()
    

    def create_default_directories(self):
    """创建默认目录结构"""
    directories = [
    '/bin', '/sbin', '/usr/bin', '/usr/sbin',
    '/etc', '/home', '/root', '/tmp',
    '/var', '/var/log', '/dev', '/proc',
    '/sys', '/mnt', '/media',
    ]

     for directory in directories:
         try:
             self.vfs.mkdir(directory, 0o755)
         except:
             pass  # 可能已存在
    

    def init_process_manager(self):
    """初始化进程管理"""
    print(" 初始化进程管理...")

     # 创建init进程(PID=1)
     init_pid = self.scheduler.create_process("/sbin/init", "init", priority=0)
     
     if init_pid != 1:
         print("警告: init进程PID不是1")
    

    def start_idle_thread(self):
    """启动空闲线程"""
    print(" 启动空闲线程...")

     # 创建空闲线程
     self.idle_thread = KernelThread(
         name="idle",
         entry_point=self.idle_loop,
         priority=255  # 最低优先级
     )
     
     self.kernel_threads.append(self.idle_thread)
     self.idle_thread.start()
    

    def idle_loop(self):
    """空闲循环"""
    while self.running:
    # 执行HLT指令(在模拟器中休眠)
    self.halt_cpu()

         # 检查是否有任务需要调度
         if self.scheduler.ready_queue:
             self.scheduler.schedule()
    

    def halt_cpu(self):
    """暂停CPU(模拟)"""
    time.sleep(0.001) # 休眠1毫秒

    def run(self):
    """运行内核"""
    if not self.initialized:
    self.initialize()

     self.running = True
     print("内核开始运行")
     
     try:
         # 内核主循环
         while self.running:
             # 处理中断
             self.handle_pending_interrupts()
             
             # 调度进程
             next_process = self.scheduler.schedule()
             if next_process:
                 self.context_switch(next_process)
             
             # 更新系统时间
             self.system_time += 1
             
             # 检查系统负载
             self.check_system_load()
             
     except KeyboardInterrupt:
         print("\n收到关机信号")
     finally:
         self.shutdown()
    

    def shutdown(self):
    """关闭系统"""
    print("正在关闭系统...")

     # 终止所有进程
     for pid in list(self.scheduler.processes.keys()):
         if pid > 1:  # 保留init进程
             self.scheduler.terminate_process(pid)
     
     # 等待进程终止
     time.sleep(0.1)
     
     # 卸载文件系统
     self.vfs.umount_all()
     
     # 关闭设备
     self.device_manager.shutdown_all()
     
     self.running = False
     print("系统关闭完成")
    

    def syscall_handler(self, syscall_number, *args):
    """系统调用处理入口"""
    return self.syscall_gate.dispatch(syscall_number, *args)

class KernelThread:
"""内核线程"""
def init(self, name, entry_point, priority=1):
self.name = name
self.entry_point = entry_point
self.priority = priority
self.state = 'READY'
self.stack = bytearray(4096) # 4KB内核栈
self.registers = {}

def start(self):
    """启动内核线程"""
    self.state = 'RUNNING'
    
    # 设置初始寄存器
    self.registers['eip'] = self.entry_point
    self.registers['esp'] = id(self.stack) + len(self.stack) - 4
    
    # 加入调度器
    scheduler.add_kernel_thread(self)
  1. 启动与运行
    python
    def create_disk_image():
    """创建磁盘映像"""
    print("创建磁盘映像...")

    创建空白磁盘映像

    disk_size = 10 * 1024 * 1024 # 10MB
    disk_image = bytearray(disk_size)

    创建MBR

    mbr = create_mbr()
    disk_image[0:512] = mbr

    创建分区表(一个分区)

    partition_offset = 2048 * 512 # 从1MB开始
    partition_size = 8 * 1024 * 1024 # 8MB

    分区表条目

    partition_entry = bytearray(16)
    partition_entry[0] = 0x80 # 可启动
    partition_entry[4] = 0x83 # Linux分区类型
    partition_entry[8:12] = (2048).to_bytes(4, 'little') # 起始LBA
    partition_entry[12:16] = (partition_size // 512).to_bytes(4, 'little') # 扇区数

    写入分区表

    disk_image[446:462] = partition_entry

    创建文件系统

    create_ext2_filesystem(disk_image[partition_offset:partition_offset+partition_size])

    复制内核到文件系统

    copy_kernel_to_fs(disk_image, partition_offset)

    return bytes(disk_image)

def main():
"""主函数"""
print("=== 微型操作系统模拟器 ===")

# 创建磁盘映像
disk_image = create_disk_image()

# 创建引导加载器
bootloader = Bootloader()

# 加载MBR
try:
    partition_info = bootloader.load_mbr(disk_image)
    print(f"找到活动分区: LBA={partition_info['start_lba']}")
    
    # 加载内核
    entry_point = bootloader.load_kernel(
        disk_image,
        partition_info['start_lba'],
        partition_info['sector_count']
    )
    print(f"内核加载完成,入口点: 0x{entry_point:08X}")
    
    # 跳转到内核
    bootloader.execute()
    
    # 如果返回,说明内核已经初始化
    print("正在启动内核...")
    
    # 创建并运行内核
    kernel = MicroKernel()
    kernel.run()
    
except Exception as e:
    print(f"启动失败: {e}")
    return 1

return 0

if name == "main":
sys.exit(main())

posted @ 2026-01-22 00:11  头发少的文不识  阅读(0)  评论(0)    收藏  举报