PlayStation Portable(PSP)架构

Rodrigo Copetti 的实用分析

译者:Jepe

经典版 - 最后更新于:2024年3月31日

可用语言:🇬🇧 - English, 🇨🇳 - 简体字, 👋 - 添加翻译


关于此版本

'“经典版”是 “现代版” 的替代版本。 它不需要 Javascript、最新的 CSS 或复杂的 HTML 支持就能工作。 它更适合电子书用户、过时的浏览器或使用无障碍工具的读者阅读。另外,电子书用户现在可以从这里查看 电子书版

两个版本内容完全相同, 只是交互式部件被简化为纯 HTML。 如果读者想尝试“完整版”,可以使用切换回原始文章的链接。

和其他文章一样,这篇文章可在 Github 上查看,这样读者可以报告错误或提出修改。 这里还有一个 前置阅读材料 可用来帮助理解该系列文章。作者还接受 捐助 以帮助提高现有文章和即将发表的文章的质量。


目录

  1. 相关影像
  2. 快速入门
  3. 主CPU
    1. 世纪之交的MIPS
    2. 新型可携带CPU
    3. 协处理器
    4. 集中式内存管理
    5. 可用内存
    6. 总线设计
    7. 应对拥塞
    8. 总结
  4. 多媒体 CPU
  5. 图形
    1. 显示
    2. Graphics Engine介绍
    3. Graphics Engine架构
    4. 硬件组织
    5. 功能
      1. 指令
      2. 矢量处理
      3. 光栅化
      4. 纹理
      5. 像素操作
      6. 观察
    6. 交互模型
    7. 视频输出
  6. 音频
    1. 音频对比
  7. I/O
    1. 内部接口
    2. 外部接口
    3. 商业配件
    4. 与家用主机连接
  8. 操作系统
    1. 架构设计
      1. 模块
      2. 内核/IPL
      3. 其他部分
    2. 启动过程
    3. Visual Shell
    4. 可更新性
  9. 游戏
    1. 开发生态
    2. 存储介质
      1. UMD 光盘
      2. 记忆棒
    3. 网络服务
      1. PlayStation Network
      2. PlayStation Store
      3. 可更新内容
  10. 反盗版和自制软件
    1. 物理安全
      1. KIRK
      2. Lepton
      3. SPOCK
    2. 软件安全
    3. 击败
      1. 早期错误
      2. 降级
      3. Pandora
      4. CFW及其他
    4. 鼓励自制
  11. 这就是全部了,伙计们。
  12. Copyright and permissions
  13. 来源 / 继续阅读
  14. 参与贡献

相关影像

型号

Image
初版PSP(PSP1000 ,代号 "Fat")。
2004年12月12日于日本发售,2005年3月24日于美国发售,2005年9月1日于欧洲发售
Image
改进版PSP(PSP2000 ,代号 "Slim")。
2007年5月9日于日本发售,2007年9月6日于美国发售,2007年9月20日于欧洲发售
Image
进一步改进版PSP(PSP3000 ,代号 "Brite"),银色版
2008年10月14日在美国发布,2008年10月16日在日本发布,2008年10月17日在欧洲发布。
Image
重新设计的PSP(PSPN1000,代号 "Go")。
2009年10月1日于美洲和欧洲发布,2009年11月1日于日本发布。

主板

Image
主板
麻雀虽小,五脏俱全
CPU 与内存之间的之字形总线用于修正总线的长度,确保所有信号同时到达。 由此可见技术发展之快!
"Slim"版本之后,Tachyon 和"NAND + SDRAM"合而为一。
Image
带有重要部件标签的主板

图示

Image
主架构图
"Slim "版本之后,NAND 和 SDRAM 的容量增加了一倍(各为 64 MB)

快速入门

任天堂 DS发布仅一个月后,索尼用 PSP 证明”横向创新”并不是在便携式游戏机市场取得成功的唯一途径。

本文献给那些想了解 PSP 运行原理的人。 本文篇幅不短,但我希望在文章结束时,您能掌握这款游戏机的构成要素(设计原理、CPU 的选择、GPU 管线、安全系统等)。


主CPU

与任天堂类似,索尼也构建了一个极其紧凑的片上系统 (SoC),其中包含了我们将会讨论的大部分组件。 其中包括负责执行游戏和其他程序的主CPU(之后我们会讨论它与其他CPU的不同)。 该 SoC 被索尼称为Tachyon(在看了星际迷航之后?)

Image
原始 PSP 型号上的 Tachyon 芯片

主 CPU 同样由索尼自主设计,保持了 MIPS 的传统。 话虽如此,PlayStation 2发布至今已有四年, MIPS的现状如何?

世纪之交的MIPS

MIPS 的黄金岁月停留在 90 年代,一去不回。 其母公司 SGI 在廉价 x86 工作站面前失去了主导地位,而且资金短缺。 因此,它在 1999 年出售了 MIPS [1] 的大部分股份。 自此之后,MIPS 再次成为一家独立的公司,但竞争却比以往更加激烈。

该公司的第一项决定是承认 MIPS CPU 不再适用于高性能计算领域。 因此,他们将重点转向低功耗计算,与空前流行ARM正面交锋。

MIPS 重新审视了其臃肿的 CPU 系列,并将其整合为 三个指令集 [2]

最大的不同是这些 MIPS 架构现在将同步推进,而不是在下一个架构推出后立即放弃上一个架构。 新版本将以”Release x”为后缀,如”MIPS32 Release 6”或”MIPS32R6”(巧合的是,这也是迄今为止的最后一个版本)。

除 ISA 外,MIPS 还开始销售一系列新的 IP 核。 例如,MIPS32 4k 实现了MIPS32 R2 ISA,它有不同的变体,并提供大量定制功能。

言归正传,索尼可能获得了 MIPS32 4k 的授权,并通过扩展 ISA 和捆绑特定协处理器对其进行了定制 [3]。 它被称为Allegrex,运行速度在33 MHz 到 333 MHz的范围内可变。

新型可携带CPU

Allegrex 是一款完整的 32 位核心,提供了 [4] [5]

总之: Allegrex 快得令人难以置信。 但我们仍然不知道用它能做什么。 毕竟,你可以把CPU想象成交响乐团的指挥,而我们…… 还不了解演奏者。

协处理器

和其他 MIPS CPU 一样,Allegrex 有三个协处理器插槽。 索尼使用了其中两个:

集中式内存管理

