自制操作系统(二、输入输出和shell的简易实现)

先实现io.asm

vbnet 复制代码
[bits 32]

; ***********************
; * 硬件端口和常量定义 *
; ***********************
VIDEO_MEMORY         equ 0xB8000
LINE_WIDTH           equ 80
SCREEN_HEIGHT        equ 25
WHITE_ON_BLACK       equ 0x0F

KEYBOARD_PORT        equ 0x60
KEYBOARD_STATUS_PORT equ 0x64
KEYBOARD_BUF_SIZE    equ 256

; 键盘状态标志
CAPS_LOCK    equ 0x01
SHIFT_DOWN   equ 0x02
CTRL_DOWN    equ 0x04
ALT_DOWN     equ 0x08

VGA_CRTC_INDEX  equ 0x3D4
VGA_CRTC_DATA   equ 0x3D5
CURSOR_START    equ 0x0A
CURSOR_END      equ 0x0B

; ***********************
; * 全局数据定义        *
; ***********************
[section .data]
key_flags      db 0     ; 键盘状态标志
cursor_x       dd 0     ; 当前光标列
cursor_y       dd 0     ; 当前光标行
keyboard_buffer times KEYBOARD_BUF_SIZE db 0
keyboard_head  dd 0
keyboard_tail  dd 0

; 扫描码转换表 (小写)
scancode_lower:
    db 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x08
    db 0, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0x0A
    db 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '`', 0
    db '\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, ' '

; 扫描码转换表 (大写/Shift)
scancode_upper:
    db 0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0x08
    db 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0x0A
    db 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 0
    db '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 0, 0, ' '

; ***********************
; * 显示功能函数        *
; ***********************
[section .text]



; 函数:hide_cursor - 隐藏文本模式光标
global hide_cursor
hide_cursor:
    push eax
    push edx

    ; 设置光标起始寄存器 (索引0x0A)
    mov al, CURSOR_START
    mov dx, VGA_CRTC_INDEX
    out dx, al

    ; 写入值0x20到数据端口(禁用光标)
    mov al, 0x20
    mov dx, VGA_CRTC_DATA
    out dx, al

    ; 可选:为了兼容性,也设置结束寄存器
    mov al, CURSOR_END
    mov dx, VGA_CRTC_INDEX
    out dx, al

    mov al, 0x00        ; 结束扫描线设为0
    mov dx, VGA_CRTC_DATA
    out dx, al

    pop edx
    pop eax
    ret

; 在指定位置输出字符
; 输入: EBX=行, ECX=列, AL=字符, AH=属性
global put_char
put_char:
    push edi
    mov edi, ebx
    imul edi, LINE_WIDTH
    add edi, ecx
    shl edi, 1
    mov [gs:edi], ax
    pop edi
    ret

; 输出字符串 (自动换行)
; 输入: EBX=起始行, ECX=起始列, ESI=字符串, AH=属性
global print_str
print_str:
    pusha
    cld
.print_loop:
    lodsb
    test al, al
    jz .done
    
    push ebx
    push ecx
    call put_char
    pop ecx
    pop ebx
    
    inc ecx
    cmp ecx, LINE_WIDTH
    jb .same_line
    
    mov ecx, 0
    inc ebx
    cmp ebx, SCREEN_HEIGHT
    jb .same_line
    
    dec ebx
    dec ecx
    call scroll_screen
.same_line:
    jmp .print_loop
.done:
    popa
    ret

; 清屏
global clear_screen
clear_screen:
    pusha
    mov edi, VIDEO_MEMORY
    mov ecx, LINE_WIDTH * SCREEN_HEIGHT
    mov ax, (WHITE_ON_BLACK << 8) | ' '
    rep stosw
    mov dword [cursor_x], 0
    mov dword [cursor_y], 0
    popa
    ret

; 屏幕向上滚动一行
global scroll_screen
scroll_screen:
    pusha
    
    ; 1. 将第2行到最后行的内容复制到第1行到倒数第2行
    mov esi, VIDEO_MEMORY + LINE_WIDTH * 2    ; 源地址 = 第2行开始
    mov edi, VIDEO_MEMORY                     ; 目标地址 = 第1行开始
    mov ecx, LINE_WIDTH * (SCREEN_HEIGHT-1)   ; 复制 (高度-1) 行
    
    ; 使用DWORD移动提高效率
    shr ecx, 1                                ; 双字计数 = 字数/2
    rep movsd
    
    ; 如果字符数为奇数,复制最后一个字
    ;test ecx, 1
    ;jz .clear_last_line
    ;movsw
    
