Rails ENV

Rails ENV 环境配置参考 Ruby China 社区的 Wiki Windows 10 在 Windowns 10 的环境下和Linux上差不多,不过不需要RVM 首先在Ruby官方网站下载好安装包 之后使用RubyChina提供的Source替换Gem的Source 之后使用Gem下载 Bundler 和 Rails 创建Rails项目运行即可 有一个软件叫做 RailsInstaller 可以直接帮你省下1和3步也就是直接帮你安装好了Ruby和Rails还有Gem,bundler。 但是🙅我目前使用的Railsinstaller有点问题。他的Ruby版本是2.3,rails版本是5,rails5依赖的是 >= 2.4版本的ruby,这就有问题了。我也没接着用这个软件了。 在rails6中加入了Webpacker的打包工具,运行之前需要先安装webpacker不然会报错。 $ rails webpacker:install 注意在上面可能会有点问题,Gem创建Rails项目的时候会下载各种依赖,这些依赖有可能会在Windows的环境上出现问题,比如我遇到的 SQLite3,所以Ruby最好还是不要在Windowns上运行。 还有Rails 是要依赖 Yarn和 nodejs 最好是10版本以上 Development Note 花了很长时间去吧Rails和一些大前端的框架合二为一,最后以失败而告终。 Rails终究是个全栈式的Web框架,老老实实用简单的就行。 Bootstrap Configuration # => 首先在 Gemfile 中加入 gem 'bootstrap', '~> 4.3.1' gem 'jquery-rails' 之后将app\assets\stylesheets\application.css 改为 scss 删掉所有的东西包括注释 加入@import “bootstrap”; Ruby Note Todo Error running 'requirements_debian_libs_install g++ gcc autoconf automake bison libc6-dev libffi-dev libgdbm-dev libncurses5-dev libsqlite3-dev libtool libyaml-dev make pkg-config sqlite3 zlib1g-dev libgmp-dev libreadline-dev libssl-dev', please read /home/sdttttt/.rvm/log/1573869340/package_install_g++_gcc_autoconf_automake_bison_libc6-dev_libffi-dev_libgdbm-dev_libncurses5-dev_libsqlite3-dev_libtool_libyaml-dev_make_pkg-config_sqlite3_zlib1g-dev_libgmp-dev_libreadline-dev_libssl-dev.log Requirements installation failed with status: 100. 碰到这种错误不需要紧张,rvm requirements command 的原理就是会使用你系统的包管理工具去下载这些依赖,所以原因很简单,你的源里找不到这些依赖就会报出100的错误。 是Ubuntu的话下面我提供了源 ...

170 字

RSSHub的反代配置