现在我们来看内存单元。 它的工作方式看起来有些原始,但却是满足本主机需求的最佳方式。

Image
使用 MPU 进行内存寻址

传统的内存管理单元(MMU)负责 CPU 对周围组件的访问。 这意味着 CPU 的所有地址线都与 MMU 相连,只有后者与系统的其他部分相连。

这有助于实现”虚拟内存”和”内存保护”等功能。 而要实现虚拟内存,MMU 必须包含一个名为”地址转换后援缓冲器”(TLB,Translation Look-aside Buffer)的组件,以保证性能。 但是Allegrex 的 MMU 并没有 TLB,因此它侧重于内存保护功能。 所以 Allegrex 的 MMU 被称为 MPU(内存保护单元)。 MPU 是阉割了虚拟内存的 MMU。 而内存保护赋予系统决定程序可以访问哪些内存位置的权力。

有了这一点,Allegrex 就不必处理用户态程序(如游戏)访问受限位置(如加密密钥)的问题。 为了实现访问限制,内存地址被分为五个具有不同权限级别的段。 此外,Allegrex 的 MPU 包含三种操作模式:用户模式监管模式内核模式

如果一个在用户模式下运行普通进程想要访问特权位置中的内存地址,MPU 将通过”异常”询问操作系统是否授予该进程权限。

总而言之,这使得操作系统的开发商索尼公司可以通过硬件执行安全系统。

可用内存

到目前为止,我们已经分析了 PSP 的主 CPU 及其加速器。 现在,让我们来看看该系统中可用的物理内存。

Image
从主 CPU 角度看内存布局

PSP 使用了两个可从 CPU 访问的内存:

总线设计

您很快就会发现,PSP 可容纳许多功能独特的组件。 为了不重复以前的错误,工程师们使用专用总线将它们相互连接起来。 因此,只有功能类似的部分组件才会共享同一条总线。 这些总线通过专用仲裁器以”内存控制器”或直接内存访问(DMA)的形式相互通信。

Tachyon 中的所有总线都采用了高级高性能总线 (AHB,Advanced High-performance Bus) ,这是 Arm 为解决其芯片和 SoC 的拥塞问题而开发的一种解决方案。 例如Wii中也使用了 AHB。

Image
该系统中三条主要总线的基本布局

根据上述原则,PSP 使用了以下几种总线:

所有三条总线都连接到主存所在的 DDR 控制器。

应对拥塞

每条总线内部都有多个独立工作的组件。 它们将在共享空间(如主 RAM)中存储处理过的数据。 我们不希望 CPU 需要在模块从内存中读取或写入数据时进行干预。 总线一般使用 DMA 单元来提供这种功能,但单个 DMA 功能有限。 PSP 内的大量组件会导致读写瓶颈。

解决方案非常简单:总线主控。 简而言之,每个组件都有自己的 DMA 控制器。 它们能作为”总线主控”,控制总线访问它们想要访问的任何位置。 为避免多个”总线主控”同时运行时的竞争情况,相邻组件将确认事件,并等待操作完成。

总结

80-90 年代的 RISC 革命催生了无数 CPU,仅有少数 CPU 得以存活到新世纪。 正如我在Dreamcast一文SuperH 分析的结论中提到的,是时候向并行计算领域的先驱 MIPS CPU 道别了。

历经辗转之后,MIPS 现在只是一家设计 RISC-V CPU 的公司。 平心而论,这项战略为该公司提升了竞争力,使其能够与 ARM 竞争。 无论如何,PlayStation Portable 将是我这一系列文章中最后一篇采用 MIPS CPU 的文章。

然而,回顾我的分析,很难理解这样一家才华横溢的公司会失去市场份额。 诚然,在工作站市场上,英特尔的 x86 不管受到多少批评,都因其设备价格低廉(得益于其奔腾系列以及那些 “克隆”产品)和兼容软件(仅限 Windows)而胜出。 而P6 架构为英特尔提供了最初只有 RISC 才能实现的可扩展性。

在低功耗计算领域,由于和 ARM 有着相似的商业模式(IP 授权),MIPS的退步就更难理解了。 幸运的是,2011 年计算机历史博物馆的一次采访也提出了同样的问题,并得到了这样的回答:

我们犯了错误,我们没有意识到手机市场的重要性。 早期无利可图(……),但 ARM 的投资得到了收益。 这是非常明智的举动,其成果令人难以置信。 我们只看到了毛利率,然后说”这件事收益不足! 我们最好把注意力放在别处”,但当然,手机变成了智能手机,[然后] 发展出庞大的市场。 [6]

John Hennessy,MIPS计算机系统公司创始人之一

尽管如此,我相信虽然我们不会再看到新的 MIPS CPU,但我们会看到它的前工程师将其独特技术应用到新项目中的成果。


多媒体 CPU

到现在为止,我们已经讨论了 Tachyon 的主 CPU 和总线,但在 SoC 中还有许多特性等待我们去发现。 特别是,还有一个为特定应用而设计的模块:多媒体。 该组模块专注于音频和图像处理,包括两者的结合(视频处理),运行时不占用主 CPU 组(“系统组”)的带宽。

Image
Daxter (2006)
使用此模块渲染的游戏内过场动画

新模块被称为媒体引擎组,由以下部分组成:

开发者无法直接操作媒体引擎,索尼通过复杂的API隐藏了所有的操作细节。 官方软件开发工具包(SDK)包括”libmpeg”或”libmp3”等库,这些库已经实现了针对该引擎优化的完整应用程序。


图形

首先,让我们来看看主机的物理屏幕,这是用户可以欣赏到本节将要讨论的所有内容的地方。

显示

PSP 配备了4.3 英寸 TFT 液晶屏。 分辨率为480x272 (作为参考,像素数量相当于任天堂 DS 的 2.6 倍),最多可显示 16,777,216 种颜色。 色彩深度为 24 位(即所谓的 “真彩色”)。

长宽比为几乎16:9,这种比例在当时正逐渐成为家用电视机的标准。 请注意,更大的视野范围也为游戏设计师提供了改进游戏体验的机会(尤其是在第一人称射击类游戏中)。

Graphics Engine介绍

现在我们来谈谈负责生成像素的组件–Graphics Engine (GE)。 该引擎位于”系统组”中,因此可以将其视为 “组中组”。 下面是它取得的一些成果:

Image
王国之心:梦中诞生(2010)
Image
蜘蛛侠3(2007)
Image
侠盗猎车手:罪恶都市传奇(2006)
Image
模拟人生2(2005)
Image
OutRun 2006:海岸至海岸(2006)
Image
乐克乐克(2006)
PSP 游戏示例。 全部以最大分辨率(480x272 )显示。

GE 负责绘制带有多种特性的 3D 图形(多边形),包括纹理映射、光照等,稍后您将看到这些特性。

Graphics Engine架构

GE子系统有许多有趣的特点值得一提,所以这部分会非常复杂。 别害怕! 为了避免混淆,我会尽量一步一步来。

首先,GE 由三个部分组成:

采用这种设计的原因是主 CPU 和图形核心都可以访问这 2 MB 的 eDRAM。 因此,为防止拥塞,GE 内部的流量会通过另一条名为本地总线的高级高性能总线(AHB)(从 GE 的角度看是”本地”)。 这允许图形核心执行其功能时无需系统总线来移动数据,防止系统其他部分阻塞。

Image
Graphics Engine架构

本地总线与系统总线(128 位)一样宽,如果这还不够,图形核心还通过 512 位总线(由两条单向 256 位总线组成)直接连接 eDRAM。 在下一节中,您将看到它的必要性。

CPU 和 GE 之间如何通信? 如前所述,CPU 和图形核心都可以读取 eDRAM。 此外,图形核心还可以访问系统总线,从任何其他组件(包括主 RAM)获取数据。 这一切并不是凭空发生的。

简而言之,两个总线矩阵重新配置了本地总线和系统总线之间的连接。 每当有组件要访问”外部”总线时,总线矩阵就会对通信进行配置,使其中一个单元成为两条总线的主控单元,而不会出现其他重叠,这种情况会持续到指定的单元完成内存传输。

这种行为让我想起了众所周知的总线控制技术,即主导组件是”总线主控”,完全控制总线,其余组件是”从属”,等待命令。 不过,我不确定索尼工程师试图复制的是哪种协议/标准。 根据我的理解,我认为它可能与 I²C 有些类似,它是一种用于串行通信的协议(尤其适用于嵌入式系统),也执行总线控制。

硬件组织

现在,我们已经了解了各个组件及其相互之间的交互方式,让我们来看看有哪些与图形相关的信息可以存入内存。

GE 最终将向三个内存位置提取或填充数据:

功能

与 PSP 的家用表亲一样,PSP 的图形系统侧重于光栅化。 不过,PSP 的 VRAM 只有 PS2 的一半大,总线速度也没有 PS2 快。 作为补偿,PSP的图形引擎采用了矢量处理器!

Image
Graphics Engine管线设计
跳过了复杂的接口部分

图形管线与 PS2 非常相似,只是增加了矢量处理阶段。 图形核心分为两个部分:表面引擎,负责矢量处理;渲染引擎,顾名思义,负责光栅化和效果处理。

虽然过去 [10] 已对其功能进行过解释,但图形管线本身的细节尚未说明。 事实上,程序员并不依赖这些信息来制作游戏。 不过,为了进行分析,我自己推导出了一个模型。

另外,我决定让这篇文章比以前的文章更具技术性。 我认为这是学习新概念和拓宽对计算机图形学视野的好机会。 说到这里,我强烈建议大家在继续阅读之前先了解一下 PS1PS2 图形系统。

指令

Image
指令处理阶段

Graphics Engine通过存储在主内存中的传统”显示列表”(display lists)进行控制。 CPU 构建它们,GPU 通过 DMA 读取。 显示列表告诉GPU要绘制什么、如何绘制以及在哪里绘制。 对于 PSP 而言,显示列表不仅限于渲染任务,还可以包括矢量转换。

为了确保 CPU 和 GPU 能够并行工作而不相互阻塞,处理列表的策略至关重要。 我们希望GPU加速操作,而不是成为负担。 因此,CPU 和 GPU 支持延迟渲染(deferred rendering),这种技术允许 CPU 在 GPU 处理前一组显示列表时构建下一组显示列表。 GE 通过指定显示列表在内存中的起始位置(基地址)和终止位置(停滞地址)来配置。 因此,有两种分配列表的方式:

此外,索尼还表示 GPU 的 DMA 单元不仅仅是一个 “傻瓜式内存复制器”,它还能理解传输的数据 [11]。 因此,显示列表可以包括 jumpreturn命令,以触发 DMA 分支并从其他地方获取数据。 这样,CPU 就不必在显示列表中嵌入模型、纹理等大型资源,减少了内存复制和带宽消耗。 这个系统继承自 PS2。

最后,DMA 还可以解释边界数据:结合存储在 GE 中的信息,DMA 将跳过不在显示区域内的绘制命令。 也可以在其他边界框内声明边界框,不过这个话题留到以后再说吧!

矢量处理

Image
矢量处理阶段

图形引擎首次具备了操作矢量的能力,这有助于减轻 CPU 的负担。 索尼公司使用它来加速过去经常由 PS2 的 VPU(矢量处理单元)通过微码[12] 执行的任务。 虽然 GE 不如 VPU 灵活(GE 是一个固定功能单元),但它确实简化了许多编码工作(考虑到微码的学习曲线)。 GE 的矢量处理器被称为表面引擎(surface engine)。

表面引擎承担三种任务。 首先是对参数曲面的操作 [13]。 还记得“无限世界”(Infinite Worlds)章节吗? 索尼公司解释说,虽然 PS2 有能力实现,但最终只有少数游戏使用了这个功能。 可能的原因包括多边形性能,以及设计和实现的难度。

为了解决这个问题,表面引擎实现了两种参数曲线:

两者都支持细节层次(levels of detail),这意味着开发人员可以设置任意值来改变细分级别,以影响生成模型的质量。

第二项任务称为顶点混合(vertex blending),这是一种用于动画的技术。 表面引擎提供了两种类型:

需要指出的是,CPU 可能仍需要计算动画来处理游戏逻辑(如碰撞检测),因此它无法分担 CPU 上的所有工作。

最后,曲面引擎还提供剪切功能,即丢弃视口/矩形区域外的顶点。

光栅化

Image
光栅化阶段

图形生成的下一阶段在渲染引擎(rendering engine)中进行(跳过指令处理器)。 在这里,矢量数据被转化为像素,与市面上的其他 GPU 基本一致。