.clear_last_line:
    ; 2. 清空最后一行
    mov edi, VIDEO_MEMORY + LINE_WIDTH * (SCREEN_HEIGHT-1) * 2
    mov ecx, LINE_WIDTH
    mov ax, (WHITE_ON_BLACK << 8) | ' '       ; 空格字符+属性
    rep stosw
    
    ; 3. 更新光标位置(保持在最后一行开头)
    mov dword [cursor_x], 0
    mov dword [cursor_y], SCREEN_HEIGHT
    
    popa
    ret

; ***********************
; * 键盘功能函数        *
; ***********************

; 键盘中断处理程序 (IRQ1)
global get_key
get_key:
    push edx
    push ebx

.wait_key:
    ; 等待键盘缓冲区有数据
    in al, KEYBOARD_STATUS_PORT
    test al, 1
    jz .wait_key

    ; 读取键盘扫描码
    in al, KEYBOARD_PORT
    mov ah, al           ; 保存扫描码

    ; 处理特殊键 (Shift/Ctrl/Alt/CapsLock)
    cmp al, 0x2A         ; 左Shift按下
    je .shift_press
    cmp al, 0xAA         ; 左Shift释放
    je .shift_release
    cmp al, 0x36         ; 右Shift按下
    je .shift_press
    cmp al, 0xB6         ; 右Shift释放
    je .shift_release
    cmp al, 0x3A         ; CapsLock
    je .caps_toggle
    cmp al, 0x1D         ; Ctrl
    je .ctrl_press
    cmp al, 0x9D         ; Ctrl释放
    je .ctrl_release
    cmp al, 0x38         ; Alt
    je .alt_press
    cmp al, 0xB8         ; Alt释放
    je .alt_release

    ; 检查是否是释放事件
    test al, 0x80
    jnz .key_release

    ; 转换为ASCII
    movzx ebx, al
    cmp ebx, 58          ; 检查是否在转换表范围内
    ja .special_key

    ; 选择转换表 (根据Shift/Caps状态)
    test byte [key_flags], SHIFT_DOWN
    jnz .use_upper
    test byte [key_flags], CAPS_LOCK
    jz .use_lower
.use_upper:
    mov al, [scancode_upper + ebx]
    jmp .check_valid
.use_lower:
    mov al, [scancode_lower + ebx]
.check_valid:
    test al, al
    jz .special_key
    stc                  ; CF=1表示按下事件
    jmp .done

.key_release:
    ;clc                  ; CF=0表示释放事件
    xor al, al
    jmp .done

.special_key:
    xor al, al           ; AL=0表示特殊键
    stc
    jmp .done

.shift_press:
    or byte [key_flags], SHIFT_DOWN
    xor al, al
    stc
    jmp .done

.shift_release:
    and byte [key_flags], ~SHIFT_DOWN
    xor al, al
    stc
    jmp .done

.caps_toggle:
    xor byte [key_flags], CAPS_LOCK
    ; 更新CapsLock LED
    call update_leds
    xor al, al
    stc
    jmp .done

.ctrl_press:
    or byte [key_flags], CTRL_DOWN
    xor al, al
    stc
    jmp .done

.ctrl_release:
    and byte [key_flags], ~CTRL_DOWN
    xor al, al
    stc
    jmp .done

.alt_press:
    or byte [key_flags], ALT_DOWN
    xor al, al
    stc
    jmp .done

.alt_release:
    and byte [key_flags], ~ALT_DOWN
    xor al, al
    stc
    jmp .done

.done:
    pop ebx
    pop edx
    ret

; 更新键盘LED状态 (CapsLock/NumLock/ScrollLock)
update_leds:
    pushad
    ; 等待键盘可接受命令
    mov ecx, 1000
.wait_ready:
    in al, KEYBOARD_STATUS_PORT
    test al, 0x02
    loopnz .wait_ready

    ; 发送LED更新命令
    mov al, 0xED         ; LED命令
    out KEYBOARD_PORT, al

    ; 等待应答
    mov ecx, 1000