为了方便做日志和限流,给RSSHub配个和好伙伴openresty(NGINX的一个支持lua的分支)写了一下反代的配置,只说一下自己写的功能吧: 请求头会说自己是SpringBoot应用,因为我最恶心的就是spring全家桶了。 请求会记录在rsshub代理等待了多久。 rsshub查询错误的话直接返回状态码,响应体直接放空,省点流量。 stat 给出一些简单的性能数据和热点IP http { ## # Basic Settings ## sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log off; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; gzip_vary on; # gzip_proxied any; gzip_comp_level 6; # gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; gzip_min_length 1024; ## # Virtual Host Configs ## # include /etc/nginx/conf.d/*.conf; # include /etc/nginx/sites-enabled/*; lua_shared_dict rss_limit_req_store 10m; init_by_lua_block { package.path = "/etc/openresty/lua/?.lua;" .. package.path } upstream rsshub { server 127.0.0.1:1222 max_fails=3 fail_timeout=30s; keepalive 8; } server { listen 1200; listen [::]:1200; server_name ""; access_by_lua_block { local rtime = require "rtime" rtime.start() } header_filter_by_lua_block { ngx.header["Server"] = "spring-boot" local rtime = require "rtime" local process_time = rtime.get_duration_ms() ngx.header["x-wait-for"] = process_time } log_by_lua_block { local log_path = "/var/log/nginx/access.log" local now = os.date("%Y-%m-%d %H:%M:%S") local method = ngx.var.request_method or "-" local uri = ngx.var.request_uri or "-" local rt_ms = tonumber(ngx.var.request_time) * 1000 if not rt_ms then rt_ms = 0 end local srcip = ngx.var.remote_addr or "-" local dstip = ngx.var.server_addr or "-" local bytes = tonumber(ngx.var.body_bytes_sent) or 0 -- 获取 User-Agent local ua = ngx.var.http_user_agent or "-" -- 构造日志 local log_lines = { string.format("%s [%s] %s %.1fms", now, method, uri, rt_ms), string.format("[%s] <=> [%s] Byte: %d", srcip, dstip, bytes), ua, "" -- 空行分隔 } -- 安全写入 local fp, err = io.open(log_path, "a") if not fp then ngx.log(ngx.ERR, "Failed to open log file: ", err) return end for _, line in ipairs(log_lines) do local ok, err = fp:write(line, "\n") if not ok then ngx.log(ngx.ERR, "Failed to write log line: ", err) break end end fp:close() } location = /stat { stub_status; access_log off; access_by_lua_block { local addr = ngx.var.remote_addr if not addr:match("^10%.126%.126%.%d+$") then ngx.log(ngx.ERR, "IP not allowed: ", addr, " for /stat, redirect to @fallback") ngx.exit(503) end } error_page 503 = @fallback; } location ~ /(telegram|twitter)/ { access_by_lua_block { ngx.exit(503) } error_page 503 = @fallback_gfw; } location / { access_by_lua_block { local rtime = require "rtime" rtime.start() local limit_req = require "resty.limit.req" local lim, err = limit_req.new("rss_limit_req_store", 10, 20) if not lim then ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err) ngx.exit(500) end local key = ngx.var.binary_remote_addr local delay, err = lim:incoming(key, true) if not delay then if err == "rejected" then ngx.log(ngx.WARN, "rate limited, key: ", key) ngx.exit(429) end ngx.log(ngx.ERR, "failed to limit req: ", err) ngx.exit(500) end if delay > 0 then ngx.sleep(delay) end } proxy_pass http://rsshub; # 代理统一用HTTP1.1 proxy_http_version 1.1; # 传递真实客户端信息 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; # 支持 WebSocket proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # 超时设置 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; # 错误处理 proxy_next_upstream error timeout; proxy_intercept_errors on; error_page 503 = @fallback; } location ~* \.(jpg|jpeg|gif|ico|css|js|woff|woff2|ttf|svg|eot)$ { expires 1d; add_header Cache-Control "public, immutable"; # 仍代理到后端(如果你的服务自己处理静态资源) proxy_pass http://rsshub; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; proxy_pass_request_headers on; } location ~* \.(png)$ { empty_gif; } location @fallback { internal; content_by_lua_block { ngx.status = 503 ngx.print() ngx.exit(ngx.status) } } location @fallback_gfw { internal; content_by_lua_block { ngx.status = 503 ngx.header["Content-Type"] = "text/plain" ngx.print("we cannot access GFW site.") ngx.exit(ngx.status) } } } } -- ip_cidr.lua local _M = {} local bit = require "bit" local internal_ipset = { "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" } local function ip_to_num(ip) -- 将 IPv4 字符串(如 "192.168.1.1")转换为 32 位整数 local parts = {} for part in ip:gmatch("%d+") do -- 提取所有数字部分(如 "192", "168") table.insert(parts, tonumber(part)) end if #parts ~= 4 then return nil, "invalid IPv4 address: 不是有效的 IPv4 格式" end for _, p in ipairs(parts) do if p < 0 or p > 255 then return nil, "invalid IPv4 address: 八位组超出 0-255 范围" end end -- 计算 32 位整数(大端序) -- 傻瓜也能听懂的讲解:也算是帮我复习了 -- IP地址每个位最大255 也就是 FF = 1111 1111 -- 192.168.1.1 经过上面转成parts就是 [192, 168, 1 ,1] -- 现在你要把这些数字转成一个整数,当然你可以直接乘10的倍数变成19216811 -- 但是这样子网掩码计算就比较复杂,并且乘法在计算机底层上算不上很高效率的指令 -- 所以这里用左移,上面说了每个位最大255也就是8个1 -- 那么最前面的192是从右数第4位那就移动 8 * 4 = 24 -- 以此类推,最后这个32位二进制数,8位的16进制数就是ip地址 local part1 = bit.lshift(parts[1], 24) -- 左移 24 位 local part2 = bit.lshift(parts[2], 16) -- 左移 16 位 local part3 = bit.lshift(parts[3], 8) -- 左移 8 位 local part4 = parts[4] -- 无需移位 return bit.bor(part1, part2, part3, part4), nil -- 按位或合并 end function _M.match(target_ip, cidr) if target_ip == nil or type(target_ip) ~= "string" or target_ip == "" then return false, nil end local cidr_ip_str, prefix_str = cidr:match("^([^/]+)/(%d+)$") if not cidr_ip_str or not prefix_str then return false, "invalid CIDR format: 错误 = " .. cidr end local prefix = tonumber(prefix_str) if prefix < 0 or prefix > 32 then return false, "invalid prefix: 前缀长度需为 0-32 的整数" end -- 步骤 2:将 CIDR 中的 IP 转换为整数 local cidr_ip_num, err = ip_to_num(cidr_ip_str) if not cidr_ip_num then return false, "CIDR IP error: " .. err end -- 生成掩码位 -- 傻瓜也能听懂的讲解: -- 打个比方,最常用的24,32 - 24 = 8 -- 0xFFFFFFFF << 8 = 0xFFFFFFF00 -- 然后去掉高位,转回32位(这个是16进制,1位当4位算) -- 0xFFFFFF00 按照子网掩码转成可读的方式 -- FF FF FF 00 = 255 255 255 0 -- 如果这还听不懂,那只能是根本不知道进制之间的转换是怎么算的 local mask = 0 if prefix ~= 0 then mask = bit.lshift(0xFFFFFFFF, 32 - prefix) mask = bit.band(mask, 0xFFFFFFFF) end -- 网段 local cidr_network = bit.band(cidr_ip_num, mask) local target_ip_num, err = ip_to_num(target_ip) if not target_ip_num then return false, "Target IP error: " .. err end local target_ip_cidr = bit.band(target_ip_num, mask) print(target_ip_cidr) print(cidr_network) print(mask) return target_ip_cidr == cidr_network, nil end function _M.is_internal(target_ip) for _, t in ipairs(internal_ipset) do local ok, err = _M.match(target_ip, t) if ok and err == nil then return ok, err end end return false, nil end return _M -- ngx_log.lua local _M = {} local cjson = require "cjson" function _M.req_info() local log_path = "/var/log/nginx/access.log" local now = os.date("%Y-%m-%d %H:%M:%S") local method = ngx.var.request_method or "-" local uri = ngx.var.request_uri or "-" local rt_ms = tonumber(ngx.var.request_time) * 1000 if not rt_ms then rt_ms = 0 end local srcip = ngx.var.remote_addr or "-" local dstip = ngx.var.server_addr or "-" local bytes = tonumber(ngx.var.body_bytes_sent) or 0 -- 获取 User-Agent local ua = ngx.var.http_user_agent or "-" -- 构造日志 local log_lines = { string.format("%s [%s] %s %.1fms", now, method, uri, rt_ms), string.format("[%s] <=> [%s] Byte: %d", srcip, dstip, bytes), ua, "" -- 空行分隔 } -- 安全写入 local fp, err = io.open(log_path, "a") if not fp then ngx.log(ngx.ERR, "Failed to open log file: ", err) return end local ok, err = pcall(function() for _, line in ipairs(log_lines) do local ok, err = fp:write(line, "\n") if not ok then ngx.log(ngx.ERR, "Failed to write log line: ", err) break end end end) fp:close() if not ok then ngx.log(ngx.ERR, "Logging error: ", err) end end return _M -- ngx_log.lua local _M = {} function _M.start() ngx.ctx.start_time = ngx.now() end function _M.get_duration_ms() local start = ngx.ctx.start_time if not start then return 0 end return string.format("%.1fms", (ngx.now() - start) * 1000) end return _M

1142 字 · sdttttt

Socks5

SOCKS 是一种网络传输协议,主要用于客户端与外网服务器之间通讯的中间传递,SOCKS 是"SOCKetS"的缩写。 SOCKS5 是 SOCKS4 的升级版,其主要多了鉴定、IPv6、UDP 支持。 SOCKS5 协议可以分为三个部分: (1) 协议版本及认证方式 (2) 根据认证方式执行对应的认证 (3) 请求信息 (1)协议版本及认证方式 创建与 SOCKS5 服务器的 TCP 连接后客户端需要先发送请求来协议版本及认证方式, VER NMETHODS METHODS 1 1 1-255 VER 是 SOCKS 版本,这里应该是 0x05; NMETHODS 是 METHODS 部分的长度; METHODS 是客户端支持的认证方式列表,每个方法占 1 字节。当前的定义是: 0x00 不需要认证 0x01 GSSAPI 0x02 用户名、密码认证 0x03 - 0x7F 由 IANA 分配(保留) 0x80 - 0xFE 为私人方法保留 0xFF 无可接受的方法 服务器回复客户端可用方法: VER METHOD 1 1 VER 是 SOCKS 版本,这里应该是 0x05; METHOD 是服务端选中的方法。如果返回 0xFF 表示没有一个认证方法被选中,客户端需要关闭连接。 代码实现: ...

618 字

To Zola

生活还是比较紧凑,没那么多时间捣鼓 blog 了,这次来到了 zola,尽可能少折腾一点。 后面我应该会自己开发一个 Blog 生成器,尽可能功能简单。

7 字

尝试写一个strlen

#include <stdio.h> extern int strlen2(char *str); int main() { char a[] = "hello,world"; int len = strlen2(a); printf("%s len:%d \n", a, len); return 0; } SECTION .data SECTION .text global strlen2 strlen2: mov rax, rdi next: cmp byte [rax], 0 je down inc rax jmp next down: sub rax, rdi ret

51 字 · sdttttt

第一个裸机程序

今天尝试写我的第一个裸机程序,虚拟机使用bochs,这个虚拟机配置很容易,也比较简单,非常新手。 # bochs 配置文件 # 设置Bochs 在运行过程中能够使用的内存,32MB megs: 32 # BIOS和显示BIOS romimage: file=/home/admin123/Desktop/bochs/share/bochs/BIOS-bochs-latest vgaromimage: file=/home/admin123/Desktop/bochs/share/bochs/VGABIOS-lgpl-latest # 软盘,不用 # floppya: 1_44=a.img, status=inserted # 使用硬盘 # boot: floppy boot: disk # 日志文件的输出。 log: bochs.out # 关闭鼠标 mouse: enabled=0 keyboard_mapping: enabled=1,map=/home/admin123/Desktop/bochs/share/bochs/keymaps/x11-pc-us.map # 硬盘设置 ata0-master: type=disk, path="hd60M.img", mode=flat, cylinders=121, heads=16, spt=63 ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 # gdb的支持,1234 端口调试 gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0 [org 0x7c00] [bits 16] BOOT_MAIN_ADDR equ 0x500 readdiskmsg db "ReadDisk...", 0 global _start _start: xor ax, ax mov ds, ax mov es, ax mov ss, ax mov fs, ax mov sp, 0x7c00 mov ax, 3 int 0x10 mov ecx, 2 mov bl, 2 mov dx, 0x1f2 mov al, bl out dx, al inc dx mov al, cl out dx, al inc dx mov al, ch out dx, al inc dx shr ecx, 16 mov al, cl out dx, al inc dx mov al, ch and al, 0b1110_1111 out dx, al inc dx mov al, 0x20 out dx, al mov si, readdiskmsg call print .hd_ready_check: mov dx, 0x1f7 in al, dx and al, 0b0000_1000 cmp al, 0b0000_1000 jnz .hd_ready_check mov dx, 0x1f0 mov cx, 256 mov edi, BOOT_MAIN_ADDR .read_boot: in ax, dx mov [edi], ax add edi, 2 loop .read_boot jmp BOOT_MAIN_ADDR ;; mov si, string ;; call print print: mov ah, 0x0e mov bh, 0 mov bl, 0x01 .print_loop: mov al, [si] cmp al, 0 jz .print_done int 0x10 inc si jmp .print_loop .print_done: ret times 510 - ($ - $$) db 0 db 0x55, 0xaa 汇编具体就不解释了,太累了。 ...

250 字 · sdttttt

固定搭配

接不定式(而不接动名词)作宾语的24个常用动词 afford to do sth. 负担得起做某事 agree to do sth. 同意做某事 arrange to do sth.安排做某事 ask to do sth. 要求做某事 beg to do sth. 请求做某事 care to do sth. 想要做某事 choose to do sth. 决定做某事 decide to do sth. 决定做某事 demand to do sth. 要求做某事 determine to do sth. 决心做某事 expect to do sth. 期待做某事 fear to do sth. 害怕做某事 help to do sth. 帮助做某事 hope to do sth. 希望做某事 ...

2590 字

关于前端构建的碎碎念

稍微谈一下现在的前端构建学到的一些东西. 打包器 这个东西本身的功能是比较单纯的, 就是将工程的整个依赖图画出来, 然后打包到单个文件里面去. 比较主流的就是 Webpack, 其他还有 sonwnpack, rollup(这个稍微有点特别), Parcel, 最后还有最近新出现的 vite. 优化: 例如压缩 Js, CSS, HTML, 摇树, 调整图像大小, 以及分包等机制.所有的优化基本都是为了能在打开网站时更快的载入页面. 扩展: 前端的技术鱼龙混杂, 光开发语言的衍生亚种就非常多, 打包器就需要能支持这些语言的编译器. 部分代码优化也在这里完成. 扩展性基本决定了一个打包器的命运和社区发展. 这两点基本所有的打包器都支持. 接下来说一些有差异化的地方. Webpack 究极老牌的打包器了, Webpack 在 5 版本之前是出了名的重和慢还有繁, 扩展性和社区都极佳, 基本所有的前端技术你都能在 wp 上找到对应的 loader 或者 plugin. 也是目前最流行的打包器了. Webpack5 出现了之后速度提升了很多. webpack-chain和webpack-merge使用这两个第三方包配合可以做到大部分的配置复用. 但是配置依然很重和繁琐这一点, 一直都没有很好的方案. var webpack = require("webpack"); module.exports = { entry: "./entry.js", //入口文件 output: { //node.js中__dirname变量获取当前模块文件所在目录的完整绝对路径 path: "dist", //输出位置 filename: "bundle.js", //输入文件 }, module: { loaders: [ { test: /\.css$/, //支持正则 loader: "style-loader!css-loader", }, { test: /\.vue$/, loader: "vue-loader", }, ], }, //其他解决方案配置 resolve: { extensions: ["", ".js", ".json", ".css", "vue"], //添加在此的后缀所对应的文件可以省略后缀 }, //插件 plugins: [new webpack.BannerPlugin("This file is created by ly")], }; Parcel 继 Webpack 之后新出现的打包器, 解决了 Webpack 的一个非常大的痛点, Parcel 可以做到零配置启动. 自身就集成了 parcel 所有的东西, 你只需呀一个小小的 index.html 作为入口, 其他的全部解析都交给 Parcel, Parcel 内部还集成了一个 Js 编译器, 并且由于该编译器使用的是 Rust 语言编写它的执行速度非常快. 理论上应该比 esbuild 还要快. Parcel 刚出现的时候风评并不好, 因为不支持 source-map, 并且摇树还有 bug.. ...

363 字

记录一次软路由故障

我目前的网关结构是: 本机 → ROS 网关, 然后根据数据包的类型来决定要不要路由到OpenWrt的机器上。 Openwrt主要是作用就是梯子,机器的网络由singbox的TUN全局接管。 一般只有dns请求,以及非国内IP还有FakeIP会被路由到Wrt上。 其他IP 一律直连。 一晚上还是没弄好,明天再检查。 昨天升级固件之后了之后发现梯子网络出现了故障,经过我一番检修,具体情况: 节点测速正常 国内网络访问正常 国外网络访问出现断断续续的问题,有时能打开有时打不开 IPv6以及IPv4连接正常 TG之类的IP直连不需要DNS解析的软件不受影响 又经过我一番检修(一晚上+一上午+一下午),大概确认了问题: 目标地址为IPv6的DNS请求无法被正确劫持到Wrt上 局域网内机器关闭IPv6之后就能正常访问国内外网 很神奇,我的配置从来没变过,也就是说这个问题一直存在,IPv6的DNS请求就从来没正确被劫持过。 以前的固件预计是按照默认DNS请求方式使用IPv4作为主要网络层协议。现在升级固件之后突然变成IPv6了。 我的ROS并不是通过防火墙NAT来劫持DNS的,而是通过防火墙标记+策略路由的方式来进行DNS劫持。 不过看起来我的IPv6策略路由没有排上用场,IPv4倒是可以正常工作。 查了很多IPv6和ROS的资料,还是不清楚为什么策略路由不生效。 没办法了,目前只能把IPv6的DNS请求直接在ROS上丢弃掉,这样客户端就会尝试使用IPv4,难受啊。 今天解决了IPv6的路由问题: 原因是我在IPv6和v4上用的是同一个路由表名,之后把名字换了就好了。 但是这很奇怪,因为IPv6和v4的Routing是完全分开的,虽然表名相同,但是内部指向的路由规则却完全不同。 我只能将这个理解为ROS的独特设计… 过了几个星期,IPv6的转发情况还是不太稳定,有时能用,有时不能用.

31 字 · sdttttt

硬盘LBA28读取以及BootLoader加载

⚠这篇文章比较无聊,因为涉及到一些硬件相关的东西,所以大部分的知识内容都很刻板,基本只能当作字典用。 之前讲了关于主引导扇区上的内容,这次就来讲讲BootLoader具体是怎么编写和加载系统的. 首先我们需要知道硬盘是如何工作的,以及它的结构。 🤣服了,搞个软件还得知道硬件的工作方法就离谱。 首先每个扇区的大小是固定在512字节的,现代硬盘的寻址方式一般都是通过LBA(逻辑块寻址)来进行。老式的叫做CHS(柱面-磁头-扇区)。这篇文章主要使用的是LBA28方式,也就是最高支持28位寻址。 当下的计算机应该采用的是更高位的LBA了。不过基本原理都是差不多的。 硬盘内部也是存在类似寄存器的结构,我们在汇编中会用端口的方式来访问它们。 端口地址 作用 说明 0x1F0 数据寄存器 负责数据管理,用于读取或写入数据 0x1F1 错误寄存器 / 特性寄存器 记录错误信息(读)、设置功能(写) 0x1F2 扇区计数寄存器 指定待读取或写入的扇区数 0x1F3 LBA 低 8 位 LBA 地址的 0-7 位 0x1F4 LBA 中 8-15 位 LBA 地址的 8-15 位 0x1F5 LBA 高 16-23 位 LBA 地址的 16-23 位 0x1F6 设备寄存器 选择主盘/从盘,LBA 高 24-27 位 0x1F7 状态寄存器 / 命令寄存器 读时返回状态,写时执行命令 数据寄存器(0x1F0) 作用:用于 读取/写入数据,一次传输 16 位(2 字节)。 数据大小:一个扇区(512 字节)= 256 次 16 位传输。 扇区计数寄存器(0x1F2) 作用:指定要读/写的 扇区数。 数值范围:1-255,0 表示 256 个扇区。 LBA 地址寄存器 LBA 地址由 28 位组成,分布在 4 个寄存器: ...

312 字 · sdttttt