引擎可绘制多种类型的图元,包括点、线、线段、三角形、三角形条、三角扇形,以及由二维矩形组成的精灵。 它还包含一个名为”数字差分分析器”(digital differential analyse)的单元,用于在光栅化和纹理映射过程中对数值进行插值。

开发人员可以提供一个投影矩阵来应用透视变换。 这将把他们的 3D 世界发送到 2D 空间(这样你就能在屏幕上看到它),并使用虚拟摄像头作为模型。

索尼并没有提供太多关于光栅工作原理的具体信息,因此也不清楚每个周期能够处理多少像素。 亚像素精度等现代功能被认为已经实现(否则,用户就会立即发现其缺失)。

纹理

Image
纹理映射阶段

对于一些人来说,这可能是最感兴趣的话题。 已是像素的多边形上可以绘制纹理。 在这一阶段,纹理贴图从内存中获取,并通过多种功能进行处理。 这一过程被称为纹理映射

渲染引擎有三种映射模式,换句话说,有三种处理纹理贴图的方法:

纹理可使用颜色查找表(CLUTs,Colour Lookup Tables)。 此外,该引擎还应用透视校正双线性或三线性过滤进行插值。

另外,GE 中有 8 KB 纹理缓存,以节省带宽。 它采用”最近最少使用”(Lru)的方式管理。

最后,虽然该管线不可编程,但开发人员可以发送额外的颜色与纹理混合。 此外,还有颜色加倍(将颜色的 RGB 值翻倍)、颜色添加(将主要颜色与次要颜色结合)和雾化 (在远处的多边形上添加雾效果)。

像素操作

Image
像素操作阶段

我们即将到达管线的尽头。 最初的几何图形已经转化为丰富多彩的像素,是时候决定如何处理它们了。

有些像素可能对应于本帧不需要的几何图形(它可能被遮挡、遮罩等)。 为了过滤掉这些像素,GE可以执行以下测试:

之后,像素还会通过以下可选的模块进行进一步的效果处理:

抗锯齿 这样的复杂功能是通过上述功能策略性组合实现的。 最后,输出的像素被写入帧缓冲区,然后再发送显示。

观察

事实证明,PSP 继承了 PS2 的各种功能。 但与提供许多需要手动配置的通用可编程单元相比,现在的功能都被硬编码在芯片上。 我推测这样做有两个原因:一是为了减少晶体管的数量,这样它就能装入 Tachyon 并保持主板的”便携性”,二是为了方便将 PS2 代码移植到新的主机上。

交互模型

为了说明该系统对模型设计的影响,并将其与 PS2Nintendo DS 进行比较,以下是两个为 PSP 设计的模型示例。 别忘了,查看器是可互动的!

Image Image Image “现代版本”中可用的互动模型
合金装备:掌上行动 加强版(2006)
1,383个三角形
Image Image Image “现代版本”中可用的互动模型
Daxter(2006).
1,374个三角形

视频输出

该控制台的第一个型号(1000)在左下角(音频插孔旁边)有一个名为远程端口(remote port)的专有视频端口。

Image
PSP(3000 型)右下角的专有”视频输出”接口

远程端口使用 RS-232 协议 [14],这是一种古老的串行数据传输标准。 尽管这个协议没有公开给开发者,也没有文档记录,但市场上还是出现了几款带有控制按钮的音频耳机。 显然,它们使用串行端口向主机发送播放、暂停等命令。

在后来的型号(2000 和 3000)中,远程端口增加了一个额外的 YCbCr 引脚。 索尼提供了三种视频线缆(component、S-Video 和composite),用户可以通过该接口在电视上看到 PSP 屏幕上的内容。

视频电缆将以逐行或隔行扫描模式发送分辨率为720x480(NTSC)或 720x576(PAL)的图像(后一种仅适用于 3000 型)。 由于 PSP 的分辨率为 480x272 像素,游戏将显示黑边以校正宽高比。 不过,当控制台运行”XMB”可视化界面时,黑边将不会显示,该界面原生支持根据视频线缆调整其分辨率。


音频

(请注意,本节没有篇幅对每个术语进行定义和解释。 对于不常见的术语,您通常可以在本系列的其他文章中找到更全面的解释。 我已经尽可能地提供了链接。)

在本节中,我们经常会提到 PSG, 序列器大型混音器。 因为归根结底,专用音频硬件的目的是将音频操作从 CPU 上转移。 不过,如果这些硬件”弱”,就会降低主机的音响能力。

PSP 中的”声音硬件”非常简陋:只有两个 PCM 通道和一个立体声混音器。 最大采样率和分辨率分别为48 kHz16 位

这里没有我在第一段中提到的任何加速器。 那么,这是否意味着声音会像其他案例一样受限? 不! 因为 PSP 的硬件短板可以通过软件来弥补。

虽然没有大量与声音相关的电路,但索尼提供了许多通用元件。 这些元件可以帮助进行音频解码、流处理和混音。 也就是Media Engine

这块组件在信号处理方面非常出色,但需要对其进行编程。 因此,索尼为媒体引擎编写了以下软件,以补充两个 PCM 通道(我们称之为 “端”)[15] [16]

游戏无法直接访问这些模块。 相反,它们会调用官方 SDK 中的许多库。 一些库操作原始信号,而另一些库则针对特定应用进行优化。 示例包括:

音频对比

让我们看看游戏是如何展现声音的。 我写的特殊播放器可以让你在不同的游戏机之间比较:

“现代版本”中的互动播放器
音频采样
任天堂 DS: 最终幻想 4(2007 年)
PSP: 最终幻想 4 完全版(2011 年)
“现代版本”中的互动播放器
音频采样
PlayStation 2: 王国之心(2005 年)
PSP: 王国之心:梦中诞生(2010 年)

在第一个例子中,任天堂 DS 游戏会实时序列化声音,而 PSP 版本则解码 ATRAC3 格式的音频。 正如您所听到的,没有专用音效硬件本身并不意味着音质更差。 恰恰相反,媒体引擎的功能比以前大多数便携式游戏机的声音芯片更强。

第二个例子更难量化。 我放了一段 PS2 的音轨作比较,但我不得不提高 PS2 版的音量(我推测 PSP 的音轨声音会大一些,以弥补较小扬声器和与用户距离的不足)。 此外,请注意不同平台的编曲略有不同。 这可能只是一种创意上的改变,因为 PSP 版是在 PS2 游戏五年后发布的。 总体而言,PSP 的性能并没有下降(考虑到 PS2 的 SPU2 非常强大和灵活)。


I/O