.wait_ack:
    in al, KEYBOARD_PORT
    cmp al, 0xFA         ; ACK
    loopne .wait_ack

    ; 发送LED状态
    mov al, [key_flags]
    and al, CAPS_LOCK    ; 只设置CapsLock
    out KEYBOARD_PORT, al
    popad
    ret

; 获取一个按键 (非阻塞)
; 输出: AL=ASCII字符 (0表示无输入)
global get_char
get_char:
    mov eax, [keyboard_head]
    cmp eax, [keyboard_tail]
    je .no_input
    
    mov al, [keyboard_buffer + eax]
    inc eax
    cmp eax, KEYBOARD_BUF_SIZE
    jne .no_wrap
    xor eax, eax
.no_wrap:
    mov [keyboard_head], eax
    ret
.no_input:
    xor al, al
    ret

; 读取一行输入 (带回显)
; 输入: EDI=缓冲区, ECX=最大长度
; 输出: EAX=读取字符数
global read_line
read_line:
    push ebx
    push ecx
    push edx
    push edi
    
    xor ebx, ebx         ; 字符计数
    mov edx, [cursor_y]
    shl edx, 16
    or edx, [cursor_x]   ; EDX高16位=行, 低16位=列
    
.read_loop:
    call get_char
    test al, al
    jz .read_loop
    
    cmp al, 0x0A         ; 回车
    je .line_end
    cmp al, 0x08         ; 退格
    je .backspace
    
    ; 检查缓冲区是否满
    cmp ebx, ecx
    jae .read_loop
    
    ; 存储并显示字符
    mov [edi + ebx], al
    inc ebx
    
    push ebx
    push ecx
    movzx ebx, dx        ; 当前列
    movzx ecx, dh        ; 当前行
    mov ah, WHITE_ON_BLACK
    call put_char
    pop ecx
    pop ebx
    
    inc dl               ; 列位置+1
    cmp dl, LINE_WIDTH
    jb .read_loop
    
    mov dl, 0            ; 换行处理
    inc dh
    cmp dh, SCREEN_HEIGHT
    jb .read_loop
    
    dec dh
    call scroll_screen
    jmp .read_loop

.backspace:
    test ebx, ebx
    jz .read_loop
    dec ebx
    
    push ebx
    push ecx
    movzx ebx, dx
    movzx ecx, dh
    mov al, ' '
    mov ah, WHITE_ON_BLACK
    call put_char
    pop ecx
    pop ebx
    
    dec dl
    jns .read_loop
    mov dl, LINE_WIDTH-1
    dec dh
    jns .read_loop
    xor dh, dh
    jmp .read_loop

.line_end:
    mov byte [edi + ebx], 0
    mov eax, ebx
    
    ; 更新光标位置
    mov [cursor_x], edx
    shr edx, 16
    mov [cursor_y], edx
    
    pop edi
    pop edx
    pop ecx
    pop ebx
    ret

实现一个简易的shell.asm

vbnet 复制代码
;shell.asm
[bits 32]

; 常量定义
ATA_BASE         equ 0x1F0
ATA_DRIVE_SELECT equ 0x1F6
ATA_STATUS       equ 0x1F7
ATA_CMD          equ 0x1F7
ATA_DATA         equ 0x1F0
extern scroll_screen
[section .data]
; Shell界面
msg db "[root@Plain]-(/)# ", 0
cmd_buffer times 80 db 0

; 命令定义
cmd_echo db "echo", 0
cmd_help db "help", 0
cmd_ls   db "ls", 0
cmd_cat  db "cat", 0
cmd_write db "write", 0
cmd_clear db "clear", 0

cmd_time db "time", 0
time_str db "HH:MM:SS", 0
; 帮助信息
help_msg1 db "Available commands:", 0
help_msg2 db "  echo <message> - Display message", 0
help_msg3 db "  help          - Show this help", 0
help_msg4 db "  ls            - List files", 0
help_msg5 db "  cat <file>    - Show file content", 0
help_msg6 db "  write <file> > <content> - Write to file", 0
help_msg7 db "  clear         - Clear screen", 0