PSP拥有丰富的接口和传感器。 不过,本节会介绍之前尚未提及的芯片组。 它们在处理玩家输入上发挥着重要作用。

内部接口

大多数可用 I/O 都连接在外设总线中。 它只有 32 位宽,但足以以正常速度传输简单信息。 它还可以访问主RAM。

十字键、摇杆和按钮输入通过特殊芯片处理,它被称为“System Control”或 SysCon。 这是索尼硬件的常用代号,用于连接各种内部组件,本例中仅用于连接物理按键。

外部接口

该主机具有相当数量的接口[18]

商业配件

由于使用了标准USB接口,其他公司得能为该主机设计配件。

Image
PSP(型号 3000)的顶部
注意mini USB 周围两个用于固定配件的孔

商业配件的示例包括:

有趣的是,这些小工具也可用于 Pocket PC 和 PDA 。 这不禁让人怀疑索尼是否将 PSP 定位为青少年的掌上电脑

与家用主机连接

PlayStation 3 发布后,PSP 有了一项新功能:Remote Play。 通过 WiFi 连接,PSP 可以远程控制 PS3。

这比 Wii U 上市早了很多年,对吧? 遗憾的是,只有少数 PS3 游戏支持远程游玩,这意味着用户只能浏览菜单、进行多媒体操作或玩 PlayStation 1 游戏。


操作系统

近些年来,负责在游戏开始前控制主机的程序变得越来越复杂,这主要是由于对安全性和服务(可更新 API、在线多人游戏、多媒体等)的需求不断增加。 PSP 试图在非常有限的硬件条件下实现所有功能。 我并不是说结果十分中庸,但这些决策都是平衡成本、性能和稳健性的结果。

架构设计

首先,PSP 在 Tachyon 内包含一个隐藏、无文档的 4 KB ROM,其中包含引导加载程序。 换句话说,CPU 在接通电源后,就会在其中查找指令。 该 ROM 有很多名字,如”Bootrom”、“Pre-IPL”或”Lib-PSP iplloader”。 后者是索尼的内部代号。

系统的其余部分保存在主板上的 32 MB NAND 闪存内。 这里是 PSP 操作系统(OS)的主体部分。

操作系统由以下组件组成:

模块

模块在 PC/Windows 中被称为”程序”或”驱动程序”。 模块加载后可驻留在内存中,并执行以下任务 [19]: - 暴露函数以简化对特定硬件的访问。 - 作为前台程序运行(如游戏)。

模块的二进制文件可以被加密或解密。 它还嵌入了元数据,以区分”用户模块”或是”内核模块”;后者允许新模块控制内存中的特权区域(也就是内核所在区域)。

模块由”内核”或”Visual Shell”(VSH)启动。 用户模块可在内核的允许下运行其他模块。 这加强了安全性——例如,内核永远不会从通用媒体磁盘(UMD)上加载内核模块。

内核/IPL

虽然该操作系统本身不包含内核,但它有多个组件来履行传统内核的职责。

首先是 IPL,它由 Pre-IPL 加载,负责初始化硬件。 IPL 中名为 IDStorage 的部分还存储了控制台的唯一信息(如 MAC 地址、序列号和 UMD 身份验证密钥) [20]。 覆盖最后一个区域会导致灾难性后果! 因此,UMD 密钥会被多次复制,以防损坏。

然后,IPL 会加载一组内核模块,用于处理底层操作(内存管理、多线程和文件系统)。 它们还实现了由 MPU 触发的内存访问异常(还记得分段吗?) 简单起见,我在本文中使用”内核”一词时,指的就是这些内核模块。

尽管如此,内核并不进行多任务处理,但它确实为单个进程实现了协作式多线程。

只要主机通电,内核就会一直存在内存中,因为程序(用户模块)不是为裸机编写的。 相反,用户模块依赖于内核模块暴露的函数。 因此,内核预留了 4 MB 主内存和另外 4 MB”易失性内存”(用于许多操作的临时缓冲区,根据请求允许访问)。 这样,用户程序只能使用 24 MB 主 RAM(总共32 MB)。

其他部分

NAND 中还存储了固件的其他部分。

首先是Visual Shell或”VSH”,这是用户打开 PSP 后首先看到的东西。 VSH 是一个图形用户界面,允许用户运行游戏和其他模块(仅限用户模块)。 它由多个模块组成,其中一些按需加载。

一个奇怪的事实是:用于启动零售游戏的系统调用首先会重启主机,然后加载可执行文件。 可能是为了卸载 VSH,为游戏释放资源。

其次,NAND 中还有第二个分区,用于存储用户相关数据,如网络设置。 该分区称为”flash1”(与”flash0”相对),其内容称为 系统设置

启动过程

既然我们已经确定了主要部件,那么让我们看看它们是如何组织起来,使主机开机后进入”工作状态”的。 安全问题在此仅作简要讨论,下一节将进行更深入的介绍。

复杂的启动过程如下 [21] [22]

  1. 主 CPU 的复位向量置为 0x1FC00000,指向 Tachyon 内部的 Pre-IPL ROM。
    1. Pre-IPL 的前半部分告诉 CPU 将另一半复制到便笺存储器,然后继续执行。
      • 之后,Pre-IPL 将从 NAND 或外部记忆棒中查找下一阶段的内容。 当选择后者时(在正常使用情况下从不选择),PSP 会进入工厂服务模式。 为简单起见,我们将重点讨论正常模式(选择 NAND)。
    2. Pre-IPL 初始化 NAND 控制器,并从 NAND 继续执行。 Pre-IPL 的第二部分运行 IPL,这会解密加密的 IPL(使用”KIRK”,详情稍后介绍),并作为工作区复制到Graphics Engine中的 eDRAM 上。
    3. 解密完成后,它会继续在解密后 IPL 所在的 eDRAM 中执行。
  2. IPL 的执行过程分为三个阶段。
    1. 第一阶段称为 loader,重置主 CPU 并从内存映射中隐藏 Pre-IPL ROM。 加载程序还会初始化最低需求硬件,并在 eDRAM 中解压下一阶段的”Main.bin”。
    2. Main.bin主要用于初始化其余硬件,包括主存。 完成后,它会将第三阶段解密到主存中,然后继续执行。
    3. 最后一个阶段称为payload,它会加载内核。 内核以不同二进制文件、模块和元数据的形式存储,一旦加载到主存中,就能赋予系统生命。 随后就能显示交互式界面。

Visual Shell

该主机首次推出了(至少在国际上)著名的XrossMediaBar或”XMB”。 这是随 PSP 一起发布的功能丰富的图形用户界面。

Image
主屏幕(未插入或安装游戏)
Image
XMB 包括照片和视频查看器
Image
游戏 “类别允许运行游戏、管理存档或搜索其他 PSP(游戏共享)
当用户选择实际的游戏项目时,XMB 会使用游戏提供的资产调整样式,直到用户选择其他项目
Image
“设置”类别提供了大量自定义选项
某些项目将许多设置控件组合在一起
Image
这就是你在主机中打字的方式,老式手机风格

从人机交互的角度来看,XMB 为许多交互难题的提供了非常有趣的解决方法(例如深度的信息中进行导航,避免向用户提供大量选项,以及将所有这些解决方案布置在4.3英寸的屏幕上)。 从本质上讲,信息通过”类别”和”元素”组织,又通过十字键在类别和元素之间导航。 左右箭头在类别之间切换,上下箭头从类别中选择元素。 值得注意的是,所有类别都在同一层级结构中。 因此,没有条目显示在其他条目之上(阻碍了吸引注意力的广告等的插入)。

此外,XMB 还提供自定义选项,例如更改背景颜色和重新排列项目。 它还提供多媒体服务,也允许用户加载游戏(无论是 UMD 还是记忆棒)。

它还有用于多媒体和存档管理的内置文件查看器。

可更新性

正如我们之前所看到的,除 Pre-IPL 之外的所有内容都存储在可写存储器中,因此是”可更新”的。 索尼以可下载文件的形式分发固件更新。 用户可以手动下载,或使用 XrossMediaBar 上的”系统更新”助手通过 Wifi 自动下载和安装更新。

Image
系统更新向导

一些更新通过在启动过程中增加更多的加密层和对内核模块进行完整性验证来加强PSP的安全系统。

从开发人员的角度来看,一些更新通过添加更多功能和修正现有功能来增强API。 因此,游戏与其开发的系统版本强绑定,用户必须更新才能玩到更新的游戏。 新的更新总是向后兼容的,所以理论上老游戏在更新的系统上应该不会出错。

从用户的角度来看,一些更新带来了新的服务,如网络浏览器、RSS 阅读器等。 PlayStation 3 发布后,许多在线应用被移植到 PSP 上,如”PlayStation 商店”和”Remote Play”。


游戏

在这个系列中,第一次出现不是针对裸机编写的游戏:为该主机开发的游戏不再依赖内存地址和端口,而是必须调用模块来执行硬件上的操作。 官方SDK中的API就是根据这种设计模型构建的。

开发生态

索尼为游戏工作室提供的开发工具包由 SN Systems(PS1 和 PS2 工具包的作者)开发。 软件包运行环境为 Windows XP 上的 Cygwin 或 CentOS Linux。

在这个工具包中,我们可以找到以下内容:

最初,索尼只提供了一个模拟器来调试 PSP 软件。 后来,它被PSP Hardware Tool所取代:一个类似 PC 的塔式计算机连接到假的 PSP 外壳(类似于任天堂 DS 工具包)。 开发工具包通过一个名为ProDG的软件与工作站连接(仅适用于 Windows)。

存储介质

PS1 和 PS2 有两种存储介质:一种是用于加载游戏的只读光盘,另一种是用于存储存档和可执行文件的可重写”存储卡”。 PSP延续了这一传统。 考虑到这是他们的第一款主流便携式游戏机,索尼是如何找到适合不同工作场景的介质的? 考虑到他们是BetaMaxMiniDisc等格式的创造者,你可以猜猜他们这次又做了什么…… 推出更多格式。

UMD 光盘

Image
典型的零售游戏

CD 和 DVD 太大,又容易复制。 另一方面,传统的读取器在晃动的环境中无法工作(那些在走路时用随身听听 CD 的人知道我在说什么)。 因此,索尼的解决方案是从头开始开发一种名为通用媒体光盘(Universal Media Disc,UMD)的专有介质。

UMD 的容量为 900 MB 或 1.8 GB内容,取决于单层还是双层。 UMD 不仅在物理上与 DVD 或 MiniDVD 有区别,其内部结构也不同。 除游戏外,索尼还发布了”UMD 视频”和”UMD 音频”格式,允许其他分销商向 PSP 用户提供内容——请记住,这是 2004 年(当时 iPod Photo 只有 2 英寸显示屏)。

这些光盘带有一个不可拆卸的外壳;中心是磁性的,因此一旦插入光盘,它就会吸附在读卡器的电机上。

记忆棒

Image
记忆棒和 SD 卡

存储卡的”便携式”同类产品是Memory Stick Pro Duo,它是索尼坚持为泛滥的市场提供另一种介质的又一产物(还记得当年有多少选项吗? 甚至flashcarts也能容纳许多可选项)。 这款产品的发布正值消费类摄影和手机的蓬勃发展时期,当时人们希望以低廉的价格获得大量存储空间;在SD卡接管一切之前。

与其他产品一样,记忆棒是一种协议,能以简便的方式将内部存储器(如闪存)与外设连接起来。 因此,您可以在不拆卸任何部件的情况下在电脑和相机之间交换记忆棒。 PSP使用的”Pro Duo”容量高达 32 GB,读取速度为1.23 MB/s,写入速度为0.54 MB/s

PSP 依靠记忆棒来存储用户相关内容,如存档、媒体文件和游戏。 它用 FAT32 文件系统格式化。 记忆棒中嵌入的控制器可包含 MagicGate DRM。

文件内容没有映射在内存中:文件系统通过内核模块的系统调用访问文件。

网络服务

最终,索尼赶上了竞争对手,改进了其在线基础设施。 它甚至提供了微软或任天堂尚未提供的服务。

PlayStation Network

Image
XMB 中的 PSN

为了应对微软的Xbox Live和任天堂的Nintendo WiFi Connection,索尼拥有了自己的在线服务…… PlayStation Network,简称PSN。

这项服务取代了 PlayStation 2 上原始的 DNAS。 其中一项新增功能就是中央认证系统。

用户可以使用主机注册免费的 PSN 帐户,这样就可以通过 WiFi 连接与全球各地的其他人共同游戏。

值得一提的是,PSP 最初并不包括很多在线服务。 随着 PlayStation 3 的发布,情况发生了翻天覆地的变化,这就是后话了……