; 错误和信息消息
not_msg db "Error: Command not found: ", 0
error_msg db "ERROR: Disk operation failed", 0
dir_entry db "  [DIR] ", 0
no_file_msg db "File not found: ", 0
write_success db "Write successful", 0
write_fail db "Write failed", 0
invalid_format_msg db "Invalid write format. Use: write filename > content", 0

; 文件系统参数
files_per_sector equ 16  ; FAT12根目录每扇区16个条目

[section .bss]
; 磁盘缓冲区
bpb_buf    resb 512
fat_buf    resb 512

; 文件系统参数
part_start resd 1
fat_start  resd 1
root_start resd 1
root_sectors resd 1

; ==== 文件系统常量定义 ====
ROOT_DIR_SECTORS    equ 14      ; 根目录占用扇区数
ROOT_DIR_START      equ 19      ; 根目录起始扇区
FAT1_START          equ 1       ; FAT1起始扇区
DATA_START          equ 33      ; 数据区起始扇区 = 1 + 9*2 + 14

; ==== 目录条目结构 ====
struc DIR_ENTRY
    .name      resb 8
    .ext       resb 3
    .attr      resb 1
    .reserved  resb 10
    .time      resw 1
    .date      resw 1
    .cluster   resw 1
    .size      resd 1
endstruc

[section .text]
extern print_str, put_char, get_key, clear_screen, fs_list_files, fs_files_count, fs_read_file 

global shell
shell:
    cmp ebx, 25
    ja .scroll
    mov ecx, 0
    mov esi, msg
    mov ah, 0x0F
    call print_str
    
    ; 初始化命令缓冲区
    mov edi, cmd_buffer
    mov ecx, 18          ; 从第18列开始输入
    mov byte [edi], 0    ; 清空缓冲区
    
.input_loop:
    call get_key
    test al, al
    jz .input_loop

    ; 处理回车
    cmp al, 0x0A
    je .execute

    ; 处理退格
    cmp al, 0x08
    je .backspace

    ; 存储并显示字符
    mov [edi], al
    inc edi
    mov ah, 0x0F
    call put_char
    inc ecx
    jmp .input_loop

.backspace:
    ; 退格处理
    cmp edi, cmd_buffer
    je .input_loop       ; 忽略空退格
    dec edi
    dec ecx
    mov al, ' '
    mov ah, 0x0F
    call put_char
    jmp .input_loop
    
.scroll:
    call scroll_screen
    dec ebx
    jmp shell
.execute:
    ; 添加字符串结束符
    mov byte [edi], 0
    
    ; 检查空命令
    mov esi, cmd_buffer
    call is_empty
    je .empty_cmd
    
    ; 跳过前导空格
    call skip_spaces
    test al, al
    jz .empty_cmd
    
    ; 检查help命令
    mov edi, cmd_help
    call cmd_cmp
    je .show_help

    ; 检查echo命令
    mov edi, cmd_echo
    call cmd_cmp
    je .do_echo
    
    
    mov edi, cmd_time
    call cmd_cmp
    je do_time

    ; 检查clear命令
    mov edi, cmd_clear
    call cmd_cmp
    je .do_clear

    ; 未知命令处理
    inc ebx
    mov ecx, 0
    mov esi, not_msg
    mov ah, 0x0C        ; 红色错误信息
    call print_str
    
    ; 只显示命令部分(第一个空格前的内容)
    mov esi, cmd_buffer
    call print_command_part
    
    inc ebx
    jmp shell

.empty_cmd:
    inc ebx
    mov ecx, 0
    jmp shell

.show_help:
    ; 显示帮助信息
    inc ebx
    mov ecx, 0
    mov esi, help_msg1
    mov ah, 0x0A        ; 绿色帮助信息
    call print_str
    
    inc ebx
    mov ecx, 0
    mov esi, help_msg2
    call print_str
    
    inc ebx
    mov ecx, 0
    mov esi, help_msg3
    call print_str
    
    inc ebx
    mov ecx, 0
    mov esi, help_msg4
    call print_str
    
    inc ebx
    mov ecx, 0
    mov esi, help_msg5
    call print_str
    
    inc ebx
    mov ecx, 0
    mov esi, help_msg6
    call print_str
    
    inc ebx
    mov ecx, 0
    mov esi, help_msg7
    call print_str
    
    inc ebx
    jmp shell