PlayStation Store

Image
PlayStation Store

在 PlayStation Network 亮相之后,另一产品就是PlayStation Store。 顾名思义,它是一个在线商店,允许用户购买数字游戏并下载到记忆棒上。

我想这为小型游戏工作室提供了巨大方便,因为实体发行总是意味着巨大的成本,最终会影响游戏的价格。 PSP的后期型号”PSP Go”,通过取消 UMD 读取器强制从实体介质转移,它只能玩从 PlayStation Store 购买的游戏。

后来,随着PS1 游戏的到来,游戏数量急剧扩张。 这些游戏可以被下载到记忆棒中,并且能像其他数字游戏一样游玩。 PSP上的PS1二进制文件使用软件模拟;索尼在系统中内置了一个模拟器,使所有这些都能无缝运行。

可更新内容

Image
XMB 中的 “更新游戏”

最后但同样重要的一点是,在线服务提供了以”更新”的形式直接下载游戏补丁到主机的机会。

不过当时,使用这一功能的游戏并不多。 在大型游戏更新往往会在游戏上架之前发布首日补丁的今天很难想象这一点……


反盗版和自制软件

虽然这是一款便携式游戏机,但这并不意味着它的安全性就应该比 PS2 弱。 从各种意义上讲,情况恰恰相反—— PSP 上采用的安全系统非常多样化,有些部分至今仍是个谜。

现在,我们都知道它的实现方式存在隐患,最终导致了自制软件和盗版的出现,但考虑到它是 2004 年发布的便携式游戏机,你可能会发现与竞争对手相比,它捆绑了某些最先进的算法。

物理安全

下面我将介绍运行安全相关操作的三种主要芯片。 对于初学者来说,算法可能相当复杂,但我还是会试着简单介绍一下。 如果您觉得有趣,请不要忘记查看参考文献,这篇文章主要关注的还是 PSP 本身。

在整个介绍过程中,请记住,出于安全原因,索尼没有公开这些信息的文档,此外,索尼还为与安全相关的例程贴上了愚蠢的标签。

此外,我无法逐一介绍每种密码系统,因为这些复杂的话题会使文章偏离主要目标。 不过,我还是请大家从其他渠道了解每种算法背后的逻辑。

KIRK

首先,我们来看 KIRK,它是 Tachyon 的另一个组件。 KIRK 是以下算法的硬件实现(可将其视为加速器)[23] [24]

简而言之,CPU 向 KIRK 发送指令(如”使用算法 x 和密钥 y 加密此字符串”)。 KIRK 也可以作为总线主控,因此它可以立即将结果存储到主 RAM 中。

Lepton

众所周知,UMD 光盘不易复制,其内容也是以加密形式存储的。 不过,用户永远不会注意到这一点,因为解密过程是由硬件执行的。

与 Tachyon 并行的另一个名为 Lepton 的 SoC 可控制 UMD 驱动器,并充当主 CPU 和 UMD 内容之间的中介。

Lepton 中包含大量电路,你甚至可以认为它是 PSP 内的另一台计算机。 该组件包括自己的 CPU、用于解码的 DSP、作为缓冲区的 480 KB 内存以及用于存储固件的 384 KB ROM。

主 CPU 通过 ATAPI 协议与 Lepton 通信,该协议是一般用于传统 CD/DVD 驱动器与 PC 的连接。 但主要区别在于,Lepton 只有在光盘被识别为真实光盘的情况下才能解密 UMD 中的数据。

SPOCK

除了由 Lepton 处理的加密系统外,UMD 的扇区也使用 AES 加密。 SPOCK 是和 KIRK 同级的另一个区块,主要用于解密 UMD 光盘的扇区。

在 NAND 闪存中,IDStorage 存储了一个被称为”主密钥”的加密密钥。 SPOCK 包含用于解密的硬连接密钥。 解密后的主密钥会被 SPOCK 用来解密 UMD 中的另一个密钥。 然后使用后一个密钥读取每个扇区。 Easy-peasy!

顺便一提,尽管 SPOCK 位于 Tachyon 内部,但它由 Lepton 控制。

总之,通过硬件中集成的程序,系统在执行游戏时无需消耗通用资源来加密/解密。

软件安全

操作系统将利用硬件构建一个安全系统。 总之,软件保护遵循以下原则:

击败

尽管有种种安全措施,黑客们似乎从未放弃过对这款主机的研究,也许是因为它的诸多优点对自制软件开发有巨大的吸引力。 请注意,这一领域的内容数量惊人,所以我必须在某个地方划出休止符。 因此,这里只提及一些重大发现。 如果想要知道更多的话,playstationdev.wiki 保存了一份完整的档案。

早期错误

PSP 在日本发布后不久,就有用户级漏洞被挖掘出来。 其中一些使用了早期固件版本中存在的安全漏洞:

这些早期错误帮助建立了 PSP 内部运行方式的知识库,从而能开发出更多的攻击载体和软件程序,以便与硬件进行交互(请记住,只有游戏工作室才能获得官方 SDK 和文档)。

就像其他猫鼠游戏一样,索尼以被新游戏依赖的系统更新作为回应,而更新的漏洞(所谓的 “TIFF”、“GTA”漏洞等[25])则不断出现。 值得一提的是,由于尚未获得内核访问权限,它们只能被视为”自制程序的起点”。

降级

Image
Chronoswitch 降级器,一款现代化的降级工具

索尼公司凭借带有安全补丁的强大固件更新和像网络浏览器这样吸引人的功能更新系统之后,旧版本就成了某种应许之地,高级用户可以在这里运行他们的自制软件。 然而,要获取特定系统版本的 PSP 变得越来越困难。 因此,“降级”迅速流行起来。 降级与升级相反,是将当前安装的固件替换为更早更容易利用的版本。

执行降级的常见方法包括利用漏洞欺骗系统安装旧的更新文件。 这并不容易,因为它依赖于越来越少的最新版本上的漏洞。

最终,市场上出现了两种”modchips”:“Undiluted Platinum”和”PSP-Devolution”。 这两款产品在出厂时都配备了单独的 NAND 芯片,用作次级 NAND 存储,使用户能够启动可利用的次级固件或替换主固件。 这种方法仅支持 PSP 1000 型号,因为后来的型号合并了 Tachyon 和 NAND + DDR SDRAM 的封装。

Pandora

猫鼠游戏终结于”Pandora”的到来。

“Pandora 电池法”是一个广受欢迎和尊重的成就集合。 它设法绕过了大部分安全层,并把重点放在了索尼无法快速反应的地方:Pre-IPL。 这是 Pandora 成功的方法 [26]

剩下的工作就是嵌入一个有效的载荷。 最受欢迎的选项包括”de-bricker”,它可以在 PSP 上重新安装一个干净的官方固件(如果 NAND 先前已损坏,则可以修复它)、“降级器”或自定义固件安装程序。

别忘了,所有这些都是艰巨的任务,特别是考虑到 KIRK 没有被逆向,并且使 Pre-IPL “跳转”的加密块必须通过暴力计算得出。

CFW及其他

Image
有些 CFW 包括特殊模块,用于操作底层选项

Pandora 对索尼来说是一个沉重的打击——它是一个有效的引导程序漏洞,就像任天堂 DS一样,只能以新硬件的形式修复。

此外,在潘多拉发布之前,所谓的定制固件(Custom Firmware)或称”CFW”也早已到来。 CFW 是经过修改的官方固件(如加入了自制模块)。 这些定制模块享有内核权限,而且正如你可能猜到的那样,它们可以完全控制主机。 新模块的例子包括 ISO 加载器、签名禁用器、低级 CPU 管理、“插件”加载器(无需重新安装固件即可添加更多自定义功能),以及许许多多其他模块。 黑客们制作了他们自己的版本,如 M33、PRO 和 ME。

利用任何内核级漏洞,CFW 可以在当前固件上安装(这是最早的方法)。 不过,它只能利用 Pandora 曾经使用的漏洞绕过签名检查自动启动。 否则,用户需要要依赖猫鼠游戏漏洞重新启动 CFW。 这就是为什么最新的 PSP 型号无法使用老办法启动 CFW。

最后一根稻草是PlayStation 3安全系统黑客攻破,因为PS3 的操作系统包含一个 PSP 模拟器,其中包含用于解密 PSP 可执行文件的私钥。 这使得任何人都可以对嵌入内核漏洞的用户级软件进行签名,以生成 CFW 安装程序和/或 CFW 加载程序等。

最近,有人发现最新固件在启动过程中包含一个内核漏洞,可用于启动所选择的 CFW。 这被打包在名为 Infinity 2 [27] 的解决方案中。

总而言之,索尼公司声称 UMD 无法破解是正确的。 毕竟,黑客攻击的实现反而要归功于众多软件缺陷。

鼓励自制

自制软件开发不仅局限在破坏安全机制上,还有一些社区致力于为自制软件开发者提供必要的工具,使他们能够在不受法律影响的情况下构建自己的软件。 例如,pspdev 小组发布了一个名为PSDK的开源 SDK,该 SDK 复刻了许多官方接口,并且没有施加索尼的限制。

PSPSDK 还包括一个处理编译和打包过程的工具包,就像官方 SDK 一样,但目标是运行了 CFW 的 PSP。


这就是全部了,伙计们。

Image
为本文购买的PSP
这就是大人想扮酷时常买的东西😉(我有一台 DS)

你刚刚阅读了有关智能手机和平板电脑主宰市场之前的最后一款便携式游戏机的内容! 这让我们了解用户在二十一世纪初对便携式掌上电脑的服务/功能的期望,以及这种期望在接下来的十年中是如何演变的。

尽管如此,我还是要感谢 PSP Homebrew 社区的 discord,他们不仅花时间校对了这篇无尽的文章,还为我提供了更多的信息。 该小组的许多成员致力于开发免费工具和自制应用程序,以扩展该主机的功能。 同时,我还要向参考资料中列出的文档的作者表示感谢。 我花了大约 3 个月的时间来撰写这篇文章,但这要归功于其他人多年来为反向工程设计这款主机所付出的努力。

至于下一篇文章,我需要先花一两个月的时间来处理 GitHub repo 上提交的所有问题和请求,并对网站进行一些维护工作,但请放心,我会努力让下一篇文章和这篇文章一样完整!

下篇文章见!
Rodrigo


参与贡献

这篇文章是 游戏主机架构 系列的一部分。如果您觉得我的文章很有趣,请考虑捐赠。您的资助将用于购买工具和资源,以帮助我提高现有文章和即将发表的文章的质量。

Donate with PayPal
Become a Patreon

你也可以购买英语版本的电子书。我会将获得的利润视为捐赠。

Image

特别感谢下列人员的捐助:

或者,您可以通过 建议更改添加翻译 来提供帮助。


Copyright and permissions

This work is licensed under a Creative Commons Attribution 4.0 International License. You may use it for your work at no cost, even for commercial purposes. But you have to respect the license and reference the article properly. Please take a look at the following guidelines and permissions:

Article information and referencing

For any referencing style, you can use the following information:

For instance, to use with BibTeX:

@misc{copetti-psp,
    url = {https://classic.copetti.org/writings/consoles/playstation-portable/},
    title = {PlayStation Portable (PSP) Architecture - A Practical Analysis},
    author = {Rodrigo Copetti},
    year = {2021}
}

or a IEEE style citation:

[1]R. Copetti, "PlayStation Portable (PSP) Architecture - A Practical Analysis", Copetti.org, 2021. [Online]. Available: https://classic.copetti.org/writings/consoles/playstation-portable/. [Accessed: day- month- year].

Special use in multimedia (Youtube, Twitch, etc)

I only ask that you at least state the author’s name, the title of the article and the URL of the article, using any style of choice.

You don’t have to include all the information in the same place if it’s not feasible. For instance, if you use the article’s imagery in a Youtube video, you may state either the author’s name or URL of the article at the bottom of the image, and then include the complete reference in the video description. In other words, for any resource used from this website, let your viewers know where it originates from.

This is a very nice example because the channel shows this website directly and their viewers know where to find it. In fact, I was so impressed with their content and commentary that I gave them an interview 🙂.

Appreciated additions

If this article has significantly contributed to your work, I would appreciate it if you could dedicate an acknowledgement section, just like I do with the people and communities that helped me.

This is of course optional and beyond the requirements of the CC license, but I think it’s a nice detail that makes us, the random authors on the net, feel part of something bigger.

Third-party publishing

If you are interested in publishing this article on a third-party website, please get in touch.

If you have translated an article and wish to publish it on a third-party website, I tend to be open about it, but please contact me first.


来源 / 继续阅读

反盗版

音频

CPU

图形

I/O

操作系统

其他媒体

影像