.do_echo:
    ; 跳过"echo"和后续空格
    add esi, 4
    call skip_spaces
    test al, al
    jz .no_args1         ; 无参数情况
    
    ; 显示echo参数
    inc ebx
    mov ecx, 0
    mov ah, 0x0F
    call print_str
    
.no_args1:
    inc ebx             ; 换行
    jmp shell

; === clear命令实现 ===
.do_clear:
    call clear_screen
    mov ebx, 0
    mov ecx, 0
    jmp shell

; === 辅助函数 ===

; 打印命令部分(第一个空格前的内容)
print_command_part:
    pusha
    mov ecx, 26         ; 错误信息后位置
.loop:
    lodsb
    test al, al
    jz .done
    cmp al, ' '
    je .done
    mov ah, 0x0F
    call put_char
    inc ecx
    jmp .loop
.done:
    popa
    ret

; 检查字符串是否为空或只有空格
is_empty:
    push esi
.loop:
    lodsb
    cmp al, ' '
    je .loop
    test al, al
    pop esi
    ret

; 跳过字符串中的空格
skip_spaces:
    lodsb
    cmp al, ' '
    je skip_spaces
    dec esi             ; 回退到第一个非空格字符
    ret

; 命令比较函数
cmd_cmp:
    pusha
.compare:
    mov al, [esi]
    mov bl, [edi]
    
    ; 检查命令是否结束(空格或字符串结束)
    cmp al, ' '
    je .check_cmd_end
    test al, al
    jz .check_cmd_end
    
    ; 转换为小写比较
    cmp al, 'A'
    jb .no_change1
    cmp al, 'Z'
    ja .no_change1
    add al, 0x20
.no_change1:
    cmp bl, 'A'
    jb .no_change2
    cmp bl, 'Z'
    ja .no_change2
    add bl, 0x20
    
.no_change2:
    cmp al, bl
    jne .not_equal
    inc esi
    inc edi
    jmp .compare
    
.check_cmd_end:
    ; 检查命令字符串是否也结束了
    cmp byte [edi], 0
    jne .not_equal
    
.equal:
    popa
    xor eax, eax  ; ZF=1
    ret
    
.not_equal:
    popa
    or eax, 1     ; ZF=0
    ret

; 显示固定数量的字符
print_nchars:
    pusha
    mov ah, 0x0F
.loop:
    lodsb
    call put_char
    loop .loop
    popa
    ret

print_hex:
    pushad
    mov ecx, 8
.loop:
    rol eax, 4
    mov ebx, eax
    and ebx, 0x0f
    mov bl, [hex_chars + ebx]
    mov ah, 0x0F
    call put_char
    loop .loop
    popad
    ret

do_time:
    call get_time
    inc ebx             ; 换行
    mov ecx, 0
    mov esi, time_str
    mov ah, 0x0F        ; 白色文字
    call print_str
    jmp shell

get_time:
    pushad

    ; 禁用NMI并读取小时
    mov al, 0x04        ; 小时寄存器
    or al, 0x80         ; 禁用NMI
    out 0x70, al
    in al, 0x71
    call bcd_to_ascii
    mov [time_str], dh
    mov [time_str+1], dl

    ; 读取分钟
    mov al, 0x02
    or al, 0x80
    out 0x70, al
    in al, 0x71
    call bcd_to_ascii
    mov [time_str+3], dh
    mov [time_str+4], dl

    ; 读取秒
    mov al, 0x00
    or al, 0x80
    out 0x70, al
    in al, 0x71
    call bcd_to_ascii
    mov [time_str+6], dh
    mov [time_str+7], dl

    popad
    ret

bcd_to_ascii:
    ; 将AL中的BCD码转换为两个ASCII字符,存储在DH和DL中
    mov dh, al
    shr dh, 4
    add dh, '0'
    mov dl, al
    and dl, 0x0F
    add dl, '0'
    ret

; === 数据区 ===
[section .data]
no_files_msg db "No files found", 0
cat_usage_msg db "Usage: cat <filename>", 0

; 文件系统参数(在Shell初始化时设置)
data_start      dd 33   ; 1+9*2+14=33
root_dir_sectors dd 14  ; 根目录扇区数
fat1_start      dd 1    ; FAT1起始扇区

file_cluster dw 0
free_entry   dd 0
lba_low      db 0
lba_mid      db 0
lba_high     db 0

sectors_per_track dd 18
num_heads        dd 2
boot_drive       db 0
hex_chars db '0123456789ABCDEF'

放一下makefile

bash 复制代码
all:
	make bin
	make img
	make run

bin:
	nasm boot.asm -o boot.bin
	nasm loader.asm -o loader.bin
	#gcc -c -O0 -fno-builtin -m32 -fno-stack-protector -o main.o main.c
	nasm -f elf -o kernel.o kernel.asm
	nasm -f elf -o io.o io.asm
	nasm -f elf -o shell.o shell.asm
	i686-elf-ld -s -Ttext 0x100000 -o kernel.bin kernel.o io.o shell.o

img : boot.bin loader.bin kernel.bin
	#dd if=boot.bin of=a.img bs=512 count=1
	#dd if=loader.bin of=a.img bs=512 seek=1 conv=notrunc
	#python img.py
	edimg   imgin:1.img \
		wbinimg src:boot.bin len:512 from:0 to:0 \
		copy from:loader.bin to:@: \
		copy from:kernel.bin to:@: \
		imgout:a.img


run : a.img
	#qemu-system-i386 -fda a.img
	qemu-system-i386 -fda a.img #-hda disk.img -boot a

最后实现kernel.asm

vbnet 复制代码
; Plain Kernel
; kernel.asm

[section .text]

%include "io.inc"

global _start
extern shell
extern init_mouse

_start:
    call hide_cursor
    call clear_screen
    mov ebx, 0          ; 行号
    mov ecx, 0          ; 列号
    mov esi, hello_msg  ; 字符串地址
    mov ah, 0x0F
    call print_str
    xor ecx, ecx
    mov ebx, 2          ; 行号
    call shell


hello_msg db "Welcome to Plain - OS !", 0

input_buffer times 80 db 0

[section .bss]
sector_buf resb 512
bpb_buf    resb 512
fat_buf    resb 512
part_start resd 1
fat_start  resd 1
root_start resd 1
data_start resd 1
root_sectors resd 1

其中io.inc

vbnet 复制代码
; 常量定义
ATA_BASE         equ 0x1F0
ATA_DRIVE_SELECT equ 0x1F6
ATA_STATUS       equ 0x1F7
ATA_CMD          equ 0x1F7
ATA_DATA         equ 0x1F0

; 全局变量

VIDEO_MEMORY equ 0xB8000
LINE_WIDTH   equ 80
WHITE_ON_BLACK equ 0x0F

KEYBOARD_PORT equ 0x60
KEYBOARD_STATUS_PORT equ 0x64
KEYBOARD_BUFFER_SIZE equ 32

extern put_char
extern print_str
;extern clear_screen
extern get_char
extern get_key
extern read_line
extern scroll_screen
extern init_fs
;extern write_file
extern ata_read
extern ata_wait
extern hide_cursor
extern clear_screen
相关推荐
QQ_4376643145 小时前
Linux下可执行程序的生成和运行详解(编译链接汇编图解)
linux·运维·c语言·汇编·caffe
九章云极AladdinEdu1 天前
GPU SIMT架构的极限压榨:PTX汇编指令级并行优化实践
汇编·人工智能·pytorch·python·深度学习·架构·gpu算力
染指11101 天前
25.第二阶段x64游戏实战-分析物品相关数据
汇编·游戏·游戏逆向·x64dbg·x64游戏
LUCIAZZZ2 天前
JVM之虚拟机运行
java·jvm·spring·操作系统·springboot
迷茫不知归路3 天前
操作系统实验习题解析 上篇
c++·算法·操作系统·实验课设
LUCIAZZZ4 天前
JVM之内存管理(一)
java·jvm·spring·操作系统·springboot
ssslar4 天前
MIT XV6 - 1.6 Lab: Xv6 and Unix utilities -uptime
操作系统·risc-v·xv6
pigfu5 天前
go 通过汇编学习atomic原子操作原理
汇编·golang·atomic·缓存行·lock指令
LUCIAZZZ5 天前
JVM之内存管理(二)
java·jvm·后端·spring·操作系统·springboot