chore(vkernel): 重置基线 — 纳入 TPV codegen 修复配合的内核侧调整与既有工作区内容

- devfs.vp: string.split 传 PATH_BUFFER_SIZE(配合 split 新增容量参数)

- fat32_types.vp: lfn_extract 越界钳制(base+i > MAX_LFN 返回 -1)

- sheet.vp: gfx.Renderer 实参修正为 (fb, zb, w, h)(原单参导致 w/h=0 渲染空操作)

- 同批包含 VKernel 其余既有移植改动与 vpsdk/Apps/Libs 工作区内容
This commit is contained in:
TermiNexus committed 2026-09-11 14:27:01 +08:00
1 parent cd1cc915c5
commit a518f75b24
61 files changed
+9272 -9201

No files matched your search

+1
View File
@@ -57,6 +57,7 @@ ViperTemplateProject/
StandardTemplateProject/
# ViperOS 编译产物(每个子项目内的 output/ 和 temp/)
**/.tpv_build/
**/output/
**/temp/
**/*.deps.json
+21 -21
View File
@@ -25,9 +25,9 @@ YIELD_ROWS: t.CDefine = 4
V3_POOL_SIZE: t.CDefine = 8192
V3_POOL_BYTES: t.CDefine = V3_POOL_SIZE * 24 + 512
_v3_mem: t.CArray[t.CUInt8T, V3_POOL_BYTES]
_v3_mem: t.CArray[uint8, V3_POOL_BYTES]
_v3_pool: memhub.MemPool | t.CPtr
_fb_mem: t.CArray[t.CUInt32T, GW * GH]
_fb_mem: t.CArray[uint32, GW * GH]
class V3:
x: t.CFloat64T
@@ -35,7 +35,7 @@ class V3:
z: t.CFloat64T
def __new__() -> 'V3' | t.CPtr:
return t.CVoid(t.CUInt64T(_v3_pool.alloc(24)), t.CPtr)
return t.CVoid(uint64(_v3_pool.alloc(24)), t.CPtr)
def __init__(self, x: t.CFloat64T, y: t.CFloat64T, z: t.CFloat64T):
self.x = x
@@ -124,7 +124,7 @@ def hash3(x: t.CFloat64T, y: t.CFloat64T, z: t.CFloat64T) -> t.CFloat64T:
def stars(d: V3 | t.CPtr) -> V3 | t.CPtr:
col: V3 | t.CPtr = V3(0.0, 0.0, 0.0)
i: t.CInt = 0
i: int = 0
while i < 3:
s: t.CFloat64T = 80.0 + t.CFloat64T(i) * 90.0
px: t.CFloat64T = d.x * s
@@ -185,7 +185,7 @@ def trace(dir_v: V3 | t.CPtr, gT: t.CFloat64T) -> V3 | t.CPtr:
T: t.CFloat64T = 1.0
col: V3 | t.CPtr = V3(0.0, 0.0, 0.0)
i: t.CInt = 0
i: int = 0
while i < MAX_STEPS:
r2: t.CFloat64T = pos.dot(pos)
r: t.CFloat64T = vm.sqrt(r2)
@@ -238,7 +238,7 @@ def trace(dir_v: V3 | t.CPtr, gT: t.CFloat64T) -> V3 | t.CPtr:
i += 1
return col
def shade_pixel(px: t.CInt, py: t.CInt, gT: t.CFloat64T) -> t.CUInt32T:
def shade_pixel(px: int, py: int, gT: t.CFloat64T) -> uint32:
aspect: t.CFloat64T = GW_F / GH_F
sx: t.CFloat64T = (2.0 * (t.CFloat64T(px) + 0.5) / GW_F - 1.0) * aspect * FOVF
sy: t.CFloat64T = (1.0 - 2.0 * (t.CFloat64T(py) + 0.5) / GH_F) * FOVF
@@ -252,13 +252,13 @@ def shade_pixel(px: t.CInt, py: t.CInt, gT: t.CFloat64T) -> t.CUInt32T:
c.x = vm.pow(c.x, 1.0 / 2.2)
c.y = vm.pow(c.y, 1.0 / 2.2)
c.z = vm.pow(c.z, 1.0 / 2.2)
R: t.CInt = t.CInt(clmp(c.x, 0.0, 1.0) * 255.0)
G: t.CInt = t.CInt(clmp(c.y, 0.0, 1.0) * 255.0)
B: t.CInt = t.CInt(clmp(c.z, 0.0, 1.0) * 255.0)
return t.CUInt32T((R << 16) | (G << 8) | B)
R: int = int(clmp(c.x, 0.0, 1.0) * 255.0)
G: int = int(clmp(c.y, 0.0, 1.0) * 255.0)
B: int = int(clmp(c.z, 0.0, 1.0) * 255.0)
return uint32((R << 16) | (G << 8) | B)
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> t.CInt | t.CExport:
def _start() -> int | t.CExport:
global _v3_pool
_v3_pool = memhub.MemPool(c.Addr(_v3_mem), V3_POOL_BYTES)
setup_camera()
@@ -266,7 +266,7 @@ def _start() -> t.CInt | t.CExport:
root: vpui.Tk = vpui.Tk()
root.title("Gargantua")
root.set_style(window.STYLE_WIN7)
root.bg_color = t.CUInt32T(0x000000)
root.bg_color = uint32(0x000000)
master: vpui.Tk | t.CPtr = c.Addr(root)
canvas: vpui.FBCanvas = vpui.FBCanvas(master, GW, GH)
@@ -279,33 +279,33 @@ def _start() -> t.CInt | t.CExport:
root.geometry(100, 30, GW, GH + 32)
gT: t.CFloat64T = 0.0
rendered: t.CInt = 0
rendered: int = 0
evt: window.InputEvent
while window.is_active(root.win_id):
result: t.CInt = window.poll_event(c.Addr(evt))
result: int = window.poll_event(c.Addr(evt))
if result != 0:
if evt.type == window.EVENT_TYPE_PING:
window.flush(root.win_id)
elif evt.type == window.EVENT_TYPE_RESIZE:
sz: t.CInt = window.get_win_size(root.win_id)
new_w: t.CInt = sz >> 16
new_h: t.CInt = sz & 0xFFFF
sz: int = window.get_win_size(root.win_id)
new_w: int = sz >> 16
new_h: int = sz & 0xFFFF
canvas.set_fb(fb, new_w, new_h)
if rendered == 0:
y: t.CInt = 0
y: int = 0
while y < GH:
x: t.CInt = 0
x: int = 0
while x < GW:
pixel: t.CUInt32T = shade_pixel(x, y, gT)
pixel: uint32 = shade_pixel(x, y, gT)
fb[y * GW + x] = pixel
x += 1
y += 1
if y % YIELD_ROWS == 0:
root.redraw()
process.yield_cpu()
result2: t.CInt = window.poll_event(c.Addr(evt))
result2: int = window.poll_event(c.Addr(evt))
if result2 != 0:
if evt.type == window.EVENT_TYPE_PING:
window.flush(root.win_id)
+53 -53
View File
@@ -1,53 +1,53 @@
import vpsdk.vpui as vpui
import vpsdk.window as window
import vpsdk.process as process
import vpsdk.dynlib as dynlib
import vpsdk.stdlib as stdlib
import vpsdk.stdio as stdio
from stdint import *
import t, c
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> t.CInt | t.CExport:
base: t.CUInt64T = dynlib.load_so("/LIBS/SLOG.SO")
if base != 0:
dynlib.so_call1("log_info", "Hello from dynamic library!")
root: vpui.Tk = vpui.Tk()
root.title("Input Demo")
root.set_style(window.STYLE_WIN7)
root.geometry(290, 30, 300, 200)
root.bg_color = t.CUInt32T(0x1E1E32)
master: vpui.Tk | t.CPtr = c.Addr(root)
entry: vpui.Entry = vpui.Entry(master, 260, 28)
root.pack(0, vpui.PACK_TOP, vpui.FILL_X, 0, 20, 10)
result: vpui.Label = vpui.Label(master, "", t.CUInt32T(0x00FF00))
root.pack(1, vpui.PACK_BOTTOM, 0, 0, 0, 10)
def _on_submit() -> t.CInt:
text: t.CConst | str = entry.get()
result.config(text)
entry.delete(0, -1)
return 0
lbl: vpui.Label = vpui.Label(master, "Name:", 0xFFFFFFFF)
root.pack(2, vpui.PACK_TOP, 0, 0, 20, 0)
btn: vpui.Button = vpui.Button(master, 100, 36, "Submit", c.Addr(_on_submit))
root.pack(3, vpui.PACK_TOP, 0, 0, 0, 10)
root2: vpui.Tk = vpui.Tk()
root2.title("Test No-Resp")
root2.set_style(window.STYLE_WIN10)
root2.geometry(200, 50, 300, 150)
root2.bg_color = t.CUInt32T(0x1E1E32)
master2: vpui.Tk | t.CPtr = c.Addr(root2)
lbl2: vpui.Label = vpui.Label(master2, "This window will NOT respond!", 0xFFFFFFFF)
lbl2.place(10, 10)
root2.update()
root.mainloop()
process.exit(0)
return 0
import vpsdk.vpui as vpui
import vpsdk.window as window
import vpsdk.process as process
import vpsdk.dynlib as dynlib
import vpsdk.stdlib as stdlib
import vpsdk.stdio as stdio
from stdint import *
import t, c
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> int | t.CExport:
base: uint64 = dynlib.load_so("/LIBS/SLOG.SO")
if base != 0:
dynlib.so_call1("log_info", "Hello from dynamic library!")
root: vpui.Tk = vpui.Tk()
root.title("Input Demo")
root.set_style(window.STYLE_WIN7)
root.geometry(290, 30, 300, 200)
root.bg_color = uint32(0x1E1E32)
master: vpui.Tk | t.CPtr = c.Addr(root)
entry: vpui.Entry = vpui.Entry(master, 260, 28)
root.pack(0, vpui.PACK_TOP, vpui.FILL_X, 0, 20, 10)
result: vpui.Label = vpui.Label(master, "", uint32(0x00FF00))
root.pack(1, vpui.PACK_BOTTOM, 0, 0, 0, 10)
def _on_submit() -> int:
text: t.CConst | str = entry.get()
result.config(text)
entry.delete(0, -1)
return 0
lbl: vpui.Label = vpui.Label(master, "Name:", 0xFFFFFFFF)
root.pack(2, vpui.PACK_TOP, 0, 0, 20, 0)
btn: vpui.Button = vpui.Button(master, 100, 36, "Submit", c.Addr(_on_submit))
root.pack(3, vpui.PACK_TOP, 0, 0, 0, 10)
root2: vpui.Tk = vpui.Tk()
root2.title("Test No-Resp")
root2.set_style(window.STYLE_WIN10)
root2.geometry(200, 50, 300, 150)
root2.bg_color = uint32(0x1E1E32)
master2: vpui.Tk | t.CPtr = c.Addr(root2)
lbl2: vpui.Label = vpui.Label(master2, "This window will NOT respond!", 0xFFFFFFFF)
lbl2.place(10, 10)
root2.update()
root.mainloop()
process.exit(0)
return 0
+305 -305
View File
@@ -1,305 +1,305 @@
from stdint import *
import vipermath
import string
import t, c
PI: t.CDefine = float(3.14159265358979323846)
SPHERE_SLICES: t.CDefine = (24 * 1)
SPHERE_STACKS: t.CDefine = (16 * 1)
SIN_WAVE_GRID: t.CDefine = (40 * 1)
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | t.CInt:
return (255 << 24) | (r << 16) | (g << 8) | (b)
@t.Object
class Vec3:
x: float
y: float
z: float
def __init__(self, x: float, y: float, z: float):
self.x = x
self.y = y
self.z = z
def Sub(self, b: 'Vec3') -> 'Vec3':
return Vec3(self.x - b.x, self.y - b.y, self.z - b.z)
def Cross(self, b: 'Vec3') -> 'Vec3':
return Vec3(self.y * b.z - self.z * b.y, self.z * b.x - self.x * b.z, self.x * b.y - self.y * b.x)
def Dot(self, b: 'Vec3') -> float:
return self.x * b.x + self.y * b.y + self.z * b.z
def Norm(self) -> 'Vec3':
l = vipermath.sqrtf(self.Dot(self))
return Vec3(self.x / l, self.y / l, self.z / l)
class Mat4:
m: t.CArray[t.CArray[float, 4], 4]
def Mat4_Identity() -> Mat4:
m: Mat4 = Mat4()
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
m.m[0][0] = 1; m.m[1][1] = 1; m.m[2][2] = 1; m.m[3][3] = 1
return m
def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4:
res: Mat4 = Mat4()
string.memset(c.Addr(res), 0, Mat4.__sizeof__())
for i in range(4):
for j in range(4):
for k in range(4):
res.m[i][j] += a.m[i][k] * b.m[k][j]
return res
def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3:
x: float = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3]
y: float = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3]
z: float = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3]
w: float = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3]
if w != 0:
x /= w; y /= w; z /= w
return Vec3(x, y, z)
def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4:
m: Mat4 = Mat4()
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
f: float = float(1.0) / vipermath.tanf(fov / float(2.0))
m.m[0][0] = f / aspect; m.m[1][1] = f
m.m[2][2] = zf / (zn - zf); m.m[2][3] = (zf * zn) / (zn - zf); m.m[3][2] = -1
return m
def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4:
zaxis: Vec3 = eye.Sub(target).Norm()
xaxis: Vec3 = up.Cross(zaxis).Norm()
yaxis: Vec3 = zaxis.Cross(xaxis)
m: Mat4 = Mat4_Identity()
m.m[0][0]=xaxis.x; m.m[0][1]=xaxis.y; m.m[0][2]=xaxis.z; m.m[0][3]= -xaxis.Dot(eye)
m.m[1][0]=yaxis.x; m.m[1][1]=yaxis.y; m.m[1][2]=yaxis.z; m.m[1][3]= -yaxis.Dot(eye)
m.m[2][0]=zaxis.x; m.m[2][1]=zaxis.y; m.m[2][2]=zaxis.z; m.m[2][3]= -zaxis.Dot(eye)
m.m[3][3] = 1
return m
def Mat4_Translate(x: float, y: float, z: float) -> Mat4:
m: Mat4 = Mat4_Identity()
m.m[0][3] = x; m.m[1][3] = y; m.m[2][3] = z
return m
def Mat4_RotateY(a: float) -> Mat4:
m: Mat4 = Mat4_Identity()
m.m[0][0] = vipermath.cosf(a); m.m[0][2] = vipermath.sinf(a)
m.m[2][0] = -vipermath.sinf(a); m.m[2][2] = vipermath.cosf(a)
return m
@t.Object
class Surface:
fb: UINT32PTR
zb: float | t.CPtr
w: int
h: int
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
self.fb = fb
self.zb = zb
self.w = w
self.h = h
@t.Object
class Renderer:
_fb: UINT32PTR
_zb: float | t.CPtr
_w: int
_h: int
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
self._fb = fb
self._zb = zb
self._w = w
self._h = h
def Clear(self, color: t.CUInt32T):
fb: UINT32PTR = self._fb
zb: float | t.CPtr = self._zb
size: int = self._w * self._h
for i in range(size):
fb[i] = color
zb[i] = float(1.0)
def DrawLine2D(self, x0: int, y0: int, x1: int, y1: int, col: t.CUInt32T):
fb: UINT32PTR = self._fb
w: int = self._w; h: int = self._h
dx: int = abs(x1-x0); dy: int = abs(y1-y0)
sx: int = 1 if x0 < x1 else -1; sy: int = 1 if y0 < y1 else -1
err: int = dx - dy
while True:
if x0 >= 0 and x0 < w and y0 >= 0 and y0 < h: fb[y0 * w + x0] = col
if x0 == x1 and y0 == y1: break
e2: int = 2 * err
if e2 > -dy: err -= dy; x0 += sx
if e2 < dx: err += dx; y0 += sy
def DrawTriangle(self, v0: Vec3, v1: Vec3, v2: Vec3, col: t.CUInt32T):
if v0.z < float(0.0) or v1.z < float(0.0) or v2.z < float(0.0): return
if (v0.x > float(10.0) or v0.x < float(-10.0) or v0.y > float(10.0) or v0.y < float(-10.0) or
v1.x > float(10.0) or v1.x < float(-10.0) or v1.y > float(10.0) or v1.y < float(-10.0) or
v2.x > float(10.0) or v2.x < float(-10.0) or v2.y > float(10.0) or v2.y < float(-10.0)): return
fb: UINT32PTR = self._fb
zb: float | t.CPtr = self._zb
w: int = self._w
h: int = self._h
sx0: float = (v0.x + float(1.0)) * float(0.5) * w; sy0: float = (float(1.0) - v0.y) * float(0.5) * h
sx1: float = (v1.x + float(1.0)) * float(0.5) * w; sy1: float = (float(1.0) - v1.y) * float(0.5) * h
sx2: float = (v2.x + float(1.0)) * float(0.5) * w; sy2: float = (float(1.0) - v2.y) * float(0.5) * h
minX: int = max(0, int(vipermath.floorf(min(min(sx0, sx1), sx2))))
maxX: int = min(w - 1, int(vipermath.ceilf(max(max(sx0, sx1), sx2))))
minY: int = max(0, int(vipermath.floorf(min(min(sy0, sy1), sy2))))
maxY: int = min(h - 1, int(vipermath.ceilf(max(max(sy0, sy1), sy2))))
dx12: float = sx1 - sx2; dy12: float = sy1 - sy2
dx02: float = sx0 - sx2; dy02: float = sy0 - sy2
denom: float = dx12 * dy02 - dy12 * dx02
if denom < float(0.001) and denom > float(-0.001): return
invDenom: float = float(1.0) / denom
row_dxP_start: float = float(minX) - sx2
for y in range(minY, maxY + 1):
dyP: float = float(y) - sy2
dxP: float = row_dxP_start
row_base: int = y * w
for x in range(minX, maxX + 1):
w0: float = (dx12 * dyP - dy12 * dxP) * invDenom
w1: float = (dxP * dy02 - dyP * dx02) * invDenom
w2: float = float(1.0) - w0 - w1
if w0 >= 0 and w1 >= 0 and w2 >= 0:
z: float = w0 * v0.z + w1 * v1.z + w2 * v2.z
idx: int = row_base + x
if z < zb[idx]:
zb[idx] = z
fb[idx] = col
dxP += float(1.0)
def DrawGlowDot(self, x: float, y: float, radius: float, core_col: t.CUInt32T, intensity: float):
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
r: int = int(radius) + 4
ix: int = int(x); iy: int = int(y)
for dy in range(-r, r + 1):
py: int = iy + dy
if py < 0 or py >= h: continue
for dx in range(-r, r + 1):
px: int = ix + dx
if px < 0 or px >= w: continue
dist: float = vipermath.sqrtf(float(dx*dx + dy*dy))
if dist < radius:
self.BlendPixel(px, py, core_col, intensity)
elif dist < float(r):
fade: float = 1.0 - (dist - radius) / 4.0
self.BlendPixel(px, py, core_col, intensity * fade * 0.5)
def BlendPixel(self, x: int, y: int, col: t.CUInt32T, alpha: float):
if alpha <= 0.0: return
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
if x < 0 or x >= w or y < 0 or y >= h: return
idx: int = y * w + x
bg: t.CUInt32T = fb[idx]
bg_b: int = bg & 0xFF; bg_g: int = (bg >> 8) & 0xFF; bg_r: int = (bg >> 16) & 0xFF
f_b: int = col & 0xFF; f_g: int = (col >> 8) & 0xFF; f_r: int = (col >> 16) & 0xFF
a: int = int(alpha * 255.0)
inv_a: int = 255 - a
nr: int = (f_r * a + bg_r * inv_a) >> 8
ng: int = (f_g * a + bg_g * inv_a) >> 8
nb: int = (f_b * a + bg_b * inv_a) >> 8
fb[idx] = COLOR_RGB(255 if (nr > 255) else nr,
255 if (ng > 255) else ng,
255 if (nb > 255) else nb)
@t.Object
class Scene3D:
renderer: Renderer
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
self.renderer = Renderer(fb, zb, w, h)
def Render(self, time: float):
rw: int = self.renderer._w
rh: int = self.renderer._h
self.renderer.Clear(COLOR_RGB(15, 15, 25))
yaw: float = float(45.0) * PI / float(180.0); pitch: float = float(45.0) * PI / float(180.0); radius: float = float(10.0)
eye: Vec3 = Vec3(radius*vipermath.cosf(pitch)*vipermath.cosf(yaw), radius*vipermath.sinf(pitch), radius*vipermath.cosf(pitch)*vipermath.sinf(yaw))
target: Vec3 = Vec3(0, 0, 0); up: Vec3 = Vec3(0, 1, 0)
view: Mat4 = Mat4_LookAt(eye, target, up)
proj: Mat4 = Mat4_Perspective(PI / float(3.0), float(rw)/float(rh), float(0.1), float(100.0))
vp: Mat4 = Mat4_Mul(proj, view)
cubeX: float = float(-3.5)
cubeMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(cubeX, 0, 0))
self._DrawCube(cubeMVP, COLOR_RGB(180, 180, 180))
colors: t.CArray[t.CUInt32T, 4] = [COLOR_RGB(255,50,50), COLOR_RGB(50,50,255), COLOR_RGB(255,255,50), COLOR_RGB(50,255,255)]
for i in range(4):
a: float = time * float(1.5) + i * (PI / float(2.0)); r: float = float(3.0)
pos: Vec3 = Vec3(vipermath.cosf(a) * r + cubeX, 0, vipermath.sinf(a) * r)
sphereMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(pos.x, pos.y, pos.z))
self._DrawSphere(sphereMVP, Vec3(0,0,0), float(0.5), colors[i])
self._Draw3DSinWave(vp, Vec3(float(3.5), 0, 0), time)
self.renderer.DrawLine2D(50, rh - 150, rw - 50, rh - 150, COLOR_RGB(80, 80, 80))
self.renderer.DrawLine2D(50, rh - 50, 50, rh - 250, COLOR_RGB(80, 80, 80))
wave_shift: float = time * float(2.0)
prev_x: int = 50; prev_y: int = rh - 150 - int(vipermath.sinf(0 - wave_shift) * float(100.0))
for i in range(1, rw - 100):
tr: float = float(i) / float(rw-100) * float(4.0) * PI
cx: int = 50 + i; cy: int = rh - 150 - int(vipermath.sinf(tr - wave_shift) * float(100.0))
self.renderer.DrawLine2D(prev_x, prev_y, cx, cy, COLOR_RGB(0, 255, 100))
prev_x = cx; prev_y = cy
def _DrawCube(self, mvp: Mat4, col: t.CUInt32T):
v: t.CArray[Vec3, 8] = [
Vec3(-1, -1, -1), Vec3(-1, -1, 1), Vec3(-1, 1, -1), Vec3(-1, 1, 1),
Vec3( 1, -1, -1), Vec3( 1, -1, 1), Vec3( 1, 1, -1), Vec3( 1, 1, 1)
]
for i in range(8): v[i] = Mat4_MulVec(mvp, v[i])
faces: t.CArray[t.CArray[int, 3], 12] = [
[0, 2, 1], [1, 2, 3], [4, 1, 5], [4, 0, 1], [6, 3, 2], [6, 7, 3],
[4, 6, 0], [0, 6, 2], [5, 7, 4], [4, 7, 6], [1, 3, 5], [5, 3, 7]
]
for i in range(12): self.renderer.DrawTriangle(v[faces[i][0]], v[faces[i][1]], v[faces[i][2]], col)
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: t.CUInt32T):
step_pi: float = PI / SPHERE_STACKS; step_2pi: float = float(2.0) * PI / SPHERE_SLICES
for i in range(SPHERE_STACKS):
for j in range(SPHERE_SLICES):
theta1: float = i * step_pi; theta2: float = (i + 1) * step_pi
phi1: float = j * step_2pi; phi2: float = (j + 1) * step_2pi
v: t.CArray[Vec3, 4]
v[0] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi1))
v[1] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi2))
v[2] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi1))
v[3] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi2))
for k in range(4): v[k] = Mat4_MulVec(mvp, v[k])
self.renderer.DrawTriangle(v[0], v[1], v[2], col)
self.renderer.DrawTriangle(v[1], v[3], v[2], col)
def _Draw3DSinWave(self, vp: Mat4, pos: Vec3, time: float):
_range: float = float(2.0) * PI; step: float = _range / SIN_WAVE_GRID; scale: float = float(0.5)
mvp: Mat4 = Mat4_Mul(vp, Mat4_Mul(Mat4_Translate(pos.x, pos.y, pos.z), Mat4_RotateY(time * float(1.0))))
for i in range(SIN_WAVE_GRID):
for j in range(SIN_WAVE_GRID):
x0: float = -PI + i * step; z0 = -PI + j * step; x1: float = x0 + step; z1 = z0 + step
y00: float = vipermath.sinf(x0) * vipermath.cosf(z0) * scale; y10: float = vipermath.sinf(x1) * vipermath.cosf(z0) * scale
y01: float = vipermath.sinf(x0) * vipermath.cosf(z1) * scale; y11: float = vipermath.sinf(x1) * vipermath.cosf(z1) * scale
t1: float = (y00 / scale + float(1.0)) * float(0.5); r1: int = int(50 + 205 * t1); g1: int = int(80 + 120 * vipermath.sinf(t1 * PI)); b1: int = int(255 - 205 * t1)
col1: t.CUInt32T = COLOR_RGB(255 if (r1 > 255) else (0 if (r1 < 0) else r1), 255 if (g1 > 255) else (0 if (g1 < 0) else g1), 255 if (b1 > 255) else (0 if (b1 < 0) else b1))
t2: float = (y11 / scale + float(1.0)) * float(0.5); r2: int = int(50 + 205 * t2); g2: int = int(80 + 120 * vipermath.sinf(t2 * PI)); b2: int = int(255 - 205 * t2)
col2: t.CUInt32T = COLOR_RGB(255 if (r2 > 255) else (0 if (r2 < 0) else r2), 255 if (g2 > 255) else (0 if (g2 < 0) else g2), 255 if (b2 > 255) else (0 if (b2 < 0) else b2))
v00: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y00, z0)); v10: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y10, z0))
v01: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y01, z1)); v11: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y11, z1))
self.renderer.DrawTriangle(v00, v10, v11, col1); self.renderer.DrawTriangle(v00, v11, v01, col2)
from stdint import *
import vipermath
import string
import t, c
PI: t.CDefine = float(3.14159265358979323846)
SPHERE_SLICES: t.CDefine = (24 * 1)
SPHERE_STACKS: t.CDefine = (16 * 1)
SIN_WAVE_GRID: t.CDefine = (40 * 1)
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | int:
return (255 << 24) | (r << 16) | (g << 8) | (b)
@t.Object
class Vec3:
x: float
y: float
z: float
def __init__(self, x: float, y: float, z: float):
self.x = x
self.y = y
self.z = z
def Sub(self, b: 'Vec3') -> 'Vec3':
return Vec3(self.x - b.x, self.y - b.y, self.z - b.z)
def Cross(self, b: 'Vec3') -> 'Vec3':
return Vec3(self.y * b.z - self.z * b.y, self.z * b.x - self.x * b.z, self.x * b.y - self.y * b.x)
def Dot(self, b: 'Vec3') -> float:
return self.x * b.x + self.y * b.y + self.z * b.z
def Norm(self) -> 'Vec3':
l = vipermath.sqrtf(self.Dot(self))
return Vec3(self.x / l, self.y / l, self.z / l)
class Mat4:
m: t.CArray[t.CArray[float, 4], 4]
def Mat4_Identity() -> Mat4:
m: Mat4 = Mat4()
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
m.m[0][0] = 1; m.m[1][1] = 1; m.m[2][2] = 1; m.m[3][3] = 1
return m
def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4:
res: Mat4 = Mat4()
string.memset(c.Addr(res), 0, Mat4.__sizeof__())
for i in range(4):
for j in range(4):
for k in range(4):
res.m[i][j] += a.m[i][k] * b.m[k][j]
return res
def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3:
x: float = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3]
y: float = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3]
z: float = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3]
w: float = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3]
if w != 0:
x /= w; y /= w; z /= w
return Vec3(x, y, z)
def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4:
m: Mat4 = Mat4()
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
f: float = float(1.0) / vipermath.tanf(fov / float(2.0))
m.m[0][0] = f / aspect; m.m[1][1] = f
m.m[2][2] = zf / (zn - zf); m.m[2][3] = (zf * zn) / (zn - zf); m.m[3][2] = -1
return m
def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4:
zaxis: Vec3 = eye.Sub(target).Norm()
xaxis: Vec3 = up.Cross(zaxis).Norm()
yaxis: Vec3 = zaxis.Cross(xaxis)
m: Mat4 = Mat4_Identity()
m.m[0][0]=xaxis.x; m.m[0][1]=xaxis.y; m.m[0][2]=xaxis.z; m.m[0][3]= -xaxis.Dot(eye)
m.m[1][0]=yaxis.x; m.m[1][1]=yaxis.y; m.m[1][2]=yaxis.z; m.m[1][3]= -yaxis.Dot(eye)
m.m[2][0]=zaxis.x; m.m[2][1]=zaxis.y; m.m[2][2]=zaxis.z; m.m[2][3]= -zaxis.Dot(eye)
m.m[3][3] = 1
return m
def Mat4_Translate(x: float, y: float, z: float) -> Mat4:
m: Mat4 = Mat4_Identity()
m.m[0][3] = x; m.m[1][3] = y; m.m[2][3] = z
return m
def Mat4_RotateY(a: float) -> Mat4:
m: Mat4 = Mat4_Identity()
m.m[0][0] = vipermath.cosf(a); m.m[0][2] = vipermath.sinf(a)
m.m[2][0] = -vipermath.sinf(a); m.m[2][2] = vipermath.cosf(a)
return m
@t.Object
class Surface:
fb: UINT32PTR
zb: float | t.CPtr
w: int
h: int
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
self.fb = fb
self.zb = zb
self.w = w
self.h = h
@t.Object
class Renderer:
_fb: UINT32PTR
_zb: float | t.CPtr
_w: int
_h: int
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
self._fb = fb
self._zb = zb
self._w = w
self._h = h
def Clear(self, color: uint32):
fb: UINT32PTR = self._fb
zb: float | t.CPtr = self._zb
size: int = self._w * self._h
for i in range(size):
fb[i] = color
zb[i] = float(1.0)
def DrawLine2D(self, x0: int, y0: int, x1: int, y1: int, col: uint32):
fb: UINT32PTR = self._fb
w: int = self._w; h: int = self._h
dx: int = abs(x1-x0); dy: int = abs(y1-y0)
sx: int = 1 if x0 < x1 else -1; sy: int = 1 if y0 < y1 else -1
err: int = dx - dy
while True:
if x0 >= 0 and x0 < w and y0 >= 0 and y0 < h: fb[y0 * w + x0] = col
if x0 == x1 and y0 == y1: break
e2: int = 2 * err
if e2 > -dy: err -= dy; x0 += sx
if e2 < dx: err += dx; y0 += sy
def DrawTriangle(self, v0: Vec3, v1: Vec3, v2: Vec3, col: uint32):
if v0.z < float(0.0) or v1.z < float(0.0) or v2.z < float(0.0): return
if (v0.x > float(10.0) or v0.x < float(-10.0) or v0.y > float(10.0) or v0.y < float(-10.0) or
v1.x > float(10.0) or v1.x < float(-10.0) or v1.y > float(10.0) or v1.y < float(-10.0) or
v2.x > float(10.0) or v2.x < float(-10.0) or v2.y > float(10.0) or v2.y < float(-10.0)): return
fb: UINT32PTR = self._fb
zb: float | t.CPtr = self._zb
w: int = self._w
h: int = self._h
sx0: float = (v0.x + float(1.0)) * float(0.5) * w; sy0: float = (float(1.0) - v0.y) * float(0.5) * h
sx1: float = (v1.x + float(1.0)) * float(0.5) * w; sy1: float = (float(1.0) - v1.y) * float(0.5) * h
sx2: float = (v2.x + float(1.0)) * float(0.5) * w; sy2: float = (float(1.0) - v2.y) * float(0.5) * h
minX: int = max(0, int(vipermath.floorf(min(min(sx0, sx1), sx2))))
maxX: int = min(w - 1, int(vipermath.ceilf(max(max(sx0, sx1), sx2))))
minY: int = max(0, int(vipermath.floorf(min(min(sy0, sy1), sy2))))
maxY: int = min(h - 1, int(vipermath.ceilf(max(max(sy0, sy1), sy2))))
dx12: float = sx1 - sx2; dy12: float = sy1 - sy2
dx02: float = sx0 - sx2; dy02: float = sy0 - sy2
denom: float = dx12 * dy02 - dy12 * dx02
if denom < float(0.001) and denom > float(-0.001): return
invDenom: float = float(1.0) / denom
row_dxP_start: float = float(minX) - sx2
for y in range(minY, maxY + 1):
dyP: float = float(y) - sy2
dxP: float = row_dxP_start
row_base: int = y * w
for x in range(minX, maxX + 1):
w0: float = (dx12 * dyP - dy12 * dxP) * invDenom
w1: float = (dxP * dy02 - dyP * dx02) * invDenom
w2: float = float(1.0) - w0 - w1
if w0 >= 0 and w1 >= 0 and w2 >= 0:
z: float = w0 * v0.z + w1 * v1.z + w2 * v2.z
idx: int = row_base + x
if z < zb[idx]:
zb[idx] = z
fb[idx] = col
dxP += float(1.0)
def DrawGlowDot(self, x: float, y: float, radius: float, core_col: uint32, intensity: float):
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
r: int = int(radius) + 4
ix: int = int(x); iy: int = int(y)
for dy in range(-r, r + 1):
py: int = iy + dy
if py < 0 or py >= h: continue
for dx in range(-r, r + 1):
px: int = ix + dx
if px < 0 or px >= w: continue
dist: float = vipermath.sqrtf(float(dx*dx + dy*dy))
if dist < radius:
self.BlendPixel(px, py, core_col, intensity)
elif dist < float(r):
fade: float = 1.0 - (dist - radius) / 4.0
self.BlendPixel(px, py, core_col, intensity * fade * 0.5)
def BlendPixel(self, x: int, y: int, col: uint32, alpha: float):
if alpha <= 0.0: return
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
if x < 0 or x >= w or y < 0 or y >= h: return
idx: int = y * w + x
bg: uint32 = fb[idx]
bg_b: int = bg & 0xFF; bg_g: int = (bg >> 8) & 0xFF; bg_r: int = (bg >> 16) & 0xFF
f_b: int = col & 0xFF; f_g: int = (col >> 8) & 0xFF; f_r: int = (col >> 16) & 0xFF
a: int = int(alpha * 255.0)
inv_a: int = 255 - a
nr: int = (f_r * a + bg_r * inv_a) >> 8
ng: int = (f_g * a + bg_g * inv_a) >> 8
nb: int = (f_b * a + bg_b * inv_a) >> 8
fb[idx] = COLOR_RGB(255 if (nr > 255) else nr,
255 if (ng > 255) else ng,
255 if (nb > 255) else nb)
@t.Object
class Scene3D:
renderer: Renderer
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
self.renderer = Renderer(fb, zb, w, h)
def Render(self, time: float):
rw: int = self.renderer._w
rh: int = self.renderer._h
self.renderer.Clear(COLOR_RGB(15, 15, 25))
yaw: float = float(45.0) * PI / float(180.0); pitch: float = float(45.0) * PI / float(180.0); radius: float = float(10.0)
eye: Vec3 = Vec3(radius*vipermath.cosf(pitch)*vipermath.cosf(yaw), radius*vipermath.sinf(pitch), radius*vipermath.cosf(pitch)*vipermath.sinf(yaw))
target: Vec3 = Vec3(0, 0, 0); up: Vec3 = Vec3(0, 1, 0)
view: Mat4 = Mat4_LookAt(eye, target, up)
proj: Mat4 = Mat4_Perspective(PI / float(3.0), float(rw)/float(rh), float(0.1), float(100.0))
vp: Mat4 = Mat4_Mul(proj, view)
cubeX: float = float(-3.5)
cubeMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(cubeX, 0, 0))
self._DrawCube(cubeMVP, COLOR_RGB(180, 180, 180))
colors: t.CArray[uint32, 4] = [COLOR_RGB(255,50,50), COLOR_RGB(50,50,255), COLOR_RGB(255,255,50), COLOR_RGB(50,255,255)]
for i in range(4):
a: float = time * float(1.5) + i * (PI / float(2.0)); r: float = float(3.0)
pos: Vec3 = Vec3(vipermath.cosf(a) * r + cubeX, 0, vipermath.sinf(a) * r)
sphereMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(pos.x, pos.y, pos.z))
self._DrawSphere(sphereMVP, Vec3(0,0,0), float(0.5), colors[i])
self._Draw3DSinWave(vp, Vec3(float(3.5), 0, 0), time)
self.renderer.DrawLine2D(50, rh - 150, rw - 50, rh - 150, COLOR_RGB(80, 80, 80))
self.renderer.DrawLine2D(50, rh - 50, 50, rh - 250, COLOR_RGB(80, 80, 80))
wave_shift: float = time * float(2.0)
prev_x: int = 50; prev_y: int = rh - 150 - int(vipermath.sinf(0 - wave_shift) * float(100.0))
for i in range(1, rw - 100):
tr: float = float(i) / float(rw-100) * float(4.0) * PI
cx: int = 50 + i; cy: int = rh - 150 - int(vipermath.sinf(tr - wave_shift) * float(100.0))
self.renderer.DrawLine2D(prev_x, prev_y, cx, cy, COLOR_RGB(0, 255, 100))
prev_x = cx; prev_y = cy
def _DrawCube(self, mvp: Mat4, col: uint32):
v: t.CArray[Vec3, 8] = [
Vec3(-1, -1, -1), Vec3(-1, -1, 1), Vec3(-1, 1, -1), Vec3(-1, 1, 1),
Vec3( 1, -1, -1), Vec3( 1, -1, 1), Vec3( 1, 1, -1), Vec3( 1, 1, 1)
]
for i in range(8): v[i] = Mat4_MulVec(mvp, v[i])
faces: t.CArray[t.CArray[int, 3], 12] = [
[0, 2, 1], [1, 2, 3], [4, 1, 5], [4, 0, 1], [6, 3, 2], [6, 7, 3],
[4, 6, 0], [0, 6, 2], [5, 7, 4], [4, 7, 6], [1, 3, 5], [5, 3, 7]
]
for i in range(12): self.renderer.DrawTriangle(v[faces[i][0]], v[faces[i][1]], v[faces[i][2]], col)
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: uint32):
step_pi: float = PI / SPHERE_STACKS; step_2pi: float = float(2.0) * PI / SPHERE_SLICES
for i in range(SPHERE_STACKS):
for j in range(SPHERE_SLICES):
theta1: float = i * step_pi; theta2: float = (i + 1) * step_pi
phi1: float = j * step_2pi; phi2: float = (j + 1) * step_2pi
v: t.CArray[Vec3, 4]
v[0] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi1))
v[1] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi2))
v[2] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi1))
v[3] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi2))
for k in range(4): v[k] = Mat4_MulVec(mvp, v[k])
self.renderer.DrawTriangle(v[0], v[1], v[2], col)
self.renderer.DrawTriangle(v[1], v[3], v[2], col)
def _Draw3DSinWave(self, vp: Mat4, pos: Vec3, time: float):
_range: float = float(2.0) * PI; step: float = _range / SIN_WAVE_GRID; scale: float = float(0.5)
mvp: Mat4 = Mat4_Mul(vp, Mat4_Mul(Mat4_Translate(pos.x, pos.y, pos.z), Mat4_RotateY(time * float(1.0))))
for i in range(SIN_WAVE_GRID):
for j in range(SIN_WAVE_GRID):
x0: float = -PI + i * step; z0 = -PI + j * step; x1: float = x0 + step; z1 = z0 + step
y00: float = vipermath.sinf(x0) * vipermath.cosf(z0) * scale; y10: float = vipermath.sinf(x1) * vipermath.cosf(z0) * scale
y01: float = vipermath.sinf(x0) * vipermath.cosf(z1) * scale; y11: float = vipermath.sinf(x1) * vipermath.cosf(z1) * scale
t1: float = (y00 / scale + float(1.0)) * float(0.5); r1: int = int(50 + 205 * t1); g1: int = int(80 + 120 * vipermath.sinf(t1 * PI)); b1: int = int(255 - 205 * t1)
col1: uint32 = COLOR_RGB(255 if (r1 > 255) else (0 if (r1 < 0) else r1), 255 if (g1 > 255) else (0 if (g1 < 0) else g1), 255 if (b1 > 255) else (0 if (b1 < 0) else b1))
t2: float = (y11 / scale + float(1.0)) * float(0.5); r2: int = int(50 + 205 * t2); g2: int = int(80 + 120 * vipermath.sinf(t2 * PI)); b2: int = int(255 - 205 * t2)
col2: uint32 = COLOR_RGB(255 if (r2 > 255) else (0 if (r2 < 0) else r2), 255 if (g2 > 255) else (0 if (g2 < 0) else g2), 255 if (b2 > 255) else (0 if (b2 < 0) else b2))
v00: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y00, z0)); v10: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y10, z0))
v01: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y01, z1)); v11: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y11, z1))
self.renderer.DrawTriangle(v00, v10, v11, col1); self.renderer.DrawTriangle(v00, v11, v01, col2)
+66 -66
View File
@@ -1,66 +1,66 @@
import vpsdk.window as window
import vpsdk.process as process
import vpsdk.vpui as vpui
import vpsdk.stdlib as stdlib
import vpsdk.stdio as stdio
import viperstring as string
import vipermath
from stdint import *
import gfx
import t, c
SCENE_W: t.CDefine = 640
SCENE_H: t.CDefine = 360
_zbuf_mem: t.CArray[t.CUInt8T, SCENE_W * SCENE_H * 8]
_fb_mem: t.CArray[t.CUInt32T, SCENE_W * SCENE_H]
_root_ptr: vpui.Tk | t.CPtr
_canvas_ptr: vpui.FBCanvas | t.CPtr
_s3d_ptr: gfx.Scene3D | t.CPtr
_time_val: float = float(0.0)
def _render_thread(arg: t.CVoid | t.CPtr) -> t.CVoid:
root: vpui.Tk | t.CPtr = _root_ptr
canvas: vpui.FBCanvas | t.CPtr = _canvas_ptr
s3d: gfx.Scene3D | t.CPtr = _s3d_ptr
while root.winfo_exists():
s3d.Render(_time_val)
_time_val += float(0.02)
root.update()
process.yield_cpu()
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> t.CInt | t.CExport:
root: vpui.Tk = vpui.Tk()
root.title("3D Scene")
root.set_style(window.STYLE_WIN11)
root.bg_color = t.CUInt32T(0x0F0F19)
master: vpui.Tk | t.CPtr = c.Addr(root)
canvas: vpui.FBCanvas = vpui.FBCanvas(master, SCENE_W, SCENE_H)
root.pack(0, vpui.PACK_TOP, vpui.FILL_BOTH, 1, 0, 0)
zbuf: float | t.CPtr = t.CVoid(c.Addr(_zbuf_mem), t.CPtr)
string.memset(zbuf, 0, SCENE_W * SCENE_H * 8)
fb: UINT32PTR = c.Addr(_fb_mem)
string.memset(fb, 0, SCENE_W * SCENE_H * 4)
canvas.set_fb(fb, SCENE_W, SCENE_H)
s3d: gfx.Scene3D = gfx.Scene3D(fb, zbuf, SCENE_W, SCENE_H)
root.geometry(100, 30, SCENE_W, SCENE_H + 32)
global _root_ptr, _canvas_ptr, _s3d_ptr
_root_ptr = c.Addr(root)
_canvas_ptr = c.Addr(canvas)
_s3d_ptr = c.Addr(s3d)
process.thread_create(_render_thread, None)
root.mainloop()
process.exit(0)
return 0
import vpsdk.window as window
import vpsdk.process as process
import vpsdk.vpui as vpui
import vpsdk.stdlib as stdlib
import vpsdk.stdio as stdio
import viperstring as string
import vipermath
from stdint import *
import gfx
import t, c
SCENE_W: t.CDefine = 640
SCENE_H: t.CDefine = 360
_zbuf_mem: t.CArray[uint8, SCENE_W * SCENE_H * 8]
_fb_mem: t.CArray[uint32, SCENE_W * SCENE_H]
_root_ptr: vpui.Tk | t.CPtr
_canvas_ptr: vpui.FBCanvas | t.CPtr
_s3d_ptr: gfx.Scene3D | t.CPtr
_time_val: float = float(0.0)
def _render_thread(arg: t.CPtr) -> t.CVoid:
root: vpui.Tk | t.CPtr = _root_ptr
canvas: vpui.FBCanvas | t.CPtr = _canvas_ptr
s3d: gfx.Scene3D | t.CPtr = _s3d_ptr
while root.winfo_exists():
s3d.Render(_time_val)
_time_val += float(0.02)
root.update()
process.yield_cpu()
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> int | t.CExport:
root: vpui.Tk = vpui.Tk()
root.title("3D Scene")
root.set_style(window.STYLE_WIN11)
root.bg_color = uint32(0x0F0F19)
master: vpui.Tk | t.CPtr = c.Addr(root)
canvas: vpui.FBCanvas = vpui.FBCanvas(master, SCENE_W, SCENE_H)
root.pack(0, vpui.PACK_TOP, vpui.FILL_BOTH, 1, 0, 0)
zbuf: float | t.CPtr = t.CVoid(c.Addr(_zbuf_mem), t.CPtr)
string.memset(zbuf, 0, SCENE_W * SCENE_H * 8)
fb: UINT32PTR = c.Addr(_fb_mem)
string.memset(fb, 0, SCENE_W * SCENE_H * 4)
canvas.set_fb(fb, SCENE_W, SCENE_H)
s3d: gfx.Scene3D = gfx.Scene3D(fb, zbuf, SCENE_W, SCENE_H)
root.geometry(100, 30, SCENE_W, SCENE_H + 32)
global _root_ptr, _canvas_ptr, _s3d_ptr
_root_ptr = c.Addr(root)
_canvas_ptr = c.Addr(canvas)
_s3d_ptr = c.Addr(s3d)
process.thread_create(_render_thread, None)
root.mainloop()
process.exit(0)
return 0
+327 -327
View File
@@ -1,327 +1,327 @@
import vpsdk.vpui as vpui
import vpsdk.window as window
import vpsdk.process as process
import vpsdk.fs as fs
import vpsdk.syscall as _syscall
import vpsdk.stdlib as stdlib
import vpsdk.stdio as stdio
import string
import viperlib
from stdint import *
import t, c
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> t.CInt | t.CExport:
root: vpui.Tk = vpui.Tk()
root.title("Terminal")
root.set_style(window.STYLE_WIN7)
root.geometry(80, 30, 640, 480)
root.bg_color = t.CUInt32T(0x0C0C0C)
master: vpui.Tk | t.CPtr = c.Addr(root)
def _sdbg(msg: str):
_syscall._syscall1(t.CUInt64T(18), t.CUInt64T(msg))
_sdbg("[term] start\n")
_cwd: t.CArray[t.CChar, 64]
_cwd[0] = 47
for i in range(1, 64):
_cwd[i] = 0
sbar: vpui.Scrollbar = vpui.Scrollbar(master, 16, 446, vpui.VERTICAL)
root.pack(0, vpui.PACK_RIGHT, vpui.FILL_Y, 0, 0, 0)
term: vpui.Text = vpui.Text(master, 624, 446)
root.pack(1, vpui.PACK_LEFT, vpui.FILL_BOTH, 1, 0, 0)
term.insert("ViperOS Terminal v1.1")
term.insert("Type 'help' for commands.")
term.insert("")
term.yscrollbar = t.CType(sbar, vpui.Widget, t.CPtr)
def _on_scroll():
act: t.CInt = sbar.action
if act == 1:
term.scroll_offset -= 1
elif act == 2:
term.scroll_offset += 1
elif act == 3:
vis: t.CInt = term._visible_lines()
term.scroll_offset -= vis
elif act == 4:
vis2: t.CInt = term._visible_lines()
term.scroll_offset += vis2
elif act == 5:
aval: t.CInt = sbar.action_value
if term.line_count > 0:
term.scroll_offset = aval * term.line_count / 1000
vis3: t.CInt = term._visible_lines()
max_off: t.CInt = term.line_count - vis3
if max_off < 0: max_off = 0
if term.scroll_offset < 0: term.scroll_offset = 0
if term.scroll_offset > max_off: term.scroll_offset = max_off
term._update_scrollbar()
sbar.command = c.Addr(_on_scroll)
def _startswith(s: str, prefix: str) -> t.CInt:
plen: t.CSizeT = string.strlen(prefix)
if string.strncmp(s, prefix, plen) == 0:
return 1
return 0
def _build_path(out: str, out_size: t.CInt, rel: str):
if c.Deref(rel) == 47:
string.strncpy(out, rel, out_size - 1)
else:
i: t.CInt = 0
for i in range(63):
ch: t.CChar = _cwd[i]
c.DerefAs(out + i, ch)
if ch == 0: break
cwd_len: t.CInt = i
if cwd_len > 0 and _cwd[cwd_len - 1] != 47:
c.DerefAs(out + cwd_len, t.CChar(47))
cwd_len += 1
j: t.CInt = 0
for j in range(out_size - 1 - cwd_len):
ch2: t.CChar = c.Deref(rel + j)
c.DerefAs(out + cwd_len + j, ch2)
if ch2 == 0: break
c.DerefAs(out + out_size - 1, t.CChar(0))
def _print_dir_entry(name: str, is_dir: t.CInt):
buf: t.CArray[t.CChar, 80]
j: t.CInt = 0
for j in range(78):
ch: t.CChar = c.Deref(name + j)
buf[j] = ch
if ch == 0: break
if is_dir and j < 78:
buf[j] = 47
j += 1
buf[j] = 0
term.insert_ptr(c.Addr(buf[0]))
def _cmd_cd(path: str):
if path is None or c.Deref(path) == 0:
_cwd[0] = 47
for i in range(1, 64):
_cwd[i] = 0
return
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
dd: t.CInt = fs.opendir(c.Addr(full[0]))
if dd < 0:
term.insert("Error: dir not found")
return
fs.closedir(dd)
string.strncpy(c.Addr(_cwd[0]), c.Addr(full[0]), 63)
_cwd[63] = 0
def _cmd_ls():
dd: t.CInt = fs.opendir(c.Addr(_cwd[0]))
if dd < 0:
term.insert("Error: cannot open dir")
return
info: t.CArray[t.CChar, 320]
string.memset(c.Addr(info[0]), 0, 320)
while True:
result: t.CInt = fs.readdir(dd, c.Addr(info[0]))
if result != 0: break
attr_val: t.CUInt8T = t.CUInt8T(c.Deref(c.Addr(info[4])))
name_off: t.CInt = 16
name_ptr: str = c.Addr(info[name_off])
if c.Deref(name_ptr) == 0: break
if c.Deref(name_ptr) == 46:
if c.Deref(name_ptr + 1) == 0:
string.memset(c.Addr(info[0]), 0, 320)
continue
if c.Deref(name_ptr + 1) == 46 and c.Deref(name_ptr + 2) == 0:
string.memset(c.Addr(info[0]), 0, 320)
continue
if (attr_val & 0x10) != 0:
_print_dir_entry(name_ptr, 1)
else:
_print_dir_entry(name_ptr, 0)
string.memset(c.Addr(info[0]), 0, 320)
fs.closedir(dd)
def _cmd_cat(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
fd: t.CInt = fs.open(c.Addr(full[0]), fs.O_RDONLY)
if fd < 0:
term.insert("Error: file not found")
return
buf: t.CArray[t.CChar, 80]
while True:
string.memset(c.Addr(buf[0]), 0, 80)
n: t.CInt = fs.read(fd, c.Addr(buf[0]), 78)
if n <= 0: break
if n > 78: n = 78
buf[n] = 0
term.insert_ptr(c.Addr(buf[0]))
fs.close(fd)
def _cmd_mkdir(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
result: t.CInt = fs.mkdir(c.Addr(full[0]))
if result < 0:
term.insert("Error: mkdir failed")
else:
term.insert("Directory created")
def _cmd_rm(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
result: t.CInt = fs.remove(c.Addr(full[0]))
if result < 0:
term.insert("Error: remove failed")
else:
term.insert("Removed")
def _cmd_touch(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
fd: t.CInt = fs.open(c.Addr(full[0]), fs.O_WRONLY | fs.O_CREAT)
if fd < 0:
term.insert("Error: touch failed")
return
fs.close(fd)
term.insert("File created")
def _cmd_sysinfo():
term.insert("ViperOS v1.0 (x86_64)")
term.insert("Framebuffer: 32bpp")
term.insert("Compiler: TransPyC")
def _cmd_hexdump(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
fd: t.CInt = fs.open(c.Addr(full[0]), fs.O_RDONLY)
if fd < 0:
term.insert("Error: file not found")
return
offset: t.CInt = 0
buf: t.CArray[t.CChar, 16]
while True:
string.memset(c.Addr(buf[0]), 0, 16)
n: t.CInt = fs.read(fd, c.Addr(buf[0]), 16)
if n <= 0: break
if n > 16: n = 16
line: t.CArray[t.CChar, 80]
string.memset(c.Addr(line[0]), 0, 80)
viperlib.snprintf(c.Addr(line[0]), 80, "%08x: ", offset)
pos: t.CInt = 10
j: t.CInt = 0
for j in range(16):
if j < n:
ub: t.CUInt32T = t.CUInt32T(buf[j]) & 0xFF
hi: t.CInt = t.CInt(ub >> 4)
lo: t.CInt = t.CInt(ub & 0xF)
if hi < 10:
line[pos] = t.CChar(48 + hi)
else:
line[pos] = t.CChar(65 + hi - 10)
pos += 1
if lo < 10:
line[pos] = t.CChar(48 + lo)
else:
line[pos] = t.CChar(65 + lo - 10)
pos += 1
else:
line[pos] = 32
pos += 1
line[pos] = 32
pos += 1
line[pos] = 32
pos += 1
if j == 7:
line[pos] = 32
pos += 1
line[pos] = 124
pos += 1
for j in range(n):
b2: t.CUInt32T = t.CUInt32T(buf[j]) & 0xFF
if b2 >= 32 and b2 < 127:
line[pos] = t.CChar(b2)
else:
line[pos] = 46
pos += 1
line[pos] = 0
term.insert_ptr(c.Addr(line[0]))
offset += n
fs.close(fd)
def _cmd_run(path: str, blocking: t.CInt):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
pid: t.CInt = process.spawn(c.Addr(full[0]), blocking)
if pid < 0:
term.insert("Error: cannot spawn")
elif blocking:
term.insert("Process exited")
else:
msg: t.CArray[t.CChar, 32]
viperlib.snprintf(c.Addr(msg[0]), 32, "Spawned pid=%d", pid)
term.insert_ptr(c.Addr(msg[0]))
def _on_command() -> t.CInt:
_sdbg("[cmd] enter\n")
text: str = term.get()
_sdbg("[cmd] text=")
_sdbg(text)
_sdbg("\n")
if _startswith(text, "echo "):
term.insert_ptr(text + 5)
elif string.samestr(text, "echo"):
pass
elif string.samestr(text, "clear"):
term.delete(0, -1)
elif string.samestr(text, "help"):
term.insert("File: ls cd cat pwd mkdir rm touch")
term.insert("Sys: ver about sysinfo reboot")
term.insert("Util: echo clear help hexdump run runb")
elif string.samestr(text, "ver"):
term.insert("ViperOS Terminal v1.1")
elif string.samestr(text, "about"):
term.insert("ViperOS - A tiny OS in Viper lang")
elif string.samestr(text, "pwd"):
term.insert_ptr(c.Addr(_cwd[0]))
elif string.samestr(text, "ls"):
_cmd_ls()
elif string.samestr(text, "cd"):
_cmd_cd("")
elif _startswith(text, "cd "):
_cmd_cd(text + 3)
elif _startswith(text, "cat "):
_cmd_cat(text + 4)
elif _startswith(text, "mkdir "):
_cmd_mkdir(text + 6)
elif _startswith(text, "rm "):
_cmd_rm(text + 3)
elif _startswith(text, "touch "):
_cmd_touch(text + 6)
elif string.samestr(text, "sysinfo"):
_cmd_sysinfo()
elif string.samestr(text, "reboot"):
process.exit(0)
elif _startswith(text, "hexdump "):
_cmd_hexdump(text + 8)
elif _startswith(text, "run "):
_cmd_run(text + 4, 0)
elif _startswith(text, "runb "):
_cmd_run(text + 5, 1)
else:
if text is not None and c.Deref(text) != 0:
term.insert("Unknown command. Type 'help'.")
return 0
term.on_command = c.Addr(_on_command)
root.mainloop()
process.exit(0)
return 0
import vpsdk.vpui as vpui
import vpsdk.window as window
import vpsdk.process as process
import vpsdk.fs as fs
import vpsdk.syscall as _syscall
import vpsdk.stdlib as stdlib
import vpsdk.stdio as stdio
import string
import viperlib
from stdint import *
import t, c
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> int | t.CExport:
root: vpui.Tk = vpui.Tk()
root.title("Terminal")
root.set_style(window.STYLE_WIN7)
root.geometry(80, 30, 640, 480)
root.bg_color = uint32(0x0C0C0C)
master: vpui.Tk | t.CPtr = c.Addr(root)
def _sdbg(msg: str):
_syscall._syscall1(uint64(18), uint64(msg))
_sdbg("[term] start\n")
_cwd: t.CArray[t.CChar, 64]
_cwd[0] = 47
for i in range(1, 64):
_cwd[i] = 0
sbar: vpui.Scrollbar = vpui.Scrollbar(master, 16, 446, vpui.VERTICAL)
root.pack(0, vpui.PACK_RIGHT, vpui.FILL_Y, 0, 0, 0)
term: vpui.Text = vpui.Text(master, 624, 446)
root.pack(1, vpui.PACK_LEFT, vpui.FILL_BOTH, 1, 0, 0)
term.insert("ViperOS Terminal v1.1")
term.insert("Type 'help' for commands.")
term.insert("")
term.yscrollbar = t.CType(sbar, vpui.Widget, t.CPtr)
def _on_scroll():
act: int = sbar.action
if act == 1:
term.scroll_offset -= 1
elif act == 2:
term.scroll_offset += 1
elif act == 3:
vis: int = term._visible_lines()
term.scroll_offset -= vis
elif act == 4:
vis2: int = term._visible_lines()
term.scroll_offset += vis2
elif act == 5:
aval: int = sbar.action_value
if term.line_count > 0:
term.scroll_offset = aval * term.line_count / 1000
vis3: int = term._visible_lines()
max_off: int = term.line_count - vis3
if max_off < 0: max_off = 0
if term.scroll_offset < 0: term.scroll_offset = 0
if term.scroll_offset > max_off: term.scroll_offset = max_off
term._update_scrollbar()
sbar.command = c.Addr(_on_scroll)
def _startswith(s: str, prefix: str) -> int:
plen: t.CSizeT = string.strlen(prefix)
if string.strncmp(s, prefix, plen) == 0:
return 1
return 0
def _build_path(out: str, out_size: int, rel: str):
if c.Deref(rel) == 47:
string.strncpy(out, rel, out_size - 1)
else:
i: int = 0
for i in range(63):
ch: t.CChar = _cwd[i]
c.DerefAs(out + i, ch)
if ch == 0: break
cwd_len: int = i
if cwd_len > 0 and _cwd[cwd_len - 1] != 47:
c.DerefAs(out + cwd_len, t.CChar(47))
cwd_len += 1
j: int = 0
for j in range(out_size - 1 - cwd_len):
ch2: t.CChar = c.Deref(rel + j)
c.DerefAs(out + cwd_len + j, ch2)
if ch2 == 0: break
c.DerefAs(out + out_size - 1, t.CChar(0))
def _print_dir_entry(name: str, is_dir: int):
buf: t.CArray[t.CChar, 80]
j: int = 0
for j in range(78):
ch: t.CChar = c.Deref(name + j)
buf[j] = ch
if ch == 0: break
if is_dir and j < 78:
buf[j] = 47
j += 1
buf[j] = 0
term.insert_ptr(c.Addr(buf[0]))
def _cmd_cd(path: str):
if path is None or c.Deref(path) == 0:
_cwd[0] = 47
for i in range(1, 64):
_cwd[i] = 0
return
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
dd: int = fs.opendir(c.Addr(full[0]))
if dd < 0:
term.insert("Error: dir not found")
return
fs.closedir(dd)
string.strncpy(c.Addr(_cwd[0]), c.Addr(full[0]), 63)
_cwd[63] = 0
def _cmd_ls():
dd: int = fs.opendir(c.Addr(_cwd[0]))
if dd < 0:
term.insert("Error: cannot open dir")
return
info: t.CArray[t.CChar, 320]
string.memset(c.Addr(info[0]), 0, 320)
while True:
result: int = fs.readdir(dd, c.Addr(info[0]))
if result != 0: break
attr_val: uint8 = uint8(c.Deref(c.Addr(info[4])))
name_off: int = 16
name_ptr: str = c.Addr(info[name_off])
if c.Deref(name_ptr) == 0: break
if c.Deref(name_ptr) == 46:
if c.Deref(name_ptr + 1) == 0:
string.memset(c.Addr(info[0]), 0, 320)
continue
if c.Deref(name_ptr + 1) == 46 and c.Deref(name_ptr + 2) == 0:
string.memset(c.Addr(info[0]), 0, 320)
continue
if (attr_val & 0x10) != 0:
_print_dir_entry(name_ptr, 1)
else:
_print_dir_entry(name_ptr, 0)
string.memset(c.Addr(info[0]), 0, 320)
fs.closedir(dd)
def _cmd_cat(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
fd: int = fs.open(c.Addr(full[0]), fs.O_RDONLY)
if fd < 0:
term.insert("Error: file not found")
return
buf: t.CArray[t.CChar, 80]
while True:
string.memset(c.Addr(buf[0]), 0, 80)
n: int = fs.read(fd, c.Addr(buf[0]), 78)
if n <= 0: break
if n > 78: n = 78
buf[n] = 0
term.insert_ptr(c.Addr(buf[0]))
fs.close(fd)
def _cmd_mkdir(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
result: int = fs.mkdir(c.Addr(full[0]))
if result < 0:
term.insert("Error: mkdir failed")
else:
term.insert("Directory created")
def _cmd_rm(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
result: int = fs.remove(c.Addr(full[0]))
if result < 0:
term.insert("Error: remove failed")
else:
term.insert("Removed")
def _cmd_touch(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
fd: int = fs.open(c.Addr(full[0]), fs.O_WRONLY | fs.O_CREAT)
if fd < 0:
term.insert("Error: touch failed")
return
fs.close(fd)
term.insert("File created")
def _cmd_sysinfo():
term.insert("ViperOS v1.0 (x86_64)")
term.insert("Framebuffer: 32bpp")
term.insert("Compiler: TransPyC")
def _cmd_hexdump(path: str):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
fd: int = fs.open(c.Addr(full[0]), fs.O_RDONLY)
if fd < 0:
term.insert("Error: file not found")
return
offset: int = 0
buf: t.CArray[t.CChar, 16]
while True:
string.memset(c.Addr(buf[0]), 0, 16)
n: int = fs.read(fd, c.Addr(buf[0]), 16)
if n <= 0: break
if n > 16: n = 16
line: t.CArray[t.CChar, 80]
string.memset(c.Addr(line[0]), 0, 80)
viperlib.snprintf(c.Addr(line[0]), 80, "%08x: ", offset)
pos: int = 10
j: int = 0
for j in range(16):
if j < n:
ub: uint32 = uint32(buf[j]) & 0xFF
hi: int = int(ub >> 4)
lo: int = int(ub & 0xF)
if hi < 10:
line[pos] = t.CChar(48 + hi)
else:
line[pos] = t.CChar(65 + hi - 10)
pos += 1
if lo < 10:
line[pos] = t.CChar(48 + lo)
else:
line[pos] = t.CChar(65 + lo - 10)
pos += 1
else:
line[pos] = 32
pos += 1
line[pos] = 32
pos += 1
line[pos] = 32
pos += 1
if j == 7:
line[pos] = 32
pos += 1
line[pos] = 124
pos += 1
for j in range(n):
b2: uint32 = uint32(buf[j]) & 0xFF
if b2 >= 32 and b2 < 127:
line[pos] = t.CChar(b2)
else:
line[pos] = 46
pos += 1
line[pos] = 0
term.insert_ptr(c.Addr(line[0]))
offset += n
fs.close(fd)
def _cmd_run(path: str, blocking: int):
full: t.CArray[t.CChar, 256]
_build_path(c.Addr(full[0]), 256, path)
pid: int = process.spawn(c.Addr(full[0]), blocking)
if pid < 0:
term.insert("Error: cannot spawn")
elif blocking:
term.insert("Process exited")
else:
msg: t.CArray[t.CChar, 32]
viperlib.snprintf(c.Addr(msg[0]), 32, "Spawned pid=%d", pid)
term.insert_ptr(c.Addr(msg[0]))
def _on_command() -> int:
_sdbg("[cmd] enter\n")
text: str = term.get()
_sdbg("[cmd] text=")
_sdbg(text)
_sdbg("\n")
if _startswith(text, "echo "):
term.insert_ptr(text + 5)
elif string.samestr(text, "echo"):
pass
elif string.samestr(text, "clear"):
term.delete(0, -1)
elif string.samestr(text, "help"):
term.insert("File: ls cd cat pwd mkdir rm touch")
term.insert("Sys: ver about sysinfo reboot")
term.insert("Util: echo clear help hexdump run runb")
elif string.samestr(text, "ver"):
term.insert("ViperOS Terminal v1.1")
elif string.samestr(text, "about"):
term.insert("ViperOS - A tiny OS in Viper lang")
elif string.samestr(text, "pwd"):
term.insert_ptr(c.Addr(_cwd[0]))
elif string.samestr(text, "ls"):
_cmd_ls()
elif string.samestr(text, "cd"):
_cmd_cd("")
elif _startswith(text, "cd "):
_cmd_cd(text + 3)
elif _startswith(text, "cat "):
_cmd_cat(text + 4)
elif _startswith(text, "mkdir "):
_cmd_mkdir(text + 6)
elif _startswith(text, "rm "):
_cmd_rm(text + 3)
elif _startswith(text, "touch "):
_cmd_touch(text + 6)
elif string.samestr(text, "sysinfo"):
_cmd_sysinfo()
elif string.samestr(text, "reboot"):
process.exit(0)
elif _startswith(text, "hexdump "):
_cmd_hexdump(text + 8)
elif _startswith(text, "run "):
_cmd_run(text + 4, 0)
elif _startswith(text, "runb "):
_cmd_run(text + 5, 1)
else:
if text is not None and c.Deref(text) != 0:
term.insert("Unknown command. Type 'help'.")
return 0
term.on_command = c.Addr(_on_command)
root.mainloop()
process.exit(0)
return 0
+12 -12
View File
@@ -1,12 +1,12 @@
import vpsdk.syscall as syscall
import t, c
def log_info(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CExport:
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T("[SerialLogger] "))
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T(msg))
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T("\n"))
def log_warn(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CExport:
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T("[SerialLogger:WARN] "))
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T(msg))
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T("\n"))
import vpsdk.syscall as syscall
import t, c
def log_info(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CExport:
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("[SerialLogger] "))
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64(msg))
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("\n"))
def log_warn(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CExport:
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("[SerialLogger:WARN] "))
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64(msg))
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("\n"))
+80 -80
View File
@@ -1,80 +1,80 @@
import t
import vpsdk.syscall as syscall
UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr
def color_rgb(r: t.CUInt8T, g: t.CUInt8T, b: t.CUInt8T) -> t.CUInt32T:
return t.CUInt32T(r) | (t.CUInt32T(g) << 8) | (t.CUInt32T(b) << 16)
def get_winbuf(win_id: t.CInt) -> UINT32PTR:
return t.CVoid(syscall._syscall2(t.CUInt64T(syscall.GET_WINBUF), t.CUInt64T(win_id), 0), t.CPtr)
def win_flush(win_id: t.CInt) -> t.CVoid:
syscall._syscall2(t.CUInt64T(syscall.WIN_FLUSH), t.CUInt64T(win_id), 0)
def draw_pixel(buf: UINT32PTR, bw: t.CInt, x: t.CInt, y: t.CInt, color: t.CUInt32T) -> t.CVoid | t.CExport:
if x < 0 or y < 0: return
buf[y * bw + x] = color
def draw_line(buf: UINT32PTR, bw: t.CInt, x0: t.CInt, y0: t.CInt, x1: t.CInt, y1: t.CInt, color: t.CUInt32T) -> t.CVoid | t.CExport:
dx: t.CInt = x1 - x0
dy: t.CInt = y1 - y0
sx: t.CInt = 1
sy: t.CInt = 1
if dx < 0:
dx = -dx
sx = -1
if dy < 0:
dy = -dy
sy = -1
err: t.CInt = dx - dy
while True:
if x0 >= 0 and y0 >= 0:
buf[y0 * bw + x0] = color
if x0 == x1 and y0 == y1:
break
e2: t.CInt = 2 * err
if e2 > -dy:
err -= dy
x0 += sx
if e2 < dx:
err += dx
y0 += sy
def draw_rect(buf: UINT32PTR, bw: t.CInt, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T) -> t.CVoid | t.CExport:
draw_line(buf, bw, rx, ry, rx + rw - 1, ry, color)
draw_line(buf, bw, rx + rw - 1, ry, rx + rw - 1, ry + rh - 1, color)
draw_line(buf, bw, rx + rw - 1, ry + rh - 1, rx, ry + rh - 1, color)
draw_line(buf, bw, rx, ry + rh - 1, rx, ry, color)
def fill_rect(buf: UINT32PTR, bw: t.CInt, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T) -> t.CVoid | t.CExport:
if rx < 0: rw += rx; rx = 0
if ry < 0: rh += ry; ry = 0
if rw <= 0 or rh <= 0: return
py: t.CInt = ry
while py < ry + rh:
px: t.CInt = rx
while px < rx + rw:
buf[py * bw + px] = color
px += 1
py += 1
def draw_circle(buf: UINT32PTR, bw: t.CInt, cx: t.CInt, cy: t.CInt, r: t.CInt, color: t.CUInt32T) -> t.CVoid | t.CExport:
x: t.CInt = r
y: t.CInt = 0
d: t.CInt = 1 - r
while x >= y:
if cx + x >= 0: buf[(cy + y) * bw + cx + x] = color
if cx + y >= 0: buf[(cy + x) * bw + cx + y] = color
if cx - y >= 0: buf[(cy + x) * bw + cx - y] = color
if cx - x >= 0: buf[(cy + y) * bw + cx - x] = color
if cx - x >= 0: buf[(cy - y) * bw + cx - x] = color
if cx - y >= 0: buf[(cy - x) * bw + cx - y] = color
if cx + y >= 0: buf[(cy - x) * bw + cx + y] = color
if cx + x >= 0: buf[(cy - y) * bw + cx + x] = color
y += 1
if d <= 0:
d += 2 * y + 1
else:
x -= 1
d += 2 * (y - x) + 1
import t
import vpsdk.syscall as syscall
UINT32PTR: t.CTypedef = uint32 | t.CPtr
def color_rgb(r: uint8, g: uint8, b: uint8) -> uint32:
return uint32(r) | (uint32(g) << 8) | (uint32(b) << 16)
def get_winbuf(win_id: int) -> UINT32PTR:
return t.CVoid(syscall._syscall2(uint64(syscall.GET_WINBUF), uint64(win_id), 0), t.CPtr)
def win_flush(win_id: int) -> t.CVoid:
syscall._syscall2(uint64(syscall.WIN_FLUSH), uint64(win_id), 0)
def draw_pixel(buf: UINT32PTR, bw: int, x: int, y: int, color: uint32) -> t.CVoid | t.CExport:
if x < 0 or y < 0: return
buf[y * bw + x] = color
def draw_line(buf: UINT32PTR, bw: int, x0: int, y0: int, x1: int, y1: int, color: uint32) -> t.CVoid | t.CExport:
dx: int = x1 - x0
dy: int = y1 - y0
sx: int = 1
sy: int = 1
if dx < 0:
dx = -dx
sx = -1
if dy < 0:
dy = -dy
sy = -1
err: int = dx - dy
while True:
if x0 >= 0 and y0 >= 0:
buf[y0 * bw + x0] = color
if x0 == x1 and y0 == y1:
break
e2: int = 2 * err
if e2 > -dy:
err -= dy
x0 += sx
if e2 < dx:
err += dx
y0 += sy
def draw_rect(buf: UINT32PTR, bw: int, rx: int, ry: int, rw: int, rh: int, color: uint32) -> t.CVoid | t.CExport:
draw_line(buf, bw, rx, ry, rx + rw - 1, ry, color)
draw_line(buf, bw, rx + rw - 1, ry, rx + rw - 1, ry + rh - 1, color)
draw_line(buf, bw, rx + rw - 1, ry + rh - 1, rx, ry + rh - 1, color)
draw_line(buf, bw, rx, ry + rh - 1, rx, ry, color)
def fill_rect(buf: UINT32PTR, bw: int, rx: int, ry: int, rw: int, rh: int, color: uint32) -> t.CVoid | t.CExport:
if rx < 0: rw += rx; rx = 0
if ry < 0: rh += ry; ry = 0
if rw <= 0 or rh <= 0: return
py: int = ry
while py < ry + rh:
px: int = rx
while px < rx + rw:
buf[py * bw + px] = color
px += 1
py += 1
def draw_circle(buf: UINT32PTR, bw: int, cx: int, cy: int, r: int, color: uint32) -> t.CVoid | t.CExport:
x: int = r
y: int = 0
d: int = 1 - r
while x >= y:
if cx + x >= 0: buf[(cy + y) * bw + cx + x] = color
if cx + y >= 0: buf[(cy + x) * bw + cx + y] = color
if cx - y >= 0: buf[(cy + x) * bw + cx - y] = color
if cx - x >= 0: buf[(cy + y) * bw + cx - x] = color
if cx - x >= 0: buf[(cy - y) * bw + cx - x] = color
if cx - y >= 0: buf[(cy - x) * bw + cx - y] = color
if cx + y >= 0: buf[(cy - x) * bw + cx + y] = color
if cx + x >= 0: buf[(cy - y) * bw + cx + x] = color
y += 1
if d <= 0:
d += 2 * y + 1
else:
x -= 1
d += 2 * (y - x) + 1
+11 -11
View File
@@ -1,17 +1,17 @@
import t, c
MEMORY_TYPE_AVAILABLE: t.CUInt64T = 7
MEMORY_TYPE_RESERVED: t.CUInt64T = 0
MEMORY_TYPE_LOADER_CODE: t.CUInt64T = 1
MEMORY_TYPE_LOADER_DATA: t.CUInt64T = 2
MEMORY_TYPE_BOOT_SERVICES_CODE: t.CUInt64T = 3
MEMORY_TYPE_BOOT_SERVICES_DATA: t.CUInt64T = 4
MEMORY_TYPE_RUNTIME_SERVICES_CODE: t.CUInt64T = 5
MEMORY_TYPE_RUNTIME_SERVICES_DATA: t.CUInt64T = 6
MEMORY_TYPE_ACPI_RECLAIMABLE: t.CUInt64T = 9
MEMORY_TYPE_ACPI_NVS: t.CUInt64T = 10
MEMORY_TYPE_BAD_MEMORY: t.CUInt64T = 8
MEMORY_TYPE_AVAILABLE: uint64 = 7
MEMORY_TYPE_RESERVED: uint64 = 0
MEMORY_TYPE_LOADER_CODE: uint64 = 1
MEMORY_TYPE_LOADER_DATA: uint64 = 2
MEMORY_TYPE_BOOT_SERVICES_CODE: uint64 = 3
MEMORY_TYPE_BOOT_SERVICES_DATA: uint64 = 4
MEMORY_TYPE_RUNTIME_SERVICES_CODE: uint64 = 5
MEMORY_TYPE_RUNTIME_SERVICES_DATA: uint64 = 6
MEMORY_TYPE_ACPI_RECLAIMABLE: uint64 = 9
MEMORY_TYPE_ACPI_NVS: uint64 = 10
MEMORY_TYPE_BAD_MEMORY: uint64 = 8
@c.Attribute(t.attr.packed)
class memory_map_entry:
+260 -256
View File
@@ -1,257 +1,261 @@
import asm
import intr.gdt as gdt
import intr.idt as idt
import drivers.serial.uart.serial as serial
import drivers.core.cpu.cpu as cpu
import mm.mm as mm
import platform.pch.timer as timer
import viperlib
import t, c
IA32_APIC_BASE: t.CDefine = 0x1B
APIC_BASE_MSR_ENABLE: t.CDefine = 0x800
APIC_BASE_ADDR_MASK: t.CDefine = 0xFFFFF000
LAPIC_ID: t.CDefine = 0x020
LAPIC_VERSION: t.CDefine = 0x030
LAPIC_TPR: t.CDefine = 0x080
LAPIC_EOI: t.CDefine = 0x0B0
LAPIC_LDR: t.CDefine = 0x0D0
LAPIC_SVR: t.CDefine = 0x0F0
LAPIC_ISR0: t.CDefine = 0x100
LAPIC_ICR_LOW: t.CDefine = 0x300
LAPIC_ICR_HIGH: t.CDefine = 0x310
LAPIC_LVT_TIMER: t.CDefine = 0x320
LAPIC_LVT_LINT0: t.CDefine = 0x350
LAPIC_LVT_LINT1: t.CDefine = 0x360
LAPIC_LVT_ERROR: t.CDefine = 0x370
LAPIC_TIMER_INIT: t.CDefine = 0x380
LAPIC_TIMER_CURRENT: t.CDefine = 0x390
LAPIC_TIMER_DIVIDE: t.CDefine = 0x3E0
LAPIC_SVR_ENABLE: t.CDefine = 0x100
LAPIC_LVT_MASKED: t.CDefine = 0x10000
LAPIC_LVT_DELIVERY_EXTINT: t.CDefine = 0x700
LAPIC_LVT_DELIVERY_NMI: t.CDefine = 0x400
LAPIC_LVT_TIMER_PERIODIC: t.CDefine = 0x20000
LAPIC_ICR_INIT: t.CDefine = 0x500
LAPIC_ICR_STARTUP: t.CDefine = 0x600
LAPIC_ICR_ASSERT: t.CDefine = 0x4000
LAPIC_ICR_DEASSERT: t.CDefine = 0x8000
LAPIC_ICR_LEVEL: t.CDefine = 0x8000
MAX_CPUS: t.CDefine = 8
import asm
import intr.gdt as gdt
import intr.idt as idt
import drivers.serial.uart.serial as serial
import drivers.core.cpu.cpu as cpu
import mm.mm as mm
import platform.pch.timer as timer
import viperlib
import t, c
IA32_APIC_BASE: t.CDefine = 0x1B
APIC_BASE_MSR_ENABLE: t.CDefine = 0x800
APIC_BASE_ADDR_MASK: t.CDefine = 0xFFFFF000
LAPIC_ID: t.CDefine = 0x020
LAPIC_VERSION: t.CDefine = 0x030
LAPIC_TPR: t.CDefine = 0x080
LAPIC_EOI: t.CDefine = 0x0B0
LAPIC_LDR: t.CDefine = 0x0D0
LAPIC_SVR: t.CDefine = 0x0F0
LAPIC_ISR0: t.CDefine = 0x100
LAPIC_ICR_LOW: t.CDefine = 0x300
LAPIC_ICR_HIGH: t.CDefine = 0x310
LAPIC_LVT_TIMER: t.CDefine = 0x320
LAPIC_LVT_LINT0: t.CDefine = 0x350
LAPIC_LVT_LINT1: t.CDefine = 0x360
LAPIC_LVT_ERROR: t.CDefine = 0x370
LAPIC_TIMER_INIT: t.CDefine = 0x380
LAPIC_TIMER_CURRENT: t.CDefine = 0x390
LAPIC_TIMER_DIVIDE: t.CDefine = 0x3E0
LAPIC_SVR_ENABLE: t.CDefine = 0x100
LAPIC_LVT_MASKED: t.CDefine = 0x10000
LAPIC_LVT_DELIVERY_EXTINT: t.CDefine = 0x700
LAPIC_LVT_DELIVERY_NMI: t.CDefine = 0x400
LAPIC_LVT_TIMER_PERIODIC: t.CDefine = 0x20000
LAPIC_ICR_INIT: t.CDefine = 0x500
LAPIC_ICR_STARTUP: t.CDefine = 0x600
LAPIC_ICR_ASSERT: t.CDefine = 0x4000
LAPIC_ICR_DEASSERT: t.CDefine = 0x8000
LAPIC_ICR_LEVEL: t.CDefine = 0x8000
MAX_CPUS: t.CDefine = 8
AP_TRAMPOLINE_ADDR: t.CDefine = 0x7000
_lapic_base: t.CUInt64T = 0
_cpu_count: t.CUInt32T = 1
_bsp_lapic_id: t.CUInt32T = 0
_ap_ready: t.CUInt32T = 0
def read(offset: t.CUInt32T) -> t.CUInt32T:
addr: t.CUInt64T = _lapic_base + t.CUInt64T(offset)
return c.Deref(t.CUInt32T(addr, t.CPtr))
def write(offset: t.CUInt32T, value: t.CUInt32T):
addr: t.CUInt64T = _lapic_base + t.CUInt64T(offset)
c.Set(c.Deref(t.CUInt32T(addr, t.CPtr)), value)
def eoi():
write(LAPIC_EOI, 0)
def get_id() -> t.CUInt32T:
return read(LAPIC_ID) >> 24
@c.Attribute(t.attr.noinline)
def init():
global _lapic_base, _bsp_lapic_id
msr_val: t.CUInt64T = cpu.msr_read(IA32_APIC_BASE)
_lapic_base = msr_val & APIC_BASE_ADDR_MASK
cpu.msr_write(IA32_APIC_BASE, msr_val | APIC_BASE_MSR_ENABLE)
_bsp_lapic_id = read(LAPIC_ID) >> 24
write(LAPIC_SVR, LAPIC_SVR_ENABLE | 0xFF)
write(LAPIC_TPR, 0)
write(LAPIC_LVT_TIMER, LAPIC_LVT_MASKED)
write(LAPIC_LVT_LINT0, LAPIC_LVT_DELIVERY_EXTINT)
write(LAPIC_LVT_LINT1, LAPIC_LVT_DELIVERY_NMI)
write(LAPIC_LVT_ERROR, LAPIC_LVT_MASKED)
write(LAPIC_TIMER_DIVIDE, 0x0B)
write(LAPIC_LDR, 0x01000000)
eoi()
@c.Attribute(t.attr.noinline)
def detect_cpu_count() -> t.CUInt32T:
res: cpu.cpuid_result
cpu.cpuid(0, c.Addr(res))
max_leaf: t.CUInt32T = res.eax
if max_leaf >= 0x0B:
cpu.cpuid_sub(0x0B, 0, c.Addr(res))
num_threads: t.CUInt32T = res.ebx & 0xFFFF
if num_threads > 0 and num_threads <= MAX_CPUS:
return num_threads
cpu.cpuid(1, c.Addr(res))
if res.edx & cpu.CPU_FEATURE_HTT:
count: t.CUInt32T = (res.ebx >> 16) & 0xFF
if count > 0 and count <= MAX_CPUS:
return count
return 1
def _wait_icr():
timeout: t.CUInt32T = 1000000
while timeout > 0:
val: t.CUInt32T = read(LAPIC_ICR_LOW)
if (val & (1 << 12)) == 0:
return
timeout -= 1
def _send_ipi(apic_id: t.CUInt32T, vector: t.CUInt32T, delivery_mode: t.CUInt32T):
_wait_icr()
write(LAPIC_ICR_HIGH, apic_id << 24)
write(LAPIC_ICR_LOW, vector | delivery_mode | LAPIC_ICR_LEVEL | LAPIC_ICR_ASSERT)
_wait_icr()
def ap_entry():
global _ap_ready
my_id: t.CUInt32T = get_id()
buf: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(buf), 64, "[AP] core %u started (lapic=%u)\n", my_id, my_id)
serial.puts(buf)
_ap_ready = 1
while True:
asm.sti()
asm.hlt()
_trampoline_bin: t.CArray[t.CUInt8T, 128] = [
0xFA, # cli
0x31, 0xC0, # xor ax, ax
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x0F, 0x01, 0x16, 0x00, 0x7E, # lgdt [0x7E00]
0x0F, 0x20, 0xC0, # mov eax, cr0
0x83, 0xC8, 0x01, # or eax, 1
0x0F, 0x22, 0xC0, # mov cr0, eax
0xEA, 0x1A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x701A
# 32-bit 保护模式开始
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x8E, 0xE0, # mov fs, ax
0x8E, 0xE8, # mov gs, ax
0x8E, 0xD0, # mov ss, ax
0x0F, 0x20, 0xE0, # mov eax, cr4
0x83, 0xC8, 0x20, # or eax, 0x20 (PAE)
0x0F, 0x22, 0xE0, # mov cr4, eax
0x8B, 0x04, 0x25, 0x00, 0x7F, 0x00, 0x00, # mov eax, [0x7F00]
0x0F, 0x22, 0xD8, # mov cr3, eax
0xB9, 0x80, 0x00, 0x00, 0xC0, # mov ecx, 0xC0000080 (EFER)
0x0F, 0x32, # rdmsr
0x83, 0xC8, 0x00, 0x01, 0x00, 0x00, # or eax, 0x100 (LME)
0x0F, 0x79, # wrmsr
0x0F, 0x20, 0xC0, # mov eax, cr0
0x0D, 0x00, 0x00, 0x00, 0x80, # or eax, 0x80000000 (PG)
0x0F, 0x22, 0xC0, # mov cr0, eax
0xEA, 0x5A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x705A
# 64-bit 长模式开始
0x48, 0x8B, 0x24, 0x25, 0x08, 0x7F, 0x00, 0x00, # mov rsp, [0x7F08]
0x0F, 0x01, 0x16, 0x10, 0x7F, # lgdt [0x7F10]
0x0F, 0x01, 0x1E, 0x20, 0x7F, # lidt [0x7F20]
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x8E, 0xE0, # mov fs, ax
0x8E, 0xE8, # mov gs, ax
0x8E, 0xD0, # mov ss, ax
0x48, 0x8B, 0x04, 0x25, 0x28, 0x7F, 0x00, 0x00, # mov rax, [0x7F28]
0xFF, 0xE0 # jmp rax
]
def _setup_trampoline(entry_addr: t.CUInt64T, stack_addr: t.CUInt64T, cr3_val: t.CUInt64T):
dest: t.CUInt8T | t.CPtr = t.CUInt8T(AP_TRAMPOLINE_ADDR, t.CPtr)
src: t.CUInt8T | t.CPtr = c.Addr(_trampoline_bin)
i: t.CInt
for i in range(128):
c.Set(c.Deref(dest + t.CUInt64T(i)), c.Deref(src + t.CUInt64T(i)))
gdt_ptr_addr: t.CUInt64T = AP_TRAMPOLINE_ADDR + 0x0E00
c.Set(c.Deref(t.CUInt16T(gdt_ptr_addr, t.CPtr)), t.CUInt16T(23))
c.Set(c.Deref(t.CUInt64T(gdt_ptr_addr + 2, t.CPtr)), t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0E10))
gdt_addr: t.CUInt64T = AP_TRAMPOLINE_ADDR + 0x0E10
c.Set(c.Deref(t.CUInt64T(gdt_addr, t.CPtr)), t.CUInt64T(0))
c.Set(c.Deref(t.CUInt64T(gdt_addr + 8, t.CPtr)), t.CUInt64T(0x00AF9A000000FFFF))
c.Set(c.Deref(t.CUInt64T(gdt_addr + 16, t.CPtr)), t.CUInt64T(0x00CF92000000FFFF))
c.Set(c.Deref(t.CUInt32T(AP_TRAMPOLINE_ADDR + 0x0F00, t.CPtr)), t.CUInt32T(cr3_val))
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F08, t.CPtr)), stack_addr)
gp_addr: t.CUInt64T = t.CUInt64T(c.Addr(gdt.gp))
gdt_base: t.CUInt64T = c.Deref(t.CUInt64T(gp_addr + 2, t.CPtr))
gdt_limit: t.CUInt16T = c.Deref(t.CUInt16T(gp_addr, t.CPtr))
c.Set(c.Deref(t.CUInt16T(AP_TRAMPOLINE_ADDR + 0x0F10, t.CPtr)), gdt_limit)
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F12, t.CPtr)), gdt_base)
idt_addr: t.CUInt64T = t.CUInt64T(c.Addr(idt.idt))
idt_base: t.CUInt64T = c.Deref(t.CUInt64T(idt_addr + 2, t.CPtr))
idt_limit: t.CUInt16T = c.Deref(t.CUInt16T(idt_addr, t.CPtr))
c.Set(c.Deref(t.CUInt16T(AP_TRAMPOLINE_ADDR + 0x0F20, t.CPtr)), idt_limit)
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F22, t.CPtr)), idt_base)
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F28, t.CPtr)), entry_addr)
def start_aps():
global _cpu_count, _ap_ready
if _cpu_count <= 1: return
cr3_val: t.CUInt64T = 0
c.Asm(f"""mov rax, cr3
mov {c.AsmOut(cr3_val, t.ASM_DESCR.OUTPUT_REG)}, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
stack_size: t.CUInt64T = 8192
i: t.CUInt32T
for i in range(1, _cpu_count):
_ap_ready = 0
stack: t.CVoid | t.CPtr = mm.malloc(stack_size)
if stack is None: continue
stack_top: t.CUInt64T = t.CUInt64T(stack) + stack_size
stack_top = stack_top & ~t.CUInt64T(15)
_setup_trampoline(t.CUInt64T(ap_entry), stack_top, cr3_val)
_send_ipi(i, 0, LAPIC_ICR_INIT)
timer.timer_msleep(10)
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
timer.timer_msleep(1)
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
wait: t.CUInt32T = 0
while _ap_ready == 0 and wait < 5000:
timer.timer_msleep(1)
wait += 1
def early_init():
global _cpu_count, _bsp_lapic_id
# 直接以 IA32_APIC_BASE 的 EN 位(bit 11)判断 APIC 是否可用:
# QEMU/OVMF 必启用,且 msr_read 路径已在前置流程验证可用;
# 比依赖 cpuid 特性位更可靠(避免 cpuid 包装被误判时静默跳过 init)。
msr_val: t.CUInt64T = cpu.msr_read(IA32_APIC_BASE)
if msr_val & APIC_BASE_MSR_ENABLE:
init()
_cpu_count = detect_cpu_count()
else:
_cpu_count = 1
def get_cpu_count() -> t.CUInt32T:
return _cpu_count
def get_base() -> t.CUInt64T:
return _lapic_base
def get_lapic_id() -> t.CUInt32T:
return get_id()
# trampoline 机器码字节数(与下方 _trampoline_bin 初始化列表元素数一致)
AP_TRAMPOLINE_LEN: t.CDefine = 138
_lapic_base: uint64 = 0
_cpu_count: uint32 = 1
_bsp_lapic_id: uint32 = 0
_ap_ready: uint32 = 0
def read(offset: uint32) -> uint32:
addr: uint64 = _lapic_base + uint64(offset)
return c.Deref(uint32(addr, t.CPtr))
def write(offset: uint32, value: uint32):
addr: uint64 = _lapic_base + uint64(offset)
c.Set(c.Deref(uint32(addr, t.CPtr)), value)
def eoi():
write(LAPIC_EOI, 0)
def get_id() -> uint32:
return read(LAPIC_ID) >> 24
@c.Attribute(t.attr.noinline)
def init():
global _lapic_base, _bsp_lapic_id
msr_val: uint64 = cpu.msr_read(IA32_APIC_BASE)
_lapic_base = msr_val & APIC_BASE_ADDR_MASK
cpu.msr_write(IA32_APIC_BASE, msr_val | APIC_BASE_MSR_ENABLE)
_bsp_lapic_id = read(LAPIC_ID) >> 24
write(LAPIC_SVR, LAPIC_SVR_ENABLE | 0xFF)
write(LAPIC_TPR, 0)
write(LAPIC_LVT_TIMER, LAPIC_LVT_MASKED)
write(LAPIC_LVT_LINT0, LAPIC_LVT_DELIVERY_EXTINT)
write(LAPIC_LVT_LINT1, LAPIC_LVT_DELIVERY_NMI)
write(LAPIC_LVT_ERROR, LAPIC_LVT_MASKED)
write(LAPIC_TIMER_DIVIDE, 0x0B)
write(LAPIC_LDR, 0x01000000)
eoi()
@c.Attribute(t.attr.noinline)
def detect_cpu_count() -> uint32:
res: cpu.cpuid_result
cpu.cpuid(0, c.Addr(res))
max_leaf: uint32 = res.eax
if max_leaf >= 0x0B:
cpu.cpuid_sub(0x0B, 0, c.Addr(res))
num_threads: uint32 = res.ebx & 0xFFFF
if num_threads > 0 and num_threads <= MAX_CPUS:
return num_threads
cpu.cpuid(1, c.Addr(res))
if res.edx & cpu.CPU_FEATURE_HTT:
count: uint32 = (res.ebx >> 16) & 0xFF
if count > 0 and count <= MAX_CPUS:
return count
return 1
def _wait_icr():
timeout: uint32 = 1000000
while timeout > 0:
val: uint32 = read(LAPIC_ICR_LOW)
if (val & (1 << 12)) == 0:
return
timeout -= 1
def _send_ipi(apic_id: uint32, vector: uint32, delivery_mode: uint32):
_wait_icr()
write(LAPIC_ICR_HIGH, apic_id << 24)
write(LAPIC_ICR_LOW, vector | delivery_mode | LAPIC_ICR_LEVEL | LAPIC_ICR_ASSERT)
_wait_icr()
def ap_entry():
global _ap_ready
my_id: uint32 = get_id()
buf: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(buf), 64, "[AP] core %u started (lapic=%u)\n", my_id, my_id)
serial.puts(buf)
_ap_ready = 1
while True:
asm.sti()
asm.hlt()
_trampoline_bin: t.CArray[uint8, AP_TRAMPOLINE_LEN] = [
0xFA, # cli
0x31, 0xC0, # xor ax, ax
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x0F, 0x01, 0x16, 0x00, 0x7E, # lgdt [0x7E00]
0x0F, 0x20, 0xC0, # mov eax, cr0
0x83, 0xC8, 0x01, # or eax, 1
0x0F, 0x22, 0xC0, # mov cr0, eax
0xEA, 0x1A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x701A
# 32-bit 保护模式开始
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x8E, 0xE0, # mov fs, ax
0x8E, 0xE8, # mov gs, ax
0x8E, 0xD0, # mov ss, ax
0x0F, 0x20, 0xE0, # mov eax, cr4
0x83, 0xC8, 0x20, # or eax, 0x20 (PAE)
0x0F, 0x22, 0xE0, # mov cr4, eax
0x8B, 0x04, 0x25, 0x00, 0x7F, 0x00, 0x00, # mov eax, [0x7F00]
0x0F, 0x22, 0xD8, # mov cr3, eax
0xB9, 0x80, 0x00, 0x00, 0xC0, # mov ecx, 0xC0000080 (EFER)
0x0F, 0x32, # rdmsr
0x83, 0xC8, 0x00, 0x01, 0x00, 0x00, # or eax, 0x100 (LME)
0x0F, 0x79, # wrmsr
0x0F, 0x20, 0xC0, # mov eax, cr0
0x0D, 0x00, 0x00, 0x00, 0x80, # or eax, 0x80000000 (PG)
0x0F, 0x22, 0xC0, # mov cr0, eax
0xEA, 0x5A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x705A
# 64-bit 长模式开始
0x48, 0x8B, 0x24, 0x25, 0x08, 0x7F, 0x00, 0x00, # mov rsp, [0x7F08]
0x0F, 0x01, 0x16, 0x10, 0x7F, # lgdt [0x7F10]
0x0F, 0x01, 0x1E, 0x20, 0x7F, # lidt [0x7F20]
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x8E, 0xE0, # mov fs, ax
0x8E, 0xE8, # mov gs, ax
0x8E, 0xD0, # mov ss, ax
0x48, 0x8B, 0x04, 0x25, 0x30, 0x7F, 0x00, 0x00, # mov rax, [0x7F30]
0xFF, 0xE0 # jmp rax
]
def _setup_trampoline(entry_addr: uint64, stack_addr: uint64, cr3_val: uint64):
dest: uint8 | t.CPtr = uint8(AP_TRAMPOLINE_ADDR, t.CPtr)
src: uint8 | t.CPtr = c.Addr(_trampoline_bin)
i: int
for i in range(AP_TRAMPOLINE_LEN):
c.Set(c.Deref(dest + uint64(i)), c.Deref(src + uint64(i)))
gdt_ptr_addr: uint64 = AP_TRAMPOLINE_ADDR + 0x0E00
c.Set(c.Deref(uint16(gdt_ptr_addr, t.CPtr)), uint16(23))
c.Set(c.Deref(uint64(gdt_ptr_addr + 2, t.CPtr)), uint64(AP_TRAMPOLINE_ADDR + 0x0E10))
gdt_addr: uint64 = AP_TRAMPOLINE_ADDR + 0x0E10
c.Set(c.Deref(uint64(gdt_addr, t.CPtr)), uint64(0))
c.Set(c.Deref(uint64(gdt_addr + 8, t.CPtr)), uint64(0x00AF9A000000FFFF))
c.Set(c.Deref(uint64(gdt_addr + 16, t.CPtr)), uint64(0x00CF92000000FFFF))
c.Set(c.Deref(uint32(AP_TRAMPOLINE_ADDR + 0x0F00, t.CPtr)), uint32(cr3_val))
c.Set(c.Deref(uint64(AP_TRAMPOLINE_ADDR + 0x0F08, t.CPtr)), stack_addr)
gp_addr: uint64 = uint64(c.Addr(gdt.gp))
gdt_base: uint64 = c.Deref(uint64(gp_addr + 2, t.CPtr))
gdt_limit: uint16 = c.Deref(uint16(gp_addr, t.CPtr))
c.Set(c.Deref(uint16(AP_TRAMPOLINE_ADDR + 0x0F10, t.CPtr)), gdt_limit)
c.Set(c.Deref(uint64(AP_TRAMPOLINE_ADDR + 0x0F12, t.CPtr)), gdt_base)
idt_addr: uint64 = uint64(c.Addr(idt.idt))
idt_base: uint64 = c.Deref(uint64(idt_addr + 2, t.CPtr))
idt_limit: uint16 = c.Deref(uint16(idt_addr, t.CPtr))
c.Set(c.Deref(uint16(AP_TRAMPOLINE_ADDR + 0x0F20, t.CPtr)), idt_limit)
c.Set(c.Deref(uint64(AP_TRAMPOLINE_ADDR + 0x0F22, t.CPtr)), idt_base)
# entry 槽位后移到 0x0F30:idt 伪描述符占 0x0F20..0x0F29(limit 2 + base 8),
# 原来 entry 放 0x0F28 会与其 base 尾部 2 字节重叠 → lidt 读到被覆盖的基址。
c.Set(c.Deref(uint64(AP_TRAMPOLINE_ADDR + 0x0F30, t.CPtr)), entry_addr)
def start_aps():
global _cpu_count, _ap_ready
if _cpu_count <= 1: return
cr3_val: uint64 = 0
c.Asm(f"""mov rax, cr3
mov {c.AsmOut(cr3_val, t.ASM_DESCR.OUTPUT_REG)}, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
stack_size: uint64 = 8192
i: uint32
for i in range(1, _cpu_count):
_ap_ready = 0
stack: t.CPtr = mm.malloc(stack_size)
if stack is None: continue
stack_top: uint64 = uint64(stack) + stack_size
stack_top = stack_top & ~uint64(15)
_setup_trampoline(uint64(ap_entry), stack_top, cr3_val)
_send_ipi(i, 0, LAPIC_ICR_INIT)
timer.timer_msleep(10)
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
timer.timer_msleep(1)
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
wait: uint32 = 0
while _ap_ready == 0 and wait < 5000:
timer.timer_msleep(1)
wait += 1
def early_init():
global _cpu_count, _bsp_lapic_id
# 直接以 IA32_APIC_BASE 的 EN 位(bit 11)判断 APIC 是否可用:
# QEMU/OVMF 必启用,且 msr_read 路径已在前置流程验证可用;
# 比依赖 cpuid 特性位更可靠(避免 cpuid 包装被误判时静默跳过 init)。
msr_val: uint64 = cpu.msr_read(IA32_APIC_BASE)
if msr_val & APIC_BASE_MSR_ENABLE:
init()
_cpu_count = detect_cpu_count()
else:
_cpu_count = 1
def get_cpu_count() -> uint32:
return _cpu_count
def get_base() -> uint64:
return _lapic_base
def get_lapic_id() -> uint32:
return get_id()
+82 -77
View File
@@ -38,38 +38,38 @@ CPU_FEATURE_PBE: t.CDefine = (1 << 25)
class cpu_info(t.CStruct):
vendor_id: t.CArray[t.CChar, 13]
brand_string: t.CArray[t.CChar, 48]
features: t.CUInt32T
family: t.CUInt32T
model: t.CUInt32T
stepping: t.CUInt32T
cpu_type: t.CUInt32T
ext_model: t.CUInt32T
ext_family: t.CUInt32T
cpu_freq: t.CUInt64T
features: uint32
family: uint32
model: uint32
stepping: uint32
cpu_type: uint32
ext_model: uint32
ext_family: uint32
cpu_freq: uint64
@c.Attribute(t.attr.packed)
class _tss:
reserved0: t.CUInt64T
rsp0: t.CUInt64T
rsp1: t.CUInt64T
rsp2: t.CUInt64T
reserved1: t.CUInt64T
ist1: t.CUInt64T
ist2: t.CUInt64T
ist3: t.CUInt64T
ist4: t.CUInt64T
ist5: t.CUInt64T
ist6: t.CUInt64T
ist7: t.CUInt64T
reserved2: t.CUInt64T
reserved3: t.CUInt16T
io_map_base: t.CUInt16T
reserved0: uint64
rsp0: uint64
rsp1: uint64
rsp2: uint64
reserved1: uint64
ist1: uint64
ist2: uint64
ist3: uint64
ist4: uint64
ist5: uint64
ist6: uint64
ist7: uint64
reserved2: uint64
reserved3: uint16
io_map_base: uint16
class cpuid_result(t.CStruct):
eax: t.CUInt32T
ebx: t.CUInt32T
ecx: t.CUInt32T
edx: t.CUInt32T
eax: uint32
ebx: uint32
ecx: uint32
edx: uint32
@c.Attribute(t.attr.naked)
def _rdmsr_naked():
@@ -91,17 +91,17 @@ def _wrmsr_naked():
ret""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
def msr_read(msr: t.CUInt32T) -> t.CUInt64T:
result: t.CUInt64T = 0
func: t.CVoid | t.CPtr = _rdmsr_naked
def msr_read(msr: uint32) -> uint64:
result: uint64 = 0
func: t.CPtr = _rdmsr_naked
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
return result
def msr_write(msr: t.CUInt32T, value: t.CUInt64T):
func: t.CVoid | t.CPtr = _wrmsr_naked
def msr_write(msr: uint32, value: uint64):
func: t.CPtr = _wrmsr_naked
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
mov r8, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
@@ -137,8 +137,8 @@ def _cpuid_sub_naked():
t.ASM_DESCR.CLOBBER_RDX])
@c.Attribute(t.attr.noinline)
def cpuid(leaf: t.CUInt32T, out: cpuid_result | t.CPtr):
func: t.CVoid | t.CPtr = _cpuid_naked
def cpuid(leaf: uint32, out: cpuid_result | t.CPtr):
func: t.CPtr = _cpuid_naked
c.Asm(f"""mov ecx, {c.AsmInp(leaf, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
@@ -148,8 +148,8 @@ def cpuid(leaf: t.CUInt32T, out: cpuid_result | t.CPtr):
t.ASM_DESCR.CLOBBER_R11])
@c.Attribute(t.attr.noinline)
def cpuid_sub(leaf: t.CUInt32T, sub: t.CUInt32T, out: cpuid_result | t.CPtr):
func: t.CVoid | t.CPtr = _cpuid_sub_naked
def cpuid_sub(leaf: uint32, sub: uint32, out: cpuid_result | t.CPtr):
func: t.CPtr = _cpuid_sub_naked
c.Asm(f"""mov ecx, {c.AsmInp(leaf, t.ASM_DESCR.REG_ANY)}
mov r8d, {c.AsmInp(sub, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
@@ -160,8 +160,8 @@ def cpuid_sub(leaf: t.CUInt32T, sub: t.CUInt32T, out: cpuid_result | t.CPtr):
t.ASM_DESCR.CLOBBER_R11])
@c.Attribute(t.attr.noinline)
def detect_features_static() -> t.CUInt32T:
features: t.CUInt32T = 0
def detect_features_static() -> uint32:
features: uint32 = 0
res: cpuid_result
cpuid(1, c.Addr(res))
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
@@ -194,18 +194,18 @@ def detect_features_static() -> t.CUInt32T:
@c.Attribute(t.attr.packed)
class per_cpu_data:
user_rsp: t.CUInt64T
kernel_rsp0: t.CUInt64T
current_pid: t.CInt
_pad0: t.CUInt32T
_pad1: t.CUInt64T
user_rsp: uint64
kernel_rsp0: uint64
current_pid: int
_pad0: uint32
_pad1: uint64
_per_cpu: per_cpu_data
@t.Object
class _CPUObject:
tss: _tss
features: t.CUInt32T
features: uint32
def __init__(self):
self.__init_tss__()
@@ -214,21 +214,21 @@ class _CPUObject:
string.memset(c.Addr(self.tss), 0, self.tss.__sizeof__())
self.tss.io_map_base = self.tss.__sizeof__()
string.memset(c.Addr(_per_cpu), 0, per_cpu_data.__sizeof__())
gdt.setTSS64(5, t.CUInt64T(c.Addr(self.tss)), self.tss.__sizeof__() - 1)
gdt.setTSS64(5, uint64(c.Addr(self.tss)), self.tss.__sizeof__() - 1)
gdt.flush()
# IA32_KERNEL_GS_BASE holds the per_cpu address for swapgs.
# When entering from Ring 3, swapgs swaps IA32_GS_BASE (0) with
# IA32_KERNEL_GS_BASE (_per_cpu), making gs: accessible in kernel.
# When returning to Ring 3, swapgs swaps back, restoring GS base to 0.
msr_write(IA32_KERNEL_GS_BASE, t.CUInt64T(c.Addr(_per_cpu)))
msr_write(IA32_KERNEL_GS_BASE, uint64(c.Addr(_per_cpu)))
def getInfo(self, info: cpu_info | t.CPtr):
if not info: return
res: cpuid_result
cpuid(0, c.Addr(res))
(t.CUInt32T(info.vendor_id, t.CPtr))[0] = res.ebx
(t.CUInt32T(info.vendor_id, t.CPtr))[1] = res.edx
(t.CUInt32T(info.vendor_id, t.CPtr))[2] = res.ecx
(uint32(info.vendor_id, t.CPtr))[0] = res.ebx
(uint32(info.vendor_id, t.CPtr))[1] = res.edx
(uint32(info.vendor_id, t.CPtr))[2] = res.ecx
info.vendor_id[12] = '\0'
info.features = self.detectFeatures()
cpuid(1, c.Addr(res))
@@ -238,18 +238,23 @@ class _CPUObject:
info.cpu_type = (res.eax >> 12) & 0x03
info.ext_model = (res.eax >> 16) & 0x0F
info.ext_family = (res.eax >> 20) & 0xFF
for i in range(4):
# CPUID 品牌串:0x80000002..0x80000004 共 3 个叶 × 16 字节 = 48,
# 与 brand_string[48] 等长(此前 range(4) 会写 64 字节 → 越界 16 字节)。
# 逐 u32 按字节地址显式写入,避免 uint32|t.CPtr 被降级为 i8* 后
# 下标按字节偏移且被截断为 i8(只写低字节、偏移不乘 4)。
brand_addr: uint64 = uint64(uint32(info.brand_string, t.CPtr))
for i in range(3):
cpuid(0x80000002 + i, c.Addr(res))
base: t.CUInt32T | t.CPtr = t.CUInt32T(info.brand_string, t.CPtr)
base[i * 4 + 0] = res.eax
base[i * 4 + 1] = res.ebx
base[i * 4 + 2] = res.ecx
base[i * 4 + 3] = res.edx
off_b: uint64 = uint64(i) * 16
c.Set(c.Deref(uint32(brand_addr + off_b, t.CPtr)), res.eax)
c.Set(c.Deref(uint32(brand_addr + off_b + 4, t.CPtr)), res.ebx)
c.Set(c.Deref(uint32(brand_addr + off_b + 8, t.CPtr)), res.ecx)
c.Set(c.Deref(uint32(brand_addr + off_b + 12, t.CPtr)), res.edx)
info.brand_string[47] = '\0'
info.cpu_freq = 2000000000
def detectFeatures(self) -> t.CUInt32T:
features: t.CInt32T = 0
def detectFeatures(self) -> uint32:
features: int32 = 0
res: cpuid_result
cpuid(1, c.Addr(res))
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
@@ -287,61 +292,61 @@ class _CPUObject:
c.Asm("cli", [t.ASM_DESCR.CLOBBER_MEMORY])
def enableNmis(self):
current: t.CUInt8T = asm.inb(0x70)
current: uint8 = asm.inb(0x70)
asm.outb(0x70, current & 0x7F)
def disableNmis(self):
current: t.CUInt8T = asm.inb(0x70)
current: uint8 = asm.inb(0x70)
asm.outb(0x70, current | 0x80)
def readCR0(self) -> t.CUInt64T:
cr0: t.CUInt64T
def readCR0(self) -> uint64:
cr0: uint64
c.Asm(f"""mov rax, cr0
mov {c.AsmOut(cr0, t.ASM_DESCR.OUTPUT_REG)}, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
return cr0
def writeCR0(self, value: t.CUInt64T):
def writeCR0(self, value: uint64):
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
mov cr0, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
def readCR3(self) -> t.CUInt64T:
cr3: t.CUInt64T
def readCR3(self) -> uint64:
cr3: uint64
c.Asm(f"""mov rax, cr3
mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
return cr3
def writeCR3(self, value: t.CUInt64T):
def writeCR3(self, value: uint64):
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
mov cr3, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
def readCR4(self) -> t.CUInt64T:
cr4: t.CUInt64T
def readCR4(self) -> uint64:
cr4: uint64
c.Asm(f"""mov rax, cr4
mov {c.AsmOut(cr4, t.ASM_DESCR.OUTPUT_REG)}, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
return cr4
def writeCR4(self, value: t.CUInt64T):
def writeCR4(self, value: uint64):
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
mov cr4, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
def readMSR(self, msr: t.CUInt32T) -> t.CUInt64T:
def readMSR(self, msr: uint32) -> uint64:
return msr_read(msr)
def writeMSR(self, msr: t.CUInt32T, value: t.CUInt64T):
def writeMSR(self, msr: uint32, value: uint64):
msr_write(msr, value)
def setTSSRSP0(self, rsp0: t.CUInt64T):
def setTSSRSP0(self, rsp0: uint64):
global _per_cpu
self.tss.rsp0 = rsp0
_per_cpu.kernel_rsp0 = rsp0
def set_kernel_rsp0(rsp0: t.CUInt64T):
def set_kernel_rsp0(rsp0: uint64):
global _per_cpu
_per_cpu.kernel_rsp0 = rsp0
@@ -349,20 +354,20 @@ def set_kernel_rsp0(rsp0: t.CUInt64T):
# OVMF/UEFI 启动后 CR4.OSFXSR 未置位,任何 movaps 都 #GP(err=0)——变参函数
# 传 float/double 时保存 xmm 寄存器触发(serial.printf / snprintf("%.2f") 崩溃根因)。
def enable_sse():
cr0_v: t.CUInt64T = 0
cr0_v: uint64 = 0
c.Asm(f"""mov rax, cr0
mov {c.AsmOut(cr0_v, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
cr0_v = cr0_v & ~t.CUInt64T(4) # 清 EM(禁止 FPU 仿真)
cr0_v = cr0_v | t.CUInt64T(2) # 置 MP(监控协处理器)
cr0_v = cr0_v & ~uint64(4) # 清 EM(禁止 FPU 仿真)
cr0_v = cr0_v | uint64(2) # 置 MP(监控协处理器)
c.Asm(f"""mov rax, {c.AsmInp(cr0_v, t.ASM_DESCR.REG_ANY)}
mov cr0, rax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
cr4_v: t.CUInt64T = 0
cr4_v: uint64 = 0
c.Asm(f"""mov rax, cr4
mov {c.AsmOut(cr4_v, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
cr4_v = cr4_v | t.CUInt64T(0x600) # OSFXSR | OSXMMEXCPT
cr4_v = cr4_v | uint64(0x600) # OSFXSR | OSXMMEXCPT
c.Asm(f"""mov rax, {c.AsmInp(cr4_v, t.ASM_DESCR.REG_ANY)}
mov cr4, rax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
+4 -4
View File
@@ -5,7 +5,7 @@ import t, c
# FPU上下文结构体
@c.Attribute(t.attr.aligned(16))
class fpu_context:
data: t.CArray[t.CUInt8T, 512] # FXSAVE区域大小
data: t.CArray[uint8, 512] # FXSAVE区域大小
@t.Object
@@ -18,14 +18,14 @@ class _FPUObject:
c.Asm("fninit", [t.ASM_DESCR.CLOBBER_MEMORY])
# 启用FPU
def enable(self):
cr0: t.CUInt64T = self.CPUObject.readCR0()
cr0: uint64 = self.CPUObject.readCR0()
# 清除EM位(禁用仿真),设置MP位(监控协处理器)
cr0 &= ~(1 << 2); # 清除EM位
cr0 |= (1 << 1); # 设置MP位
# 写入CR0寄存器
self.CPUObject.writeCR0(cr0)
# 读取CR4寄存器
cr4: t.CUInt64T = self.CPUObject.readCR4()
cr4: uint64 = self.CPUObject.readCR4()
# 设置OSFXSR位和OSXMMEXCPT位,启用SSE
cr4 |= (1 << 9) | (1 << 10)
# 写入CR4寄存器
@@ -34,7 +34,7 @@ class _FPUObject:
c.Asm("fninit", [t.ASM_DESCR.CLOBBER_MEMORY])
# 禁用FPU
def disable(self):
cr0: t.CUInt64T = self.CPUObject.readCR0()
cr0: uint64 = self.CPUObject.readCR0()
# 设置EM位(启用仿真),清除MP位(禁用监控协处理器)
cr0 |= (1 << 2) # 设置EM位
cr0 &= ~(1 << 1) # 清除MP位
+73 -72
View File
@@ -10,15 +10,15 @@ MAX_DIRECTORIES: t.CDefine = 16
PATH_BUFFER_SIZE: t.CDefine = 256
directories: t.CArray[devfs_directory, MAX_DIRECTORIES] = [0]
directory_count: t.CStatic | t.CInt = 0
directory_count: t.CStatic | int = 0
files: t.CArray[devfs_file, MAX_DEVICE_FILES] = [0]
file_count: t.CStatic | t.CInt = 0
file_count: t.CStatic | int = 0
class _fd_table:
file: devfs_file | t.CPtr
flags: t.CInt
flags: int
fd_table: t.CArray[_fd_table, MAX_FILE_DESCRIPTORS] = [0]
@@ -35,7 +35,7 @@ class devfs_directory:
current_dir: devfs_directory | t.CPtr = root_directory
result: t.CArray[str, PATH_BUFFER_SIZE]
token = string.split(path, "/", result)
token = string.split(path, "/", result, PATH_BUFFER_SIZE)
# `for i in result` 按 NULL 终止语义遍历(i8* 元素,split 尾哨兵 NULL 停):
# 编译器 _handle_array_iter 已实现"长度上限 + 解引用为空提前终止"。
@@ -63,12 +63,12 @@ class devfs_directory:
@staticmethod
def list_subdirs(dir_ptr: devfs_directory | t.CPtr,
buffer: str,
size: t.CUInt32T,
pos: t.CInt) -> t.CInt:
size: uint32,
pos: int) -> int:
for d in range(directory_count):
dirp: devfs_directory = c.Addr(directories[d])
if dirp.parent == dir_ptr:
name_len: t.CInt = string.strlen(dirp.name)
name_len: int = string.strlen(dirp.name)
if pos + name_len + 1 > size:
break
string.strcpy(buffer + pos, dirp.name)
@@ -81,7 +81,7 @@ class devfs_directory:
@t.CVTable
class devfs_file:
name: t.CArray[t.CChar, 64]
private_data: t.CVoid | t.CPtr
private_data: t.CPtr
parent_dir: 'devfs_directory' | t.CPtr
@staticmethod
@@ -96,12 +96,12 @@ class devfs_file:
@staticmethod
def list_in_dir(dir_ptr: devfs_directory | t.CPtr,
buffer: str,
size: t.CUInt32T,
pos: t.CInt) -> t.CInt:
size: uint32,
pos: int) -> int:
for f in range(file_count):
filep: devfs_file | t.CPtr = c.Addr(files[f])
if filep.parent_dir == dir_ptr:
name_len: t.CInt = string.strlen(filep.name)
name_len: int = string.strlen(filep.name)
if pos + name_len + 1 > size:
break
string.strcpy(buffer + pos, filep.name)
@@ -110,19 +110,19 @@ class devfs_file:
pos += 1
return pos
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
def open(self, path: t.CConst | str, flags: int) -> int:
return 0
def close(self, fd: t.CInt) -> t.CInt:
def close(self, fd: int) -> int:
return 0
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def read(self, fd: int, buffer: t.CPtr, size: uint32) -> int:
return 0
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def write(self, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
return 0
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
def ioctl(self, fd: int, request: int, arg: t.CPtr) -> int:
return 0
@t.Object
@@ -168,8 +168,8 @@ class _DevFSObject:
current: devfs_directory | t.CPtr = self.root_directory
buf: t.CArray[t.CChar, PATH_BUFFER_SIZE]
string.memset(c.Addr(buf), 0, PATH_BUFFER_SIZE)
buf_idx: t.CInt = 0
p: t.CInt = 0
buf_idx: int = 0
p: int = 0
if path[p] == '/':
p += 1
serial.puts("C")
@@ -199,12 +199,12 @@ class _DevFSObject:
return current
def init(self) -> t.CInt:
def init(self) -> int:
self.create_directory("/dev")
self.create_directory("/dev/input")
return 0
def create_directory(self, path: t.CConst | str) -> t.CInt:
def create_directory(self, path: t.CConst | str) -> int:
serial.puts("T1")
dir_ptr: devfs_directory | t.CPtr = self.find_or_create_directory(path)
serial.puts("T2")
@@ -212,7 +212,7 @@ class _DevFSObject:
def create_file(self, path: t.CConst | str,
file_ptr: devfs_file | t.CPtr,
private_data: t.CVoid | t.CPtr) -> t.CInt:
private_data: t.CPtr) -> int:
global file_count
path_copy: t.CArray[t.CChar, PATH_BUFFER_SIZE]
string.memset(c.Addr(path_copy), 0, PATH_BUFFER_SIZE)
@@ -237,7 +237,7 @@ class _DevFSObject:
if file_ptr:
# [DIAG] 定位 register 阶段 strcpy 目标:打印 file_ptr(用后移除)
_dbg3: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(_dbg3), 80, "[cf] fp=%lx\n", t.CUInt64T(file_ptr))
viperlib.snprintf(c.Addr(_dbg3), 80, "[cf] fp=%lx\n", uint64(file_ptr))
serial.puts(c.Addr(_dbg3))
string.strcpy(file_ptr.name, file_name)
file_ptr.private_data = private_data
@@ -252,7 +252,7 @@ class _DevFSObject:
file_count += 1
return 0
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
def open(self, path: t.CConst | str, flags: int) -> int:
path_copy: t.CArray[t.CChar, PATH_BUFFER_SIZE]
string.memset(c.Addr(path_copy), 0, PATH_BUFFER_SIZE)
string.strcpy(path_copy, path)
@@ -273,12 +273,12 @@ class _DevFSObject:
# [DIAG] 定位 vtable 悬垂:打印 file_ptr 与对象首字段(vtable 指针)(用后移除)
_dbg_buf: t.CArray[t.CChar, 96]
_dbg_vt: t.CUInt64T = t.CUInt64T(file_ptr, t.CPtr)[0]
_dbg_vt: uint64 = uint64(file_ptr, t.CPtr)[0]
viperlib.snprintf(c.Addr(_dbg_buf), 96, "[open] fp=%lx vt=%lx\n",
t.CUInt64T(file_ptr), _dbg_vt)
uint64(file_ptr), _dbg_vt)
serial.puts(c.Addr(_dbg_buf))
fd: t.CInt = -1
fd: int = -1
for i in range(MAX_FILE_DESCRIPTORS):
if not fd_table[i].file:
fd = i
@@ -286,14 +286,14 @@ class _DevFSObject:
if fd == -1: return -1
ret: t.CInt = file_ptr.open(path, flags)
ret: int = file_ptr.open(path, flags)
if ret != 0: return ret
fd_table[fd].file = file_ptr
fd_table[fd].flags = flags
return fd
def close(self, fd: t.CInt) -> t.CInt:
def close(self, fd: int) -> int:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
@@ -302,19 +302,19 @@ class _DevFSObject:
fd_table[fd].flags = 0
return 0
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def read(self, fd: int, buffer: t.CPtr, size: uint32) -> int:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
return file_ptr.read(fd, buffer, size)
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def write(self, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
return file_ptr.write(fd, buffer, size)
def ioctl(self, fd: t.CInt, cmd: t.CUInt32T, arg: t.CVoid | t.CPtr) -> t.CInt:
def ioctl(self, fd: int, cmd: uint32, arg: t.CPtr) -> int:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
@@ -322,11 +322,11 @@ class _DevFSObject:
def list_directory(self, path: t.CConst | str,
buffer: str,
size: t.CUInt32T) -> t.CInt:
size: uint32) -> int:
dir_ptr: devfs_directory | t.CPtr = devfs_directory.find(path, self.root_directory)
if not dir_ptr or not buffer or size == 0: return -1
pos: t.CInt = devfs_directory.list_subdirs(dir_ptr, buffer, size, 0)
pos: int = devfs_directory.list_subdirs(dir_ptr, buffer, size, 0)
pos = devfs_file.list_in_dir(dir_ptr, buffer, size, pos)
return pos
@@ -335,7 +335,7 @@ DevFSObject: _DevFSObject | t.CPtr
_DevFSObject_instance: _DevFSObject
def devfs_init() -> t.CInt:
def devfs_init() -> int:
global DevFSObject, _DevFSObject_instance
DevFSObject = c.Addr(_DevFSObject_instance)
_DevFSObject_instance = _DevFSObject()
@@ -343,57 +343,57 @@ def devfs_init() -> t.CInt:
DevFSObject.init()
return 0
def devfs_create_directory(path: t.CConst | str) -> t.CInt:
def devfs_create_directory(path: t.CConst | str) -> int:
return DevFSObject.create_directory(path)
def devfs_create_file(path: t.CConst | str,
file_ptr: devfs_file | t.CPtr,
private_data: t.CVoid | t.CPtr) -> t.CInt:
private_data: t.CPtr) -> int:
return DevFSObject.create_file(path, file_ptr, private_data)
def devfs_open(path: t.CConst | str, flags: t.CInt) -> t.CInt:
def devfs_open(path: t.CConst | str, flags: int) -> int:
return DevFSObject.open(path, flags)
def devfs_close(fd: t.CInt) -> t.CInt:
def devfs_close(fd: int) -> int:
return DevFSObject.close(fd)
def devfs_read(fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def devfs_read(fd: int, buffer: t.CPtr, size: uint32) -> int:
return DevFSObject.read(fd, buffer, size)
def devfs_write(fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def devfs_write(fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
return DevFSObject.write(fd, buffer, size)
def devfs_ioctl(fd: t.CInt, cmd: t.CUInt32T, arg: t.CVoid | t.CPtr) -> t.CInt:
def devfs_ioctl(fd: int, cmd: uint32, arg: t.CPtr) -> int:
return DevFSObject.ioctl(fd, cmd, arg)
def devfs_list_directory(path: t.CConst | str,
buffer: str,
size: t.CUInt32T) -> t.CInt:
size: uint32) -> int:
return DevFSObject.list_directory(path, buffer, size)
serial0_file: devfs_file
def serial0_open(self: t.CVoid | t.CPtr, path: t.CConst | str, flags: t.CInt) -> t.CInt:
def serial0_open(self: t.CPtr, path: t.CConst | str, flags: int) -> int:
serial.puts("[serial0] open: ")
serial.puts(path)
serial.puts("\n")
return 0
def serial0_close(self: t.CVoid | t.CPtr, fd: t.CInt) -> t.CInt:
def serial0_close(self: t.CPtr, fd: int) -> int:
serial.puts("[serial0] close\n")
return 0
def serial0_read(self: t.CVoid | t.CPtr, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def serial0_read(self: t.CPtr, fd: int, buffer: t.CPtr, size: uint32) -> int:
serial.puts("[serial0] read\n")
return 0
def serial0_write(self: t.CVoid | t.CPtr, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def serial0_write(self: t.CPtr, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
serial.puts("[serial0] write\n")
serial.puts(str(buffer))
serial.puts("\n")
return size
def devfs_register_serial0() -> t.CInt:
def devfs_register_serial0() -> int:
global serial0_file
serial0_file = devfs_file()
serial0_file.open = serial0_open
@@ -405,21 +405,21 @@ def devfs_register_serial0() -> t.CInt:
@t.Object
@t.CVTable
class serial1_device(devfs_file):
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
def open(self, path: t.CConst | str, flags: int) -> int:
serial.puts("[serial1] open: ")
serial.puts(path)
serial.puts("\n")
return 0
def close(self, fd: t.CInt) -> t.CInt:
def close(self, fd: int) -> int:
serial.puts("[serial1] close\n")
return 0
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def read(self, fd: int, buffer: t.CPtr, size: uint32) -> int:
serial.puts("[serial1] read\n")
return 0
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def write(self, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
serial.puts("[serial1] write\n")
serial.puts(str(buffer))
serial.puts("\n")
@@ -427,7 +427,7 @@ class serial1_device(devfs_file):
serial1_file: serial1_device
def devfs_register_serial1() -> t.CInt:
def devfs_register_serial1() -> int:
global serial1_file
serial1_file = serial1_device()
return devfs_create_file("/dev/serial1", serial1_file, None)
@@ -438,16 +438,16 @@ import drivers.input.mouse.mouse as mouse
@t.Object
@t.CVTable
class keyboard_device(devfs_file):
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
def open(self, path: t.CConst | str, flags: int) -> int:
return 0
def close(self, fd: t.CInt) -> t.CInt:
def close(self, fd: int) -> int:
return 0
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
count: t.CUInt32T = 0
def read(self, fd: int, buffer: t.CPtr, size: uint32) -> int:
count: uint32 = 0
while count < size and keyboard.has_data():
sc: t.CUInt8T = keyboard.read_scancode()
sc: uint8 = keyboard.read_scancode()
ch: t.CChar = keyboard.scancode_to_ascii(sc)
if ch != '\0':
# c.Set(t.CChar(...)[count], ch) 是 Subscript 左值,translate_c_set
@@ -456,15 +456,15 @@ class keyboard_device(devfs_file):
count += 1
return count
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def write(self, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
return -1
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
def ioctl(self, fd: int, request: int, arg: t.CPtr) -> int:
return 0
kbd_file: keyboard_device
def devfs_register_keyboard() -> t.CInt:
def devfs_register_keyboard() -> int:
global kbd_file
kbd_file = keyboard_device()
keyboard.init()
@@ -473,34 +473,35 @@ def devfs_register_keyboard() -> t.CInt:
@t.Object
@t.CVTable
class mouse_device(devfs_file):
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
def open(self, path: t.CConst | str, flags: int) -> int:
return 0
def close(self, fd: t.CInt) -> t.CInt:
def close(self, fd: int) -> int:
return 0
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def read(self, fd: int, buffer: t.CPtr, size: uint32) -> int:
if not mouse.has_data(): return 0
pkt: mouse.mouse_packet
mouse.read_packet(c.Addr(pkt))
if size >= 1:
t.CUInt8T(buffer, t.CPtr)[0] = pkt.buttons
if size >= 5:
buf: t.CUInt32T | t.CPtr = t.CVoid(t.CUInt64T(buffer) + 1, t.CPtr)
t.CInt32T(buf, t.CPtr)[0] = mouse.get_x()
t.CInt32T(buf, t.CPtr)[1] = mouse.get_y()
return 5
uint8(buffer, t.CPtr)[0] = pkt.buttons
# 完整包需要 1(buttons) + 4(x) + 4(y) = 9 字节,否则越界写
if size >= 9:
buf: uint32 | t.CPtr = t.CVoid(uint64(buffer) + 1, t.CPtr)
int32(buf, t.CPtr)[0] = mouse.get_x()
int32(buf, t.CPtr)[1] = mouse.get_y()
return 9
return 1
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
def write(self, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
return -1
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
def ioctl(self, fd: int, request: int, arg: t.CPtr) -> int:
return 0
mse_file: mouse_device
def devfs_register_mouse() -> t.CInt:
def devfs_register_mouse() -> int:
global mse_file
mse_file = mouse_device()
mouse.init()
+238 -238
View File
@@ -1,238 +1,238 @@
from stdint import *
import fat32 as fs
import fat32_types as types
import fat32_part as part
import fat32_mkfs as mkfs_mod
import string
import t, c
def print_fresult(res: types.FRESULT, msg: t.CConst | str) -> t.CInt:
if res == types.FRESULT.FR_OK:
print(f"[成功] {msg}")
return 0
else:
print(f"[失败] {msg}: {res}")
return -1
def print_fresult_void(res: types.FRESULT, msg: t.CConst | str):
print_fresult(res, msg)
def example_main() -> t.CInt:
print("=== FAT32 文件系统完整示例 ===")
print()
# 1. 扫描可用驱动器
print("--- 1. 扫描可用驱动器 ---")
res: types.FRESULT = fs.scan_drives()
print_fresult_void(res, "扫描驱动器")
drive_count: t.CInt = fs.get_drive_count()
print(f"找到 {drive_count} 个驱动器")
i: t.CInt
for i in range(drive_count):
letter: t.CChar = fs.get_drive_letter(i)
part_count: t.CInt = fs.get_partition_count(letter)
print(f" 驱动器 {i}: {letter}")
for j in range(part_count):
is_fat32: t.CInt = fs.is_partition_fat32(letter, j)
print(f" 分区 {j}: FAT32={is_fat32}")
print()
# 2. 挂载文件系统
print("--- 2. 挂载文件系统 ---")
res = fs.mount()
if print_fresult(res, "挂载文件系统") != 0:
print("提示: 可能需要先格式化磁盘")
print()
# 3. 文件系统信息
print("--- 3. 文件系统信息 ---")
mounted: t.CInt = fs.is_mounted()
print(f"已挂载: {mounted}")
if mounted:
total_clusters: t.CUInt32T = fs.get_total()
free_clusters: t.CUInt32T = fs.get_free()
cluster_size: t.CUInt32T = fs.get_cluster_size()
total_bytes: t.CUInt64T = t.CUInt64T(total_clusters) * t.CUInt64T(cluster_size)
free_bytes: t.CUInt64T = t.CUInt64T(free_clusters) * t.CUInt64T(cluster_size)
print(f"总簇数: {total_clusters}")
print(f"空闲簇数: {free_clusters}")
print(f"簇大小: {cluster_size} 字节")
print(f"总大小: {total_bytes} 字节")
print(f"空闲大小: {free_bytes} 字节")
print()
# 4. 元数据操作
print("--- 4. 元数据操作 ---")
fs.set_metadata(0x12345678)
metadata: t.CUInt32T = fs.get_metadata()
print(f"设置的元数据: 0x{metadata:08X}")
print()
# 5. 获取 FAT 时间
print("--- 5. 获取 FAT 时间 ---")
fattime: t.CUInt32T = fs.get_fattime()
print(f"当前 FAT 时间: 0x{fattime:08X}")
print()
# 6. 目录操作
if fs.is_mounted():
print("--- 6. 目录操作 ---")
# 创建目录
res = fs.mkdir("/test_dir_1")
print_fresult_void(res, "创建目录 /test_dir_1")
res = fs.mkdir("/test_dir_1/subdir")
print_fresult_void(res, "创建子目录 /test_dir_1/subdir")
res = fs.mkdir("/test_dir_2")
print_fresult_void(res, "创建目录 /test_dir_2")
print()
# 7. 文件操作
print("--- 7. 文件操作 ---")
# 创建并写入文件
fp1: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
if fp1 is not None:
test_data1: t.CConst | str = "Hello, World!"
written: t.CUInt32T = fs.write(fp1, test_data1, 13)
print(f"写入文件 /test_dir_1/file1.txt: {written} 字节")
fs.close(fp1)
# 打开追加
fp2: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_ALWAYS | types.FA_WRITE | types.FA_OPEN_APPEND)
if fp2 is not None:
test_data2: t.CConst | str = " Append data!"
written2: t.CUInt32T = fs.write(fp2, test_data2, 13)
print(f"追加写入: {written2} 字节")
fs.close(fp2)
# 读取文件
fp3: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_EXISTING | types.FA_READ)
if fp3 is not None:
buf: t.CArray[t.CUInt8T, 256]
read_bytes: t.CUInt32T = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
print(f"读取字节数: {read_bytes}")
print(f"文件内容: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
# seek 和 tell
fs.seek(fp3, 5)
pos: t.CUInt32T = fs.tell(fp3)
print(f"seek 到位置 5, 当前位置: {pos}")
read_bytes2: t.CUInt32T = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
print(f"从位置 5 读取: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
# 获取文件大小
fsize: t.CUInt32T = fs.size(fp3)
print(f"文件大小: {fsize} 字节")
fs.close(fp3)
# 创建另一个文件
fp4: types.fileobj | t.CPtr = fs.open("/test_dir_1/large_file.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
if fp4 is not None:
large_data: t.CArray[t.CUInt8T, 1024]
k: t.CInt
for k in range(1024):
large_data[k] = t.CUInt8T(ord('A') + (k % 26))
written3: t.CUInt32T = fs.write(fp4, t.CVoid(c.Addr(large_data[0]), t.CPtr), 1024)
print(f"创建大文件, 写入: {written3} 字节")
fs.close(fp4)
print()
# 8. 文件状态和属性
print("--- 8. 文件状态和属性 ---")
info: types.fileinfo
res = fs.stat("/test_dir_1/file1.txt", c.Addr(info))
print_fresult_void(res, "获取文件信息")
if res == types.FRESULT.FR_OK:
print(f" 文件名: {info.fname}")
print(f" 大小: {info.file_size} 字节")
print(f" 属性: 0x{info.attr:02X}")
print(f" 创建时间: 0x{info.ctime:04X}")
print(f" 创建日期: 0x{info.cdate:04X}")
print(f" 修改时间: 0x{info.mtime:04X}")
print(f" 修改日期: 0x{info.mdate:04X}")
print(f" 访问日期: 0x{info.adate:04X}")
# 修改属性
res = fs.chmod("/test_dir_1/file1.txt", types.AM_RDO, types.AM_RDO)
print_fresult_void(res, "设置文件为只读")
print()
# 9. 重命名和移动
print("--- 9. 重命名和移动 ---")
res = fs.rename("/test_dir_1/file1.txt", "/test_dir_1/renamed.txt")
print_fresult_void(res, "重命名文件")
res = fs.move("/test_dir_1/renamed.txt", "/test_dir_2/moved.txt")
print_fresult_void(res, "移动文件")
res = fs.rename("/test_dir_2", "/test_dir_renamed")
print_fresult_void(res, "重命名目录")
print()
# 10. 列出目录
print("--- 10. 列出目录 ---")
dp: types.dirobj
res = fs.opendir("/", c.Addr(dp))
if res == types.FRESULT.FR_OK:
print("根目录内容:")
dir_info: types.fileinfo
while True:
res = fs.readdir(c.Addr(dp), c.Addr(dir_info))
if res != types.FRESULT.FR_OK:
break
attr_str: t.CArray[t.CChar, 8] = [0]
if dir_info.attr & types.AM_DIR:
string.strcat(attr_str, "D")
else:
string.strcat(attr_str, "F")
if dir_info.attr & types.AM_RDO:
string.strcat(attr_str, "R")
if dir_info.attr & types.AM_HID:
string.strcat(attr_str, "H")
if dir_info.attr & types.AM_SYS:
string.strcat(attr_str, "S")
if dir_info.attr & types.AM_ARC:
string.strcat(attr_str, "A")
print(f" [{attr_str}] {dir_info.fname} ({dir_info.file_size} 字节)")
fs.closedir(c.Addr(dp))
print()
# 11. 删除文件和目录
print("--- 11. 删除文件和目录 ---")
res = fs.remove("/test_dir_renamed/moved.txt")
print_fresult_void(res, "删除文件")
res = fs.remove("/test_dir_1/large_file.txt")
print_fresult_void(res, "删除大文件")
res = fs.rmdir("/test_dir_1/subdir")
print_fresult_void(res, "删除子目录")
res = fs.rmdir("/test_dir_1")
print_fresult_void(res, "删除目录 /test_dir_1")
res = fs.rmdir("/test_dir_renamed")
print_fresult_void(res, "删除目录 /test_dir_renamed")
print()
# 12. 卸载文件系统
print("--- 12. 卸载文件系统 ---")
res = fs.unmount()
print_fresult_void(res, "卸载文件系统")
print()
print("=== 示例完成 ===")
return 0
from stdint import *
import fat32 as fs
import fat32_types as types
import fat32_part as part
import fat32_mkfs as mkfs_mod
import string
import t, c
def print_fresult(res: types.FRESULT, msg: t.CConst | str) -> int:
if res == types.FRESULT.FR_OK:
print(f"[成功] {msg}")
return 0
else:
print(f"[失败] {msg}: {res}")
return -1
def print_fresult_void(res: types.FRESULT, msg: t.CConst | str):
print_fresult(res, msg)
def example_main() -> int:
print("=== FAT32 文件系统完整示例 ===")
print()
# 1. 扫描可用驱动器
print("--- 1. 扫描可用驱动器 ---")
res: types.FRESULT = fs.scan_drives()
print_fresult_void(res, "扫描驱动器")
drive_count: int = fs.get_drive_count()
print(f"找到 {drive_count} 个驱动器")
i: int
for i in range(drive_count):
letter: t.CChar = fs.get_drive_letter(i)
part_count: int = fs.get_partition_count(letter)
print(f" 驱动器 {i}: {letter}")
for j in range(part_count):
is_fat32: int = fs.is_partition_fat32(letter, j)
print(f" 分区 {j}: FAT32={is_fat32}")
print()
# 2. 挂载文件系统
print("--- 2. 挂载文件系统 ---")
res = fs.mount()
if print_fresult(res, "挂载文件系统") != 0:
print("提示: 可能需要先格式化磁盘")
print()
# 3. 文件系统信息
print("--- 3. 文件系统信息 ---")
mounted: int = fs.is_mounted()
print(f"已挂载: {mounted}")
if mounted:
total_clusters: uint32 = fs.get_total()
free_clusters: uint32 = fs.get_free()
cluster_size: uint32 = fs.get_cluster_size()
total_bytes: uint64 = uint64(total_clusters) * uint64(cluster_size)
free_bytes: uint64 = uint64(free_clusters) * uint64(cluster_size)
print(f"总簇数: {total_clusters}")
print(f"空闲簇数: {free_clusters}")
print(f"簇大小: {cluster_size} 字节")
print(f"总大小: {total_bytes} 字节")
print(f"空闲大小: {free_bytes} 字节")
print()
# 4. 元数据操作
print("--- 4. 元数据操作 ---")
fs.set_metadata(0x12345678)
metadata: uint32 = fs.get_metadata()
print(f"设置的元数据: 0x{metadata:08X}")
print()
# 5. 获取 FAT 时间
print("--- 5. 获取 FAT 时间 ---")
fattime: uint32 = fs.get_fattime()
print(f"当前 FAT 时间: 0x{fattime:08X}")
print()
# 6. 目录操作
if fs.is_mounted():
print("--- 6. 目录操作 ---")
# 创建目录
res = fs.mkdir("/test_dir_1")
print_fresult_void(res, "创建目录 /test_dir_1")
res = fs.mkdir("/test_dir_1/subdir")
print_fresult_void(res, "创建子目录 /test_dir_1/subdir")
res = fs.mkdir("/test_dir_2")
print_fresult_void(res, "创建目录 /test_dir_2")
print()
# 7. 文件操作
print("--- 7. 文件操作 ---")
# 创建并写入文件
fp1: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
if fp1 is not None:
test_data1: t.CConst | str = "Hello, World!"
written: uint32 = fs.write(fp1, test_data1, 13)
print(f"写入文件 /test_dir_1/file1.txt: {written} 字节")
fs.close(fp1)
# 打开追加
fp2: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_ALWAYS | types.FA_WRITE | types.FA_OPEN_APPEND)
if fp2 is not None:
test_data2: t.CConst | str = " Append data!"
written2: uint32 = fs.write(fp2, test_data2, 13)
print(f"追加写入: {written2} 字节")
fs.close(fp2)
# 读取文件
fp3: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_EXISTING | types.FA_READ)
if fp3 is not None:
buf: t.CArray[uint8, 256]
read_bytes: uint32 = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
print(f"读取字节数: {read_bytes}")
print(f"文件内容: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
# seek 和 tell
fs.seek(fp3, 5)
pos: uint32 = fs.tell(fp3)
print(f"seek 到位置 5, 当前位置: {pos}")
read_bytes2: uint32 = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
print(f"从位置 5 读取: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
# 获取文件大小
fsize: uint32 = fs.size(fp3)
print(f"文件大小: {fsize} 字节")
fs.close(fp3)
# 创建另一个文件
fp4: types.fileobj | t.CPtr = fs.open("/test_dir_1/large_file.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
if fp4 is not None:
large_data: t.CArray[uint8, 1024]
k: int
for k in range(1024):
large_data[k] = uint8(ord('A') + (k % 26))
written3: uint32 = fs.write(fp4, t.CVoid(c.Addr(large_data[0]), t.CPtr), 1024)
print(f"创建大文件, 写入: {written3} 字节")
fs.close(fp4)
print()
# 8. 文件状态和属性
print("--- 8. 文件状态和属性 ---")
info: types.fileinfo
res = fs.stat("/test_dir_1/file1.txt", c.Addr(info))
print_fresult_void(res, "获取文件信息")
if res == types.FRESULT.FR_OK:
print(f" 文件名: {info.fname}")
print(f" 大小: {info.file_size} 字节")
print(f" 属性: 0x{info.attr:02X}")
print(f" 创建时间: 0x{info.ctime:04X}")
print(f" 创建日期: 0x{info.cdate:04X}")
print(f" 修改时间: 0x{info.mtime:04X}")
print(f" 修改日期: 0x{info.mdate:04X}")
print(f" 访问日期: 0x{info.adate:04X}")
# 修改属性
res = fs.chmod("/test_dir_1/file1.txt", types.AM_RDO, types.AM_RDO)
print_fresult_void(res, "设置文件为只读")
print()
# 9. 重命名和移动
print("--- 9. 重命名和移动 ---")
res = fs.rename("/test_dir_1/file1.txt", "/test_dir_1/renamed.txt")
print_fresult_void(res, "重命名文件")
res = fs.move("/test_dir_1/renamed.txt", "/test_dir_2/moved.txt")
print_fresult_void(res, "移动文件")
res = fs.rename("/test_dir_2", "/test_dir_renamed")
print_fresult_void(res, "重命名目录")
print()
# 10. 列出目录
print("--- 10. 列出目录 ---")
dp: types.dirobj
res = fs.opendir("/", c.Addr(dp))
if res == types.FRESULT.FR_OK:
print("根目录内容:")
dir_info: types.fileinfo
while True:
res = fs.readdir(c.Addr(dp), c.Addr(dir_info))
if res != types.FRESULT.FR_OK:
break
attr_str: t.CArray[t.CChar, 8] = [0]
if dir_info.attr & types.AM_DIR:
string.strcat(attr_str, "D")
else:
string.strcat(attr_str, "F")
if dir_info.attr & types.AM_RDO:
string.strcat(attr_str, "R")
if dir_info.attr & types.AM_HID:
string.strcat(attr_str, "H")
if dir_info.attr & types.AM_SYS:
string.strcat(attr_str, "S")
if dir_info.attr & types.AM_ARC:
string.strcat(attr_str, "A")
print(f" [{attr_str}] {dir_info.fname} ({dir_info.file_size} 字节)")
fs.closedir(c.Addr(dp))
print()
# 11. 删除文件和目录
print("--- 11. 删除文件和目录 ---")
res = fs.remove("/test_dir_renamed/moved.txt")
print_fresult_void(res, "删除文件")
res = fs.remove("/test_dir_1/large_file.txt")
print_fresult_void(res, "删除大文件")
res = fs.rmdir("/test_dir_1/subdir")
print_fresult_void(res, "删除子目录")
res = fs.rmdir("/test_dir_1")
print_fresult_void(res, "删除目录 /test_dir_1")
res = fs.rmdir("/test_dir_renamed")
print_fresult_void(res, "删除目录 /test_dir_renamed")
print()
# 12. 卸载文件系统
print("--- 12. 卸载文件系统 ---")
res = fs.unmount()
print_fresult_void(res, "卸载文件系统")
print()
print("=== 示例完成 ===")
return 0
+214 -214
View File
@@ -1,214 +1,214 @@
from stdint import *
import string
import fat32_types as types
import fat32_time as ftime
import fat32_mkfs as mkfs_mod
import fat32_part as part
import fat32_diskio as diskio
import sched.sched as sched
import viperlib
import drivers.serial.uart.serial as serial
import t, c
default_fs: types.volinfo = types.volinfo()
_fs_lock: t.CInt = 0
def lock():
global _fs_lock
while True:
c.Asm("cli")
if _fs_lock == 0:
_fs_lock = 1
c.Asm("sti")
return
c.Asm("sti")
sched.Scheduler._yield()
def unlock():
global _fs_lock
_fs_lock = 0
def mount() -> types.FRESULT:
default_fs.pdrv = 0
default_fs.hidden_sectors = 0
buf: t.CArray[t.CUInt8T, 512]
dres: types.DRESULT = diskio.read(0, c.Addr(buf[0]), 0, 1)
if dres == types.DRESULT.RES_OK:
if buf[0] == 0xEB or buf[0] == 0xE9:
default_fs.hidden_sectors = 0
else:
sig: t.CUInt16T = t.CUInt16T(buf[510]) | (t.CUInt16T(buf[511]) << 8)
if sig == 0xAA55:
ptype: t.CUInt8T = buf[450]
if ptype != 0:
slba: t.CUInt32T = t.CUInt32T(buf[454]) | (t.CUInt32T(buf[455]) << 8) | (t.CUInt32T(buf[456]) << 16) | (t.CUInt32T(buf[457]) << 24)
default_fs.hidden_sectors = slba
if default_fs.mounted: return types.FRESULT.FR_OK
dsk_res: types.DRESULT = diskio.status(default_fs.pdrv)
if dsk_res != types.DRESULT.RES_OK:
dsk_res = diskio.init(default_fs.pdrv)
if dsk_res != types.DRESULT.RES_OK: return types.FRESULT.FR_NOT_READY
default_fs.winsect = 0xFFFFFFFFFFFFFFFF
default_fs.fat_winsect = 0xFFFFFFFFFFFFFFFF
wres: types.FRESULT = default_fs.win_read(0)
if wres != types.FRESULT.FR_OK: return types.FRESULT.FR_DISK_ERR
bps: t.CUInt16T = default_fs.win[11] | (t.CUInt16T(default_fs.win[12]) << 8)
spc: t.CUInt8T = default_fs.win[13]
rsc: t.CUInt16T = default_fs.win[14] | (t.CUInt16T(default_fs.win[15]) << 8)
nf: t.CUInt8T = default_fs.win[16]
if bps != 512: return types.FRESULT.FR_NO_FILESYSTEM
if spc == 0 or (spc & (spc - 1)) != 0: return types.FRESULT.FR_NO_FILESYSTEM
if rsc == 0: return types.FRESULT.FR_NO_FILESYSTEM
if nf == 0: return types.FRESULT.FR_NO_FILESYSTEM
root_ent: t.CUInt16T = default_fs.win[17] | (t.CUInt16T(default_fs.win[18]) << 8)
fat16sz: t.CUInt16T = default_fs.win[22] | (t.CUInt16T(default_fs.win[23]) << 8)
tot32: t.CUInt32T = t.CUInt32T(default_fs.win[32]) | (t.CUInt32T(default_fs.win[33]) << 8) | (t.CUInt32T(default_fs.win[34]) << 16) | (t.CUInt32T(default_fs.win[35]) << 24)
fat32sz: t.CUInt32T = t.CUInt32T(default_fs.win[36]) | (t.CUInt32T(default_fs.win[37]) << 8) | (t.CUInt32T(default_fs.win[38]) << 16) | (t.CUInt32T(default_fs.win[39]) << 24)
root_clus: t.CUInt32T = t.CUInt32T(default_fs.win[44]) | (t.CUInt32T(default_fs.win[45]) << 8) | (t.CUInt32T(default_fs.win[46]) << 16) | (t.CUInt32T(default_fs.win[47]) << 24)
if root_ent != 0 or fat16sz != 0: return types.FRESULT.FR_NO_FILESYSTEM
if fat32sz == 0: return types.FRESULT.FR_NO_FILESYSTEM
if tot32 == 0: return types.FRESULT.FR_NO_FILESYSTEM
if default_fs.win[510] != 0x55 or default_fs.win[511] != 0xAA: return types.FRESULT.FR_NO_FILESYSTEM
fsinfo_sec: t.CUInt16T = default_fs.win[48] | (t.CUInt16T(default_fs.win[49]) << 8)
bkboot_sec: t.CUInt16T = default_fs.win[50] | (t.CUInt16T(default_fs.win[51]) << 8)
default_fs.sector_size = 512
default_fs.cluster_sectors = spc
default_fs.cluster_size = t.CUInt32T(spc) * 512
default_fs.num_fats = nf
default_fs.reserved_sectors = rsc
default_fs.fat_size = fat32sz
default_fs.fat_start = t.CUInt64T(rsc)
default_fs.total_sectors = t.CUInt64T(tot32)
default_fs.root_cluster = root_clus
default_fs.fsinfo_sector = fsinfo_sec
default_fs.backup_sector = bkboot_sec
default_fs.vol_id = t.CUInt32T(default_fs.win[67]) | (t.CUInt32T(default_fs.win[68]) << 8) | (t.CUInt32T(default_fs.win[69]) << 16) | (t.CUInt32T(default_fs.win[70]) << 24)
data_sectors: t.CUInt64T = default_fs.total_sectors - t.CUInt64T(rsc) - t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
default_fs.total_clusters = t.CUInt32T(data_sectors / t.CUInt64T(spc))
default_fs.data_start = default_fs.fat_start + t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
default_fs.last_alloc = 2
default_fs.free_clusters = 0xFFFFFFFF
if fsinfo_sec != 0:
default_fs.fsinfo_read()
default_fs.mounted = 1
return types.FRESULT.FR_OK
def unmount() -> types.FRESULT:
return default_fs.unmount()
def format(sec_per_clus: t.CUInt8T = 0, vol_id: t.CUInt32T = 0) -> types.FRESULT:
return mkfs_mod.mkfs(default_fs.pdrv, sec_per_clus, vol_id)
def open(path: t.CConst | str, mode: t.CUInt8T) -> types.fileobj | t.CPtr:
return default_fs.file_open(path, mode)
def close(fp: types.fileobj | t.CPtr) -> types.FRESULT:
return fp.close()
def read(fp: types.fileobj | t.CPtr, buff: t.CVoid | t.CPtr, btr: t.CUInt32T) -> t.CUInt32T:
br: t.CUInt32T = 0
fp.read(buff, btr, c.Addr(br))
# [RD2-DIAG] 确认 br 是否被 c.Set 写入(types 内 total_read=64 但外部可能收不到)
_rd2: t.CArray[t.CChar, 96]
viperlib.snprintf(c.Addr(_rd2), 96, "[fat32.vp] read br=%lu\n", br)
serial.puts(c.Addr(_rd2))
return br
def write(fp: types.fileobj | t.CPtr, buff: t.CConst | t.CVoid | t.CPtr, btw: t.CUInt32T) -> t.CUInt32T:
bw: t.CUInt32T = 0
fp.write(buff, btw, c.Addr(bw))
return bw
def seek(fp: types.fileobj | t.CPtr, offset: t.CUInt32T) -> types.FRESULT:
return fp.seek(offset)
def tell(fp: types.fileobj | t.CPtr) -> t.CUInt32T:
return fp.tell()
def size(fp: types.fileobj | t.CPtr) -> t.CUInt32T:
return fp.size()
def truncate(fp: types.fileobj | t.CPtr) -> types.FRESULT:
return fp.truncate()
def remove(path: t.CConst | str) -> types.FRESULT:
return default_fs.file_delete(path)
def rename(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
return default_fs.file_rename(old_path, new_path)
def move(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
return default_fs.file_rename(old_path, new_path)
def stat(path: t.CConst | str, info: types.fileinfo | t.CPtr) -> types.FRESULT:
return default_fs.file_stat(path, info)
def mkdir(path: t.CConst | str) -> types.FRESULT:
return default_fs.dir_make(path)
def rmdir(path: t.CConst | str) -> types.FRESULT:
return default_fs.dir_remove(path)
def opendir(path: t.CConst | str, dp: types.dirobj | t.CPtr) -> types.FRESULT:
return default_fs.dir_open_path(path, dp)
def readdir(dp: types.dirobj | t.CPtr, info: types.fileinfo | t.CPtr) -> types.FRESULT:
return default_fs.dir_read(dp, info)
def closedir(dp: types.dirobj | t.CPtr):
dp.is_open = 0
def chmod(path: t.CConst | str, attr: t.CUInt8T, mask: t.CUInt8T) -> types.FRESULT:
return default_fs.chmod(path, attr, mask)
def utime(path: t.CConst | str, mtime: t.CUInt16T, mdate: t.CUInt16T) -> types.FRESULT:
return default_fs.utime(path, mtime, mdate)
def get_free() -> t.CUInt32T:
if not default_fs.mounted: return 0
if default_fs.free_clusters == 0xFFFFFFFF:
return default_fs.count_free_clusters()
return default_fs.free_clusters
def get_total() -> t.CUInt32T:
if not default_fs.mounted: return 0
return default_fs.total_clusters
def get_cluster_size() -> t.CUInt32T:
if not default_fs.mounted: return 0
return default_fs.cluster_size
def is_mounted() -> t.CInt:
return default_fs.mounted
def last_error() -> t.CUInt32T:
return default_fs.last_error
def get_fattime() -> t.CUInt32T:
return ftime.get_fattime()
def get_metadata() -> t.CUInt32T:
return default_fs.metadata
def set_metadata(val: t.CUInt32T):
default_fs.metadata = val
def scan_drives() -> types.FRESULT:
return part.scan_drives()
def get_drive_count() -> t.CInt:
return part.get_drive_count()
def get_drive_letter(idx: t.CInt) -> t.CChar:
return part.get_drive_letter(idx)
def set_drive_letter(idx: t.CInt, letter: t.CChar) -> types.FRESULT:
return part.set_drive_letter(idx, letter)
def get_partition_count(letter: t.CChar) -> t.CInt:
return part.get_partition_count(letter)
def is_partition_fat32(letter: t.CChar, part_idx: t.CInt) -> t.CInt:
return part.is_partition_fat32(letter, part_idx)
from stdint import *
import string
import fat32_types as types
import fat32_time as ftime
import fat32_mkfs as mkfs_mod
import fat32_part as part
import fat32_diskio as diskio
import sched.sched as sched
import viperlib
import drivers.serial.uart.serial as serial
import t, c
default_fs: types.volinfo = types.volinfo()
_fs_lock: int = 0
def lock():
global _fs_lock
while True:
c.Asm("cli")
if _fs_lock == 0:
_fs_lock = 1
c.Asm("sti")
return
c.Asm("sti")
sched.Scheduler._yield()
def unlock():
global _fs_lock
_fs_lock = 0
def mount() -> types.FRESULT:
default_fs.pdrv = 0
default_fs.hidden_sectors = 0
buf: t.CArray[uint8, 512]
dres: types.DRESULT = diskio.read(0, c.Addr(buf[0]), 0, 1)
if dres == types.DRESULT.RES_OK:
if buf[0] == 0xEB or buf[0] == 0xE9:
default_fs.hidden_sectors = 0
else:
sig: uint16 = uint16(buf[510]) | (uint16(buf[511]) << 8)
if sig == 0xAA55:
ptype: uint8 = buf[450]
if ptype != 0:
slba: uint32 = uint32(buf[454]) | (uint32(buf[455]) << 8) | (uint32(buf[456]) << 16) | (uint32(buf[457]) << 24)
default_fs.hidden_sectors = slba
if default_fs.mounted: return types.FRESULT.FR_OK
dsk_res: types.DRESULT = diskio.status(default_fs.pdrv)
if dsk_res != types.DRESULT.RES_OK:
dsk_res = diskio.init(default_fs.pdrv)
if dsk_res != types.DRESULT.RES_OK: return types.FRESULT.FR_NOT_READY
default_fs.winsect = 0xFFFFFFFFFFFFFFFF
default_fs.fat_winsect = 0xFFFFFFFFFFFFFFFF
wres: types.FRESULT = default_fs.win_read(0)
if wres != types.FRESULT.FR_OK: return types.FRESULT.FR_DISK_ERR
bps: uint16 = default_fs.win[11] | (uint16(default_fs.win[12]) << 8)
spc: uint8 = default_fs.win[13]
rsc: uint16 = default_fs.win[14] | (uint16(default_fs.win[15]) << 8)
nf: uint8 = default_fs.win[16]
if bps != 512: return types.FRESULT.FR_NO_FILESYSTEM
if spc == 0 or (spc & (spc - 1)) != 0: return types.FRESULT.FR_NO_FILESYSTEM
if rsc == 0: return types.FRESULT.FR_NO_FILESYSTEM
if nf == 0: return types.FRESULT.FR_NO_FILESYSTEM
root_ent: uint16 = default_fs.win[17] | (uint16(default_fs.win[18]) << 8)
fat16sz: uint16 = default_fs.win[22] | (uint16(default_fs.win[23]) << 8)
tot32: uint32 = uint32(default_fs.win[32]) | (uint32(default_fs.win[33]) << 8) | (uint32(default_fs.win[34]) << 16) | (uint32(default_fs.win[35]) << 24)
fat32sz: uint32 = uint32(default_fs.win[36]) | (uint32(default_fs.win[37]) << 8) | (uint32(default_fs.win[38]) << 16) | (uint32(default_fs.win[39]) << 24)
root_clus: uint32 = uint32(default_fs.win[44]) | (uint32(default_fs.win[45]) << 8) | (uint32(default_fs.win[46]) << 16) | (uint32(default_fs.win[47]) << 24)
if root_ent != 0 or fat16sz != 0: return types.FRESULT.FR_NO_FILESYSTEM
if fat32sz == 0: return types.FRESULT.FR_NO_FILESYSTEM
if tot32 == 0: return types.FRESULT.FR_NO_FILESYSTEM
if default_fs.win[510] != 0x55 or default_fs.win[511] != 0xAA: return types.FRESULT.FR_NO_FILESYSTEM
fsinfo_sec: uint16 = default_fs.win[48] | (uint16(default_fs.win[49]) << 8)
bkboot_sec: uint16 = default_fs.win[50] | (uint16(default_fs.win[51]) << 8)
default_fs.sector_size = 512
default_fs.cluster_sectors = spc
default_fs.cluster_size = uint32(spc) * 512
default_fs.num_fats = nf
default_fs.reserved_sectors = rsc
default_fs.fat_size = fat32sz
default_fs.fat_start = uint64(rsc)
default_fs.total_sectors = uint64(tot32)
default_fs.root_cluster = root_clus
default_fs.fsinfo_sector = fsinfo_sec
default_fs.backup_sector = bkboot_sec
default_fs.vol_id = uint32(default_fs.win[67]) | (uint32(default_fs.win[68]) << 8) | (uint32(default_fs.win[69]) << 16) | (uint32(default_fs.win[70]) << 24)
data_sectors: uint64 = default_fs.total_sectors - uint64(rsc) - uint64(uint64(nf) * uint64(fat32sz))
default_fs.total_clusters = uint32(data_sectors / uint64(spc))
default_fs.data_start = default_fs.fat_start + uint64(uint64(nf) * uint64(fat32sz))
default_fs.last_alloc = 2
default_fs.free_clusters = 0xFFFFFFFF
if fsinfo_sec != 0:
default_fs.fsinfo_read()
default_fs.mounted = 1
return types.FRESULT.FR_OK
def unmount() -> types.FRESULT:
return default_fs.unmount()
def format(sec_per_clus: uint8 = 0, vol_id: uint32 = 0) -> types.FRESULT:
return mkfs_mod.mkfs(default_fs.pdrv, sec_per_clus, vol_id)
def open(path: t.CConst | str, mode: uint8) -> types.fileobj | t.CPtr:
return default_fs.file_open(path, mode)
def close(fp: types.fileobj | t.CPtr) -> types.FRESULT:
return fp.close()
def read(fp: types.fileobj | t.CPtr, buff: t.CPtr, btr: uint32) -> uint32:
br: uint32 = 0
fp.read(buff, btr, c.Addr(br))
# [RD2-DIAG] 确认 br 是否被 c.Set 写入(types 内 total_read=64 但外部可能收不到)
_rd2: t.CArray[t.CChar, 96]
viperlib.snprintf(c.Addr(_rd2), 96, "[fat32.vp] read br=%lu\n", br)
serial.puts(c.Addr(_rd2))
return br
def write(fp: types.fileobj | t.CPtr, buff: t.CConst | t.CPtr, btw: uint32) -> uint32:
bw: uint32 = 0
fp.write(buff, btw, c.Addr(bw))
return bw
def seek(fp: types.fileobj | t.CPtr, offset: uint32) -> types.FRESULT:
return fp.seek(offset)
def tell(fp: types.fileobj | t.CPtr) -> uint32:
return fp.tell()
def size(fp: types.fileobj | t.CPtr) -> uint32:
return fp.size()
def truncate(fp: types.fileobj | t.CPtr) -> types.FRESULT:
return fp.truncate()
def remove(path: t.CConst | str) -> types.FRESULT:
return default_fs.file_delete(path)
def rename(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
return default_fs.file_rename(old_path, new_path)
def move(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
return default_fs.file_rename(old_path, new_path)
def stat(path: t.CConst | str, info: types.fileinfo | t.CPtr) -> types.FRESULT:
return default_fs.file_stat(path, info)
def mkdir(path: t.CConst | str) -> types.FRESULT:
return default_fs.dir_make(path)
def rmdir(path: t.CConst | str) -> types.FRESULT:
return default_fs.dir_remove(path)
def opendir(path: t.CConst | str, dp: types.dirobj | t.CPtr) -> types.FRESULT:
return default_fs.dir_open_path(path, dp)
def readdir(dp: types.dirobj | t.CPtr, info: types.fileinfo | t.CPtr) -> types.FRESULT:
return default_fs.dir_read(dp, info)
def closedir(dp: types.dirobj | t.CPtr):
dp.is_open = 0
def chmod(path: t.CConst | str, attr: uint8, mask: uint8) -> types.FRESULT:
return default_fs.chmod(path, attr, mask)
def utime(path: t.CConst | str, mtime: uint16, mdate: uint16) -> types.FRESULT:
return default_fs.utime(path, mtime, mdate)
def get_free() -> uint32:
if not default_fs.mounted: return 0
if default_fs.free_clusters == 0xFFFFFFFF:
return default_fs.count_free_clusters()
return default_fs.free_clusters
def get_total() -> uint32:
if not default_fs.mounted: return 0
return default_fs.total_clusters
def get_cluster_size() -> uint32:
if not default_fs.mounted: return 0
return default_fs.cluster_size
def is_mounted() -> int:
return default_fs.mounted
def last_error() -> uint32:
return default_fs.last_error
def get_fattime() -> uint32:
return ftime.get_fattime()
def get_metadata() -> uint32:
return default_fs.metadata
def set_metadata(val: uint32):
default_fs.metadata = val
def scan_drives() -> types.FRESULT:
return part.scan_drives()
def get_drive_count() -> int:
return part.get_drive_count()
def get_drive_letter(idx: int) -> t.CChar:
return part.get_drive_letter(idx)
def set_drive_letter(idx: int, letter: t.CChar) -> types.FRESULT:
return part.set_drive_letter(idx, letter)
def get_partition_count(letter: t.CChar) -> int:
return part.get_partition_count(letter)
def is_partition_fat32(letter: t.CChar, part_idx: int) -> int:
return part.is_partition_fat32(letter, part_idx)
+16 -16
View File
@@ -1,16 +1,16 @@
from stdint import *
import fat32_types as types
import t, c
_read32 = types._read32
_read16 = types._read16
_write32 = types._write32
_write16 = types._write16
def is_eoc(cluster: t.CUInt32T) -> t.CInt:
return 1 if (cluster >= types.CLUSTER_EOC_MIN and cluster <= types.CLUSTER_EOC_MAX) else 0
def is_free(cluster: t.CUInt32T) -> t.CInt:
return 1 if cluster == types.CLUSTER_FREE else 0
from stdint import *
import fat32_types as types
import t, c
_read32 = types._read32
_read16 = types._read16
_write32 = types._write32
_write16 = types._write16
def is_eoc(cluster: uint32) -> int:
return 1 if (cluster >= types.CLUSTER_EOC_MIN and cluster <= types.CLUSTER_EOC_MAX) else 0
def is_free(cluster: uint32) -> int:
return 1 if cluster == types.CLUSTER_FREE else 0
+81 -81
View File
@@ -1,81 +1,81 @@
import drivers.storage.ide.ide as ide
import fat32_types as types
import spinlock
import string
import t, c
MAX_DRIVES: t.CDefine = 4
drive_initialized: t.CArray[t.CInt, MAX_DRIVES]
drive_lock: spinlock._spinlock = spinlock._spinlock()
def status(pdrv: t.CUInt8T) -> types.DRESULT:
global drive_initialized
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
return types.DRESULT.RES_OK
def init(pdrv: t.CUInt8T) -> types.DRESULT:
global drive_lock, drive_initialized
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
drive_lock.lock()
err: t.CInt = ide.init()
if err != 0:
drive_lock.unlock()
return types.DRESULT.RES_NOTRDY
drive_initialized[pdrv] = 1
drive_lock.unlock()
return types.DRESULT.RES_OK
def read(pdrv: t.CUInt8T, buff: t.CUInt8T | t.CPtr, sector: t.CUInt32T, count: t.CUInt32T) -> types.DRESULT:
global drive_initialized, drive_lock
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
drive_lock.lock()
i: t.CUInt32T
for i in range(count):
rd_res: t.CInt = ide.readSector(sector + i, buff + (i * 512))
if rd_res != 0:
drive_lock.unlock()
return types.DRESULT.RES_ERROR
drive_lock.unlock()
return types.DRESULT.RES_OK
def write(pdrv: t.CUInt8T, buff: t.CConst | t.CUInt8T | t.CPtr, sector: t.CUInt32T, count: t.CUInt32T) -> types.DRESULT:
global drive_initialized, drive_lock
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
drive_lock.lock()
i: t.CUInt32T
for i in range(count):
if ide.writeSector(sector + i, buff + (i * 512)) != 0:
drive_lock.unlock()
return types.DRESULT.RES_ERROR
drive_lock.unlock()
return types.DRESULT.RES_OK
def ioctl(pdrv: t.CUInt8T, cmd: t.CUInt8T, buff: t.CVoid | t.CPtr) -> types.DRESULT:
global drive_initialized
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
match cmd:
case types.GET_SECTOR_COUNT:
disk_size: t.CUInt64T = ide.getDiskSize()
if disk_size == 0:
c.Set(c.Deref(t.CUInt32T(buff, t.CPtr)), 131072)
elif disk_size > 0xFFFFFFFF:
c.Set(c.Deref(t.CUInt32T(buff, t.CPtr)), 0xFFFFFFFF)
else:
c.Set(c.Deref(t.CUInt32T(buff, t.CPtr)), t.CUInt32T(disk_size))
return types.DRESULT.RES_OK
case types.GET_SECTOR_SIZE:
c.Set(c.Deref(t.CUInt16T(buff, t.CPtr)), 512)
return types.DRESULT.RES_OK
case types.GET_BLOCK_SIZE:
c.Set(c.Deref(t.CUInt32T(buff, t.CPtr)), 1)
return types.DRESULT.RES_OK
case types.CTRL_SYNC:
return types.DRESULT.RES_OK
case _:
return types.DRESULT.RES_PARERR
import drivers.storage.ide.ide as ide
import fat32_types as types
import spinlock
import string
import t, c
MAX_DRIVES: t.CDefine = 4
drive_initialized: t.CArray[int, MAX_DRIVES]
drive_lock: spinlock._spinlock = spinlock._spinlock()
def status(pdrv: uint8) -> types.DRESULT:
global drive_initialized
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
return types.DRESULT.RES_OK
def init(pdrv: uint8) -> types.DRESULT:
global drive_lock, drive_initialized
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
drive_lock.lock()
err: int = ide.init()
if err != 0:
drive_lock.unlock()
return types.DRESULT.RES_NOTRDY
drive_initialized[pdrv] = 1
drive_lock.unlock()
return types.DRESULT.RES_OK
def read(pdrv: uint8, buff: uint8 | t.CPtr, sector: uint32, count: uint32) -> types.DRESULT:
global drive_initialized, drive_lock
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
drive_lock.lock()
i: uint32
for i in range(count):
rd_res: int = ide.readSector(sector + i, buff + (i * 512))
if rd_res != 0:
drive_lock.unlock()
return types.DRESULT.RES_ERROR
drive_lock.unlock()
return types.DRESULT.RES_OK
def write(pdrv: uint8, buff: t.CConst | uint8 | t.CPtr, sector: uint32, count: uint32) -> types.DRESULT:
global drive_initialized, drive_lock
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
drive_lock.lock()
i: uint32
for i in range(count):
if ide.writeSector(sector + i, buff + (i * 512)) != 0:
drive_lock.unlock()
return types.DRESULT.RES_ERROR
drive_lock.unlock()
return types.DRESULT.RES_OK
def ioctl(pdrv: uint8, cmd: uint8, buff: t.CPtr) -> types.DRESULT:
global drive_initialized
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
match cmd:
case types.GET_SECTOR_COUNT:
disk_size: uint64 = ide.getDiskSize()
if disk_size == 0:
c.Set(c.Deref(uint32(buff, t.CPtr)), 131072)
elif disk_size > 0xFFFFFFFF:
c.Set(c.Deref(uint32(buff, t.CPtr)), 0xFFFFFFFF)
else:
c.Set(c.Deref(uint32(buff, t.CPtr)), uint32(disk_size))
return types.DRESULT.RES_OK
case types.GET_SECTOR_SIZE:
c.Set(c.Deref(uint16(buff, t.CPtr)), 512)
return types.DRESULT.RES_OK
case types.GET_BLOCK_SIZE:
c.Set(c.Deref(uint32(buff, t.CPtr)), 1)
return types.DRESULT.RES_OK
case types.CTRL_SYNC:
return types.DRESULT.RES_OK
case _:
return types.DRESULT.RES_PARERR
+143 -143
View File
@@ -1,143 +1,143 @@
from stdint import *
import fat32_types as types
import fat32_diskio as diskio
import fat32_time as ftime
import string
import t, c
def _div_round_up(a: t.CUInt64T, b: t.CUInt64T) -> t.CUInt64T:
return (a + b - 1) / b
def _calc_fat_size(total_sectors: t.CUInt64T, reserved: t.CUInt32T, sec_per_clus: t.CUInt8T, num_fats: t.CUInt8T) -> t.CUInt32T:
tmp: t.CUInt64T = total_sectors - t.CUInt64T(reserved)
fat_sz: t.CUInt32T = 1
while True:
data_sectors: t.CUInt64T = tmp - t.CUInt64T(fat_sz) * t.CUInt64T(num_fats)
total_clusters: t.CUInt32T = t.CUInt32T(data_sectors / t.CUInt64T(sec_per_clus))
needed: t.CUInt64T = _div_round_up(t.CUInt64T(total_clusters) * 4, 512)
if needed <= t.CUInt64T(fat_sz): break
fat_sz = t.CUInt32T(needed)
return fat_sz
def _write_boot_sector(pdrv: t.CUInt8T, total_sectors: t.CUInt64T, sec_per_clus: t.CUInt8T, vol_id: t.CUInt32T, fat_sz: t.CUInt32T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
buf[0] = 0xEB; buf[1] = 0x58; buf[2] = 0x90
buf[3] = 'M'; buf[4] = 'S'; buf[5] = 'W'; buf[6] = 'I'; buf[7] = 'N'
buf[8] = '4'; buf[9] = '.'; buf[10] = '1'
types._write16(c.Addr(buf[0]), 11, 512)
buf[13] = sec_per_clus
types._write16(c.Addr(buf[0]), 14, 32)
buf[16] = 2
types._write16(c.Addr(buf[0]), 17, 0)
buf[21] = 0xF8
types._write16(c.Addr(buf[0]), 22, 0)
types._write16(c.Addr(buf[0]), 24, 63)
types._write16(c.Addr(buf[0]), 26, 255)
types._write32(c.Addr(buf[0]), 28, 0)
types._write32(c.Addr(buf[0]), 32, t.CUInt32T(total_sectors))
types._write32(c.Addr(buf[0]), 36, fat_sz)
types._write16(c.Addr(buf[0]), 40, 0)
types._write16(c.Addr(buf[0]), 42, 0)
types._write32(c.Addr(buf[0]), 44, 2)
types._write16(c.Addr(buf[0]), 48, 1)
types._write16(c.Addr(buf[0]), 50, 6)
buf[64] = 0x80
buf[66] = 0x29
types._write32(c.Addr(buf[0]), 67, vol_id)
vol_label: t.CArray[t.CChar, 11]
vol_label[0] = 'N'; vol_label[1] = 'O'; vol_label[2] = ' '; vol_label[3] = ' '
vol_label[4] = ' '; vol_label[5] = ' '; vol_label[6] = ' '; vol_label[7] = ' '
vol_label[8] = ' '; vol_label[9] = ' '; vol_label[10] = ' '
i: t.CInt
for i in range(11): buf[71 + i] = t.CUInt8T(vol_label[i])
buf[82] = 'F'; buf[83] = 'A'; buf[84] = 'T'; buf[85] = '3'
buf[86] = '2'; buf[87] = ' '; buf[88] = ' '; buf[89] = ' '
buf[510] = 0x55; buf[511] = 0xAA
return diskio.write(pdrv, c.Addr(buf[0]), 0, 1)
def _write_fsinfo(pdrv: t.CUInt8T, free_count: t.CUInt32T, next_free: t.CUInt32T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
types._write32(c.Addr(buf[0]), 0, 0x41615252)
types._write32(c.Addr(buf[0]), 484, 0x61417272)
types._write32(c.Addr(buf[0]), 488, free_count)
types._write32(c.Addr(buf[0]), 492, next_free)
types._write32(c.Addr(buf[0]), 508, 0xAA550000)
return diskio.write(pdrv, c.Addr(buf[0]), 1, 1)
def _init_fat(pdrv: t.CUInt8T, fat_start: t.CUInt64T, fat_sz: t.CUInt32T, root_cluster: t.CUInt32T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
types._write32(c.Addr(buf[0]), 0, 0x0FFFFFF8)
types._write32(c.Addr(buf[0]), 4, 0x0FFFFFFF)
types._write32(c.Addr(buf[0]), 8, 0x0FFFFFFF)
if root_cluster >= 2:
cluster_off: t.CUInt32T = root_cluster * 4
sector_off: t.CUInt32T = cluster_off / 512
byte_off: t.CUInt32T = cluster_off % 512
if sector_off == 0:
types._write32(c.Addr(buf[0]), byte_off, 0x0FFFFFFF)
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(fat_start), 1)
if res != types.DRESULT.RES_OK: return res
string.memset(c.Addr(buf[0]), 0, 512)
s: t.CUInt32T
for s in range(1, fat_sz):
res2: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(fat_start) + s, 1)
if res2 != types.DRESULT.RES_OK: return res2
return types.DRESULT.RES_OK
def _init_root_dir(pdrv: t.CUInt8T, root_sector: t.CUInt64T, sec_per_clus: t.CUInt8T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
s: t.CUInt8T
for s in range(sec_per_clus):
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(root_sector + t.CUInt64T(s)), 1)
if res != types.DRESULT.RES_OK: return res
return types.DRESULT.RES_OK
def _calc_sec_per_clus(total_sectors: t.CUInt64T) -> t.CUInt8T:
ts: t.CUInt64T = total_sectors
if ts < 532480: return 1
elif ts < 16777216: return 8
elif ts < 33554432: return 16
elif ts < 67108864: return 32
else: return 64
def mkfs(pdrv: t.CUInt8T, sec_per_clus: t.CUInt8T, vol_id: t.CUInt32T) -> types.FRESULT:
if pdrv != types.DEV_DISK: return types.FRESULT.FR_INVALID_DRIVE
total_sectors_buf: t.CUInt32T = 0
diskio.ioctl(pdrv, types.GET_SECTOR_COUNT, c.Addr(total_sectors_buf))
total_sectors: t.CUInt64T = t.CUInt64T(total_sectors_buf)
if total_sectors < 65536: return types.FRESULT.FR_MKFS_ABORTED
if sec_per_clus == 0: sec_per_clus = _calc_sec_per_clus(total_sectors)
if sec_per_clus != 1 and sec_per_clus != 2 and sec_per_clus != 4 and sec_per_clus != 8 and sec_per_clus != 16 and sec_per_clus != 32 and sec_per_clus != 64 and sec_per_clus != 128:
return types.FRESULT.FR_INVALID_PARAMETER
if vol_id == 0: vol_id = ftime.get_fattime()
reserved: t.CUInt32T = 32
num_fats: t.CUInt8T = 2
fat_sz: t.CUInt32T = _calc_fat_size(total_sectors, reserved, sec_per_clus, num_fats)
data_sectors: t.CUInt64T = total_sectors - t.CUInt64T(reserved) - t.CUInt64T(fat_sz) * t.CUInt64T(num_fats)
total_clusters: t.CUInt32T = t.CUInt32T(data_sectors / t.CUInt64T(sec_per_clus))
free_count: t.CUInt32T = total_clusters - 1
res: types.DRESULT = _write_boot_sector(pdrv, total_sectors, sec_per_clus, vol_id, fat_sz)
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
res2: types.DRESULT = _write_fsinfo(pdrv, free_count, 3)
if res2 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
boot_backup: t.CArray[t.CUInt8T, 512]
diskio.read(pdrv, c.Addr(boot_backup[0]), 0, 1)
diskio.write(pdrv, c.Addr(boot_backup[0]), 6, 1)
fsinfo_backup: t.CArray[t.CUInt8T, 512]
diskio.read(pdrv, c.Addr(fsinfo_backup[0]), 1, 1)
diskio.write(pdrv, c.Addr(fsinfo_backup[0]), 7, 1)
fat_start: t.CUInt64T = t.CUInt64T(reserved)
res3: types.DRESULT = _init_fat(pdrv, fat_start, fat_sz, 2)
if res3 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
fat2_start: t.CUInt64T = fat_start + t.CUInt64T(fat_sz)
res4: types.DRESULT = _init_fat(pdrv, fat2_start, fat_sz, 2)
if res4 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
root_sector: t.CUInt64T = fat2_start + t.CUInt64T(fat_sz)
res5: types.DRESULT = _init_root_dir(pdrv, root_sector, sec_per_clus)
if res5 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
return types.FRESULT.FR_OK
from stdint import *
import fat32_types as types
import fat32_diskio as diskio
import fat32_time as ftime
import string
import t, c
def _div_round_up(a: uint64, b: uint64) -> uint64:
return (a + b - 1) / b
def _calc_fat_size(total_sectors: uint64, reserved: uint32, sec_per_clus: uint8, num_fats: uint8) -> uint32:
tmp: uint64 = total_sectors - uint64(reserved)
fat_sz: uint32 = 1
while True:
data_sectors: uint64 = tmp - uint64(fat_sz) * uint64(num_fats)
total_clusters: uint32 = uint32(data_sectors / uint64(sec_per_clus))
needed: uint64 = _div_round_up(uint64(total_clusters) * 4, 512)
if needed <= uint64(fat_sz): break
fat_sz = uint32(needed)
return fat_sz
def _write_boot_sector(pdrv: uint8, total_sectors: uint64, sec_per_clus: uint8, vol_id: uint32, fat_sz: uint32) -> types.DRESULT:
buf: t.CArray[uint8, 512]
string.memset(c.Addr(buf[0]), 0, 512)
buf[0] = 0xEB; buf[1] = 0x58; buf[2] = 0x90
buf[3] = 'M'; buf[4] = 'S'; buf[5] = 'W'; buf[6] = 'I'; buf[7] = 'N'
buf[8] = '4'; buf[9] = '.'; buf[10] = '1'
types._write16(c.Addr(buf[0]), 11, 512)
buf[13] = sec_per_clus
types._write16(c.Addr(buf[0]), 14, 32)
buf[16] = 2
types._write16(c.Addr(buf[0]), 17, 0)
buf[21] = 0xF8
types._write16(c.Addr(buf[0]), 22, 0)
types._write16(c.Addr(buf[0]), 24, 63)
types._write16(c.Addr(buf[0]), 26, 255)
types._write32(c.Addr(buf[0]), 28, 0)
types._write32(c.Addr(buf[0]), 32, uint32(total_sectors))
types._write32(c.Addr(buf[0]), 36, fat_sz)
types._write16(c.Addr(buf[0]), 40, 0)
types._write16(c.Addr(buf[0]), 42, 0)
types._write32(c.Addr(buf[0]), 44, 2)
types._write16(c.Addr(buf[0]), 48, 1)
types._write16(c.Addr(buf[0]), 50, 6)
buf[64] = 0x80
buf[66] = 0x29
types._write32(c.Addr(buf[0]), 67, vol_id)
vol_label: t.CArray[t.CChar, 11]
vol_label[0] = 'N'; vol_label[1] = 'O'; vol_label[2] = ' '; vol_label[3] = ' '
vol_label[4] = ' '; vol_label[5] = ' '; vol_label[6] = ' '; vol_label[7] = ' '
vol_label[8] = ' '; vol_label[9] = ' '; vol_label[10] = ' '
i: int
for i in range(11): buf[71 + i] = uint8(vol_label[i])
buf[82] = 'F'; buf[83] = 'A'; buf[84] = 'T'; buf[85] = '3'
buf[86] = '2'; buf[87] = ' '; buf[88] = ' '; buf[89] = ' '
buf[510] = 0x55; buf[511] = 0xAA
return diskio.write(pdrv, c.Addr(buf[0]), 0, 1)
def _write_fsinfo(pdrv: uint8, free_count: uint32, next_free: uint32) -> types.DRESULT:
buf: t.CArray[uint8, 512]
string.memset(c.Addr(buf[0]), 0, 512)
types._write32(c.Addr(buf[0]), 0, 0x41615252)
types._write32(c.Addr(buf[0]), 484, 0x61417272)
types._write32(c.Addr(buf[0]), 488, free_count)
types._write32(c.Addr(buf[0]), 492, next_free)
types._write32(c.Addr(buf[0]), 508, 0xAA550000)
return diskio.write(pdrv, c.Addr(buf[0]), 1, 1)
def _init_fat(pdrv: uint8, fat_start: uint64, fat_sz: uint32, root_cluster: uint32) -> types.DRESULT:
buf: t.CArray[uint8, 512]
string.memset(c.Addr(buf[0]), 0, 512)
types._write32(c.Addr(buf[0]), 0, 0x0FFFFFF8)
types._write32(c.Addr(buf[0]), 4, 0x0FFFFFFF)
types._write32(c.Addr(buf[0]), 8, 0x0FFFFFFF)
if root_cluster >= 2:
cluster_off: uint32 = root_cluster * 4
sector_off: uint32 = cluster_off / 512
byte_off: uint32 = cluster_off % 512
if sector_off == 0:
types._write32(c.Addr(buf[0]), byte_off, 0x0FFFFFFF)
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), uint32(fat_start), 1)
if res != types.DRESULT.RES_OK: return res
string.memset(c.Addr(buf[0]), 0, 512)
s: uint32
for s in range(1, fat_sz):
res2: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), uint32(fat_start) + s, 1)
if res2 != types.DRESULT.RES_OK: return res2
return types.DRESULT.RES_OK
def _init_root_dir(pdrv: uint8, root_sector: uint64, sec_per_clus: uint8) -> types.DRESULT:
buf: t.CArray[uint8, 512]
string.memset(c.Addr(buf[0]), 0, 512)
s: uint8
for s in range(sec_per_clus):
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), uint32(root_sector + uint64(s)), 1)
if res != types.DRESULT.RES_OK: return res
return types.DRESULT.RES_OK
def _calc_sec_per_clus(total_sectors: uint64) -> uint8:
ts: uint64 = total_sectors
if ts < 532480: return 1
elif ts < 16777216: return 8
elif ts < 33554432: return 16
elif ts < 67108864: return 32
else: return 64
def mkfs(pdrv: uint8, sec_per_clus: uint8, vol_id: uint32) -> types.FRESULT:
if pdrv != types.DEV_DISK: return types.FRESULT.FR_INVALID_DRIVE
total_sectors_buf: uint32 = 0
diskio.ioctl(pdrv, types.GET_SECTOR_COUNT, c.Addr(total_sectors_buf))
total_sectors: uint64 = uint64(total_sectors_buf)
if total_sectors < 65536: return types.FRESULT.FR_MKFS_ABORTED
if sec_per_clus == 0: sec_per_clus = _calc_sec_per_clus(total_sectors)
if sec_per_clus != 1 and sec_per_clus != 2 and sec_per_clus != 4 and sec_per_clus != 8 and sec_per_clus != 16 and sec_per_clus != 32 and sec_per_clus != 64 and sec_per_clus != 128:
return types.FRESULT.FR_INVALID_PARAMETER
if vol_id == 0: vol_id = ftime.get_fattime()
reserved: uint32 = 32
num_fats: uint8 = 2
fat_sz: uint32 = _calc_fat_size(total_sectors, reserved, sec_per_clus, num_fats)
data_sectors: uint64 = total_sectors - uint64(reserved) - uint64(fat_sz) * uint64(num_fats)
total_clusters: uint32 = uint32(data_sectors / uint64(sec_per_clus))
free_count: uint32 = total_clusters - 1
res: types.DRESULT = _write_boot_sector(pdrv, total_sectors, sec_per_clus, vol_id, fat_sz)
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
res2: types.DRESULT = _write_fsinfo(pdrv, free_count, 3)
if res2 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
boot_backup: t.CArray[uint8, 512]
diskio.read(pdrv, c.Addr(boot_backup[0]), 0, 1)
diskio.write(pdrv, c.Addr(boot_backup[0]), 6, 1)
fsinfo_backup: t.CArray[uint8, 512]
diskio.read(pdrv, c.Addr(fsinfo_backup[0]), 1, 1)
diskio.write(pdrv, c.Addr(fsinfo_backup[0]), 7, 1)
fat_start: uint64 = uint64(reserved)
res3: types.DRESULT = _init_fat(pdrv, fat_start, fat_sz, 2)
if res3 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
fat2_start: uint64 = fat_start + uint64(fat_sz)
res4: types.DRESULT = _init_fat(pdrv, fat2_start, fat_sz, 2)
if res4 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
root_sector: uint64 = fat2_start + uint64(fat_sz)
res5: types.DRESULT = _init_root_dir(pdrv, root_sector, sec_per_clus)
if res5 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
return types.FRESULT.FR_OK
+153 -153
View File
@@ -1,153 +1,153 @@
from stdint import *
import fat32_types as types
import fat32_diskio as diskio
import string
import t, c
MAX_VOLUMES: t.CDefine = 4
MAX_PARTITIONS: t.CDefine = 4
MBR_SIGNATURE: t.CDefine = 0xAA55
PART_TYPE_FAT32: t.CDefine = 0x0C
PART_TYPE_FAT32_LBA: t.CDefine = 0x0B
PART_TYPE_FAT16: t.CDefine = 0x06
PART_TYPE_FAT16_LBA: t.CDefine = 0x0E
class partition_entry:
boot_flag: t.CUInt8T
start_chs: t.CArray[t.CUInt8T, 3]
part_type: t.CUInt8T
end_chs: t.CArray[t.CUInt8T, 3]
start_lba: t.CUInt32T
total_sectors: t.CUInt32T
drive_pdrv: t.CArray[t.CUInt8T, MAX_VOLUMES]
drive_num_parts: t.CArray[t.CInt, MAX_VOLUMES]
drive_letter_map: t.CArray[t.CChar, MAX_VOLUMES]
volume_mounted: t.CArray[t.CInt, MAX_VOLUMES]
part_types: t.CArray[t.CUInt8T, MAX_VOLUMES * MAX_PARTITIONS]
part_start_lbas: t.CArray[t.CUInt64T, MAX_VOLUMES * MAX_PARTITIONS]
part_totals: t.CArray[t.CUInt64T, MAX_VOLUMES * MAX_PARTITIONS]
part_is_fat32: t.CArray[t.CInt, MAX_VOLUMES * MAX_PARTITIONS]
num_drives: t.CInt = 0
def _init():
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
global part_types, part_start_lbas, part_totals, part_is_fat32
if num_drives > 0: return
i: t.CInt
for i in range(MAX_VOLUMES):
drive_letter_map[i] = 0
volume_mounted[i] = 0
drive_pdrv[i] = 0
drive_num_parts[i] = 0
j: t.CInt
for j in range(MAX_VOLUMES * MAX_PARTITIONS):
part_types[j] = 0
part_start_lbas[j] = 0
part_totals[j] = 0
part_is_fat32[j] = 0
def _part_idx(drive: t.CInt, part: t.CInt) -> t.CInt:
return drive * MAX_PARTITIONS + part
def parse_mbr(pdrv: t.CUInt8T, drive_idx: t.CInt) -> types.FRESULT:
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
global part_types, part_start_lbas, part_totals, part_is_fat32
buf: t.CArray[t.CUInt8T, 512]
res: types.DRESULT = diskio.read(pdrv, c.Addr(buf[0]), 0, 1)
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
if buf[0] == 0xEB or buf[0] == 0xE9:
return types.FRESULT.FR_NO_FILESYSTEM
sig: t.CUInt16T = t.CUInt16T(buf[510]) | (t.CUInt16T(buf[511]) << 8)
if sig != MBR_SIGNATURE: return types.FRESULT.FR_NO_FILESYSTEM
drive_pdrv[drive_idx] = pdrv
drive_num_parts[drive_idx] = 0
i: t.CInt
for i in range(4):
base: t.CUInt32T = 446 + t.CUInt32T(i * 16)
ptype: t.CUInt8T = buf[base + 4]
slba: t.CUInt32T = t.CUInt32T(buf[base + 8]) | (t.CUInt32T(buf[base + 9]) << 8) | (t.CUInt32T(buf[base + 10]) << 16) | (t.CUInt32T(buf[base + 11]) << 24)
tsec: t.CUInt32T = t.CUInt32T(buf[base + 12]) | (t.CUInt32T(buf[base + 13]) << 8) | (t.CUInt32T(buf[base + 14]) << 16) | (t.CUInt32T(buf[base + 15]) << 24)
if ptype != 0 and tsec > 0:
pi: t.CInt = drive_num_parts[drive_idx]
if pi < MAX_PARTITIONS:
pidx: t.CInt = _part_idx(drive_idx, pi)
part_types[pidx] = ptype
part_start_lbas[pidx] = t.CUInt64T(slba)
part_totals[pidx] = t.CUInt64T(tsec)
part_is_fat32[pidx] = 1 if (ptype == PART_TYPE_FAT32 or ptype == PART_TYPE_FAT32_LBA) else 0
drive_num_parts[drive_idx] = pi + 1
return types.FRESULT.FR_OK
def scan_drives() -> types.FRESULT:
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
global part_types, part_start_lbas, part_totals, part_is_fat32
_init()
global num_drives
num_drives = 0
pdrv: t.CUInt8T
for pdrv in range(MAX_VOLUMES):
res: types.DRESULT = diskio.init(pdrv)
if res != types.DRESULT.RES_OK: continue
res2: types.FRESULT = parse_mbr(pdrv, num_drives)
if res2 == types.FRESULT.FR_OK and drive_num_parts[num_drives] > 0:
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
else:
drive_pdrv[num_drives] = pdrv
drive_num_parts[num_drives] = 1
pidx: t.CInt = _part_idx(num_drives, 0)
part_types[pidx] = PART_TYPE_FAT32_LBA
part_start_lbas[pidx] = 0
part_totals[pidx] = 0
part_is_fat32[pidx] = 1
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
num_drives = num_drives + 1
if num_drives >= MAX_VOLUMES: break
return types.FRESULT.FR_OK
def get_drive(letter: t.CChar) -> t.CInt:
_init()
i: t.CInt
for i in range(num_drives):
if drive_letter_map[i] == letter or drive_letter_map[i] == (letter - 32) or drive_letter_map[i] == (letter + 32):
return i
return -1
def get_pdrv(letter: t.CChar) -> t.CUInt8T:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
return drive_pdrv[idx]
def get_partition_start(letter: t.CChar, part_idx: t.CInt) -> t.CUInt64T:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
if part_idx >= drive_num_parts[idx]: return 0
pidx: t.CInt = _part_idx(idx, part_idx)
return part_start_lbas[pidx]
def get_partition_count(letter: t.CChar) -> t.CInt:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
return drive_num_parts[idx]
def is_partition_fat32(letter: t.CChar, part_idx: t.CInt) -> t.CInt:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
if part_idx >= drive_num_parts[idx]: return 0
pidx: t.CInt = _part_idx(idx, part_idx)
return part_is_fat32[pidx]
def get_drive_count() -> t.CInt:
return num_drives
def get_drive_letter(idx: t.CInt) -> t.CChar:
if idx < 0 or idx >= num_drives: return 0
return drive_letter_map[idx]
def set_drive_letter(idx: t.CInt, letter: t.CChar) -> types.FRESULT:
if idx < 0 or idx >= num_drives: return types.FRESULT.FR_INVALID_PARAMETER
drive_letter_map[idx] = letter
return types.FRESULT.FR_OK
from stdint import *
import fat32_types as types
import fat32_diskio as diskio
import string
import t, c
MAX_VOLUMES: t.CDefine = 4
MAX_PARTITIONS: t.CDefine = 4
MBR_SIGNATURE: t.CDefine = 0xAA55
PART_TYPE_FAT32: t.CDefine = 0x0C
PART_TYPE_FAT32_LBA: t.CDefine = 0x0B
PART_TYPE_FAT16: t.CDefine = 0x06
PART_TYPE_FAT16_LBA: t.CDefine = 0x0E
class partition_entry:
boot_flag: uint8
start_chs: t.CArray[uint8, 3]
part_type: uint8
end_chs: t.CArray[uint8, 3]
start_lba: uint32
total_sectors: uint32
drive_pdrv: t.CArray[uint8, MAX_VOLUMES]
drive_num_parts: t.CArray[int, MAX_VOLUMES]
drive_letter_map: t.CArray[t.CChar, MAX_VOLUMES]
volume_mounted: t.CArray[int, MAX_VOLUMES]
part_types: t.CArray[uint8, MAX_VOLUMES * MAX_PARTITIONS]
part_start_lbas: t.CArray[uint64, MAX_VOLUMES * MAX_PARTITIONS]
part_totals: t.CArray[uint64, MAX_VOLUMES * MAX_PARTITIONS]
part_is_fat32: t.CArray[int, MAX_VOLUMES * MAX_PARTITIONS]
num_drives: int = 0
def _init():
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
global part_types, part_start_lbas, part_totals, part_is_fat32
if num_drives > 0: return
i: int
for i in range(MAX_VOLUMES):
drive_letter_map[i] = 0
volume_mounted[i] = 0
drive_pdrv[i] = 0
drive_num_parts[i] = 0
j: int
for j in range(MAX_VOLUMES * MAX_PARTITIONS):
part_types[j] = 0
part_start_lbas[j] = 0
part_totals[j] = 0
part_is_fat32[j] = 0
def _part_idx(drive: int, part: int) -> int:
return drive * MAX_PARTITIONS + part
def parse_mbr(pdrv: uint8, drive_idx: int) -> types.FRESULT:
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
global part_types, part_start_lbas, part_totals, part_is_fat32
buf: t.CArray[uint8, 512]
res: types.DRESULT = diskio.read(pdrv, c.Addr(buf[0]), 0, 1)
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
if buf[0] == 0xEB or buf[0] == 0xE9:
return types.FRESULT.FR_NO_FILESYSTEM
sig: uint16 = uint16(buf[510]) | (uint16(buf[511]) << 8)
if sig != MBR_SIGNATURE: return types.FRESULT.FR_NO_FILESYSTEM
drive_pdrv[drive_idx] = pdrv
drive_num_parts[drive_idx] = 0
i: int
for i in range(4):
base: uint32 = 446 + uint32(i * 16)
ptype: uint8 = buf[base + 4]
slba: uint32 = uint32(buf[base + 8]) | (uint32(buf[base + 9]) << 8) | (uint32(buf[base + 10]) << 16) | (uint32(buf[base + 11]) << 24)
tsec: uint32 = uint32(buf[base + 12]) | (uint32(buf[base + 13]) << 8) | (uint32(buf[base + 14]) << 16) | (uint32(buf[base + 15]) << 24)
if ptype != 0 and tsec > 0:
pi: int = drive_num_parts[drive_idx]
if pi < MAX_PARTITIONS:
pidx: int = _part_idx(drive_idx, pi)
part_types[pidx] = ptype
part_start_lbas[pidx] = uint64(slba)
part_totals[pidx] = uint64(tsec)
part_is_fat32[pidx] = 1 if (ptype == PART_TYPE_FAT32 or ptype == PART_TYPE_FAT32_LBA) else 0
drive_num_parts[drive_idx] = pi + 1
return types.FRESULT.FR_OK
def scan_drives() -> types.FRESULT:
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
global part_types, part_start_lbas, part_totals, part_is_fat32
_init()
global num_drives
num_drives = 0
pdrv: uint8
for pdrv in range(MAX_VOLUMES):
res: types.DRESULT = diskio.init(pdrv)
if res != types.DRESULT.RES_OK: continue
res2: types.FRESULT = parse_mbr(pdrv, num_drives)
if res2 == types.FRESULT.FR_OK and drive_num_parts[num_drives] > 0:
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
else:
drive_pdrv[num_drives] = pdrv
drive_num_parts[num_drives] = 1
pidx: int = _part_idx(num_drives, 0)
part_types[pidx] = PART_TYPE_FAT32_LBA
part_start_lbas[pidx] = 0
part_totals[pidx] = 0
part_is_fat32[pidx] = 1
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
num_drives = num_drives + 1
if num_drives >= MAX_VOLUMES: break
return types.FRESULT.FR_OK
def get_drive(letter: t.CChar) -> int:
_init()
i: int
for i in range(num_drives):
if drive_letter_map[i] == letter or drive_letter_map[i] == (letter - 32) or drive_letter_map[i] == (letter + 32):
return i
return -1
def get_pdrv(letter: t.CChar) -> uint8:
idx: int = get_drive(letter)
if idx < 0: return 0
return drive_pdrv[idx]
def get_partition_start(letter: t.CChar, part_idx: int) -> uint64:
idx: int = get_drive(letter)
if idx < 0: return 0
if part_idx >= drive_num_parts[idx]: return 0
pidx: int = _part_idx(idx, part_idx)
return part_start_lbas[pidx]
def get_partition_count(letter: t.CChar) -> int:
idx: int = get_drive(letter)
if idx < 0: return 0
return drive_num_parts[idx]
def is_partition_fat32(letter: t.CChar, part_idx: int) -> int:
idx: int = get_drive(letter)
if idx < 0: return 0
if part_idx >= drive_num_parts[idx]: return 0
pidx: int = _part_idx(idx, part_idx)
return part_is_fat32[pidx]
def get_drive_count() -> int:
return num_drives
def get_drive_letter(idx: int) -> t.CChar:
if idx < 0 or idx >= num_drives: return 0
return drive_letter_map[idx]
def set_drive_letter(idx: int, letter: t.CChar) -> types.FRESULT:
if idx < 0 or idx >= num_drives: return types.FRESULT.FR_INVALID_PARAMETER
drive_letter_map[idx] = letter
return types.FRESULT.FR_OK
+64 -64
View File
@@ -1,64 +1,64 @@
from stdint import *
import t, c
import asm
rtc_cmos_addr: t.CUInt16T = 0x70
rtc_cmos_data: t.CUInt16T = 0x71
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
asm.outb(rtc_cmos_addr, reg)
return asm.inb(rtc_cmos_data)
def bcd_to_bin(bcd: t.CUInt8T) -> t.CUInt8T:
return (bcd >> 4) * 10 + (bcd & 0x0F)
def get_rtc_time() -> t.CUInt32T:
while cmos_read(0x0A) & 0x80: pass
sec: t.CUInt8T = cmos_read(0x00)
min_: t.CUInt8T = cmos_read(0x02)
hour: t.CUInt8T = cmos_read(0x04)
day: t.CUInt8T = cmos_read(0x07)
mon: t.CUInt8T = cmos_read(0x08)
year: t.CUInt8T = cmos_read(0x09)
reg_b: t.CUInt8T = cmos_read(0x0B)
if not (reg_b & 0x04):
sec = bcd_to_bin(sec)
min_ = bcd_to_bin(min_)
hour = bcd_to_bin(hour)
day = bcd_to_bin(day)
mon = bcd_to_bin(mon)
year = bcd_to_bin(year)
fat_year: t.CUInt16T = t.CUInt16T(year) + 2000 - 1980
if fat_year > 127: fat_year = 127
fat_date: t.CUInt16T = (fat_year << 9) | (t.CUInt16T(mon) << 5) | t.CUInt16T(day)
fat_time: t.CUInt16T = (t.CUInt16T(hour) << 11) | (t.CUInt16T(min_) << 5) | (t.CUInt16T(sec) / 2)
return (t.CUInt32T(fat_date) << 16) | t.CUInt32T(fat_time)
def get_fattime() -> t.CUInt32T:
return get_rtc_time()
def to_year(ft: t.CUInt32T) -> t.CUInt16T:
return t.CUInt16T((ft >> 25) & 0x7F) + 1980
def to_month(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 21) & 0x0F)
def to_day(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 16) & 0x1F)
def to_hour(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 11) & 0x1F)
def to_minute(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 5) & 0x3F)
def to_second(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft & 0x1F) * 2)
def make(year: t.CUInt16T, month: t.CUInt8T, day: t.CUInt8T, hour: t.CUInt8T, minute: t.CUInt8T, second: t.CUInt8T) -> t.CUInt32T:
fat_year: t.CUInt16T = year - 1980
if fat_year > 127: fat_year = 127
fat_date: t.CUInt16T = (fat_year << 9) | (t.CUInt16T(month) << 5) | t.CUInt16T(day)
fat_time: t.CUInt16T = (t.CUInt16T(hour) << 11) | (t.CUInt16T(minute) << 5) | (t.CUInt16T(second) / 2)
return (t.CUInt32T(fat_date) << 16) | t.CUInt32T(fat_time)
from stdint import *
import t, c
import asm
rtc_cmos_addr: uint16 = 0x70
rtc_cmos_data: uint16 = 0x71
def cmos_read(reg: uint8) -> uint8:
asm.outb(rtc_cmos_addr, reg)
return asm.inb(rtc_cmos_data)
def bcd_to_bin(bcd: uint8) -> uint8:
return (bcd >> 4) * 10 + (bcd & 0x0F)
def get_rtc_time() -> uint32:
while cmos_read(0x0A) & 0x80: pass
sec: uint8 = cmos_read(0x00)
min_: uint8 = cmos_read(0x02)
hour: uint8 = cmos_read(0x04)
day: uint8 = cmos_read(0x07)
mon: uint8 = cmos_read(0x08)
year: uint8 = cmos_read(0x09)
reg_b: uint8 = cmos_read(0x0B)
if not (reg_b & 0x04):
sec = bcd_to_bin(sec)
min_ = bcd_to_bin(min_)
hour = bcd_to_bin(hour)
day = bcd_to_bin(day)
mon = bcd_to_bin(mon)
year = bcd_to_bin(year)
fat_year: uint16 = uint16(year) + 2000 - 1980
if fat_year > 127: fat_year = 127
fat_date: uint16 = (fat_year << 9) | (uint16(mon) << 5) | uint16(day)
fat_time: uint16 = (uint16(hour) << 11) | (uint16(min_) << 5) | (uint16(sec) / 2)
return (uint32(fat_date) << 16) | uint32(fat_time)
def get_fattime() -> uint32:
return get_rtc_time()
def to_year(ft: uint32) -> uint16:
return uint16((ft >> 25) & 0x7F) + 1980
def to_month(ft: uint32) -> uint8:
return uint8((ft >> 21) & 0x0F)
def to_day(ft: uint32) -> uint8:
return uint8((ft >> 16) & 0x1F)
def to_hour(ft: uint32) -> uint8:
return uint8((ft >> 11) & 0x1F)
def to_minute(ft: uint32) -> uint8:
return uint8((ft >> 5) & 0x3F)
def to_second(ft: uint32) -> uint8:
return uint8((ft & 0x1F) * 2)
def make(year: uint16, month: uint8, day: uint8, hour: uint8, minute: uint8, second: uint8) -> uint32:
fat_year: uint16 = year - 1980
if fat_year > 127: fat_year = 127
fat_date: uint16 = (fat_year << 9) | (uint16(month) << 5) | uint16(day)
fat_time: uint16 = (uint16(hour) << 11) | (uint16(minute) << 5) | (uint16(second) / 2)
return (uint32(fat_date) << 16) | uint32(fat_time)
File diff suppressed because it is too large. Load diff
+148 -148
View File
@@ -1,148 +1,148 @@
import asm
import intr.idt as idt
import drivers.serial.uart.serial as serial
import viperstring as string
import t, c
KBD_DATA: t.CDefine = 0x60
KBD_STATUS: t.CDefine = 0x64
KBD_COMMAND: t.CDefine = 0x64
KBD_BUF_SIZE: t.CDefine = 1024
KEY_RELEASED: t.CDefine = 0x80
buffer: t.CArray[t.CUInt8T, KBD_BUF_SIZE]
buf_head: t.CStatic | t.CUInt32T = 0
buf_tail: t.CStatic | t.CUInt32T = 0
buf_count: t.CStatic | t.CUInt32T = 0
kbd_irq_cnt: t.CStatic | t.CUInt64T = 0
shift_l: t.CStatic | t.CUInt8T = 0
shift_r: t.CStatic | t.CUInt8T = 0
ctrl_l: t.CStatic | t.CUInt8T = 0
alt_l: t.CStatic | t.CUInt8T = 0
caps_lock: t.CStatic | t.CUInt8T = 0
scancode_set1: t.CArray[t.CChar, 128] = [
'\0', '\x1b', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
'\0', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '`', '\0',
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0', ' ',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0'
]
scancode_set1_shift: t.CArray[t.CChar, 128] = [
'\0', '\x1b', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
'\0', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', '\0',
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '\0', '\0', '\0', ' ',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0'
]
def _wait_read():
timeout: t.CUInt32T = 100000
while timeout > 0:
if (asm.inb(KBD_STATUS) & 0x01) != 0: return
timeout -= 1
def _wait_write():
timeout: t.CUInt32T = 100000
while timeout > 0:
if (asm.inb(KBD_STATUS) & 0x02) == 0: return
timeout -= 1
def irq_handler() -> t.CInt:
global buf_head, buf_tail, buf_count, kbd_irq_cnt
kbd_irq_cnt += 1
scancode: t.CUInt8T = asm.inb(KBD_DATA)
if buf_count < KBD_BUF_SIZE:
buffer[buf_tail] = scancode
buf_tail = buf_tail + 1
if buf_tail >= KBD_BUF_SIZE:
buf_tail = 0
buf_count += 1
return 0
def read_scancode() -> t.CUInt8T:
global buf_head, buf_count
asm.cli()
if buf_count == 0:
asm.sti()
return 0
code: t.CUInt8T = buffer[buf_head]
buf_head = buf_head + 1
if buf_head >= KBD_BUF_SIZE:
buf_head = 0
buf_count -= 1
asm.sti()
return code
def scancode_to_ascii(scancode: t.CUInt8T) -> t.CChar:
code: t.CUInt8T = scancode & ~t.CUInt8T(KEY_RELEASED)
if code >= 128: return '\0'
shifted: bool = (shift_l or shift_r) != 0
if caps_lock and code >= 0x10 and code <= 0x32:
shifted = not shifted
if shifted:
return scancode_set1_shift[code]
return scancode_set1[code]
def has_data() -> t.CInt:
return buf_count
def init():
drain: t.CUInt32T
drain = 0
while (asm.inb(KBD_STATUS) & 0x01) != 0:
asm.inb(KBD_DATA)
drain += 1
if drain > 1000: break
_wait_write()
asm.outb(KBD_COMMAND, 0xAD)
drain = 0
while (asm.inb(KBD_STATUS) & 0x01) != 0:
asm.inb(KBD_DATA)
drain += 1
if drain > 1000: break
_wait_write()
asm.outb(KBD_COMMAND, 0x20)
_wait_read()
ccb: t.CUInt8T = asm.inb(KBD_DATA)
ccb = ccb | 0x01
ccb = ccb | 0x40
ccb = ccb & 0xEF
_wait_write()
asm.outb(KBD_COMMAND, 0x60)
_wait_write()
asm.outb(KBD_DATA, ccb)
_wait_write()
asm.outb(KBD_COMMAND, 0xAE)
drain = 0
while (asm.inb(KBD_STATUS) & 0x01) != 0:
asm.inb(KBD_DATA)
drain += 1
if drain > 1000: break
_wait_write()
asm.outb(KBD_DATA, 0xF4)
_wait_read()
asm.inb(KBD_DATA)
idt.irqInstallHandler(1, irq_handler, "keyboard")
import asm
import intr.idt as idt
import drivers.serial.uart.serial as serial
import viperstring as string
import t, c
KBD_DATA: t.CDefine = 0x60
KBD_STATUS: t.CDefine = 0x64
KBD_COMMAND: t.CDefine = 0x64
KBD_BUF_SIZE: t.CDefine = 1024
KEY_RELEASED: t.CDefine = 0x80
buffer: t.CArray[uint8, KBD_BUF_SIZE]
buf_head: t.CStatic | uint32 = 0
buf_tail: t.CStatic | uint32 = 0
buf_count: t.CStatic | uint32 = 0
kbd_irq_cnt: t.CStatic | uint64 = 0
shift_l: t.CStatic | uint8 = 0
shift_r: t.CStatic | uint8 = 0
ctrl_l: t.CStatic | uint8 = 0
alt_l: t.CStatic | uint8 = 0
caps_lock: t.CStatic | uint8 = 0
scancode_set1: t.CArray[t.CChar, 128] = [
'\0', '\x1b', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
'\0', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '`', '\0',
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0', ' ',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0'
]
scancode_set1_shift: t.CArray[t.CChar, 128] = [
'\0', '\x1b', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
'\0', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', '\0',
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '\0', '\0', '\0', ' ',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0'
]
def _wait_read():
timeout: uint32 = 100000
while timeout > 0:
if (asm.inb(KBD_STATUS) & 0x01) != 0: return
timeout -= 1
def _wait_write():
timeout: uint32 = 100000
while timeout > 0:
if (asm.inb(KBD_STATUS) & 0x02) == 0: return
timeout -= 1
def irq_handler() -> int:
global buf_head, buf_tail, buf_count, kbd_irq_cnt
kbd_irq_cnt += 1
scancode: uint8 = asm.inb(KBD_DATA)
if buf_count < KBD_BUF_SIZE:
buffer[buf_tail] = scancode
buf_tail = buf_tail + 1
if buf_tail >= KBD_BUF_SIZE:
buf_tail = 0
buf_count += 1
return 0
def read_scancode() -> uint8:
global buf_head, buf_count
asm.cli()
if buf_count == 0:
asm.sti()
return 0
code: uint8 = buffer[buf_head]
buf_head = buf_head + 1
if buf_head >= KBD_BUF_SIZE:
buf_head = 0
buf_count -= 1
asm.sti()
return code
def scancode_to_ascii(scancode: uint8) -> t.CChar:
code: uint8 = scancode & ~uint8(KEY_RELEASED)
if code >= 128: return '\0'
shifted: bool = (shift_l or shift_r) != 0
if caps_lock and code >= 0x10 and code <= 0x32:
shifted = not shifted
if shifted:
return scancode_set1_shift[code]
return scancode_set1[code]
def has_data() -> int:
return buf_count
def init():
drain: uint32
drain = 0
while (asm.inb(KBD_STATUS) & 0x01) != 0:
asm.inb(KBD_DATA)
drain += 1
if drain > 1000: break
_wait_write()
asm.outb(KBD_COMMAND, 0xAD)
drain = 0
while (asm.inb(KBD_STATUS) & 0x01) != 0:
asm.inb(KBD_DATA)
drain += 1
if drain > 1000: break
_wait_write()
asm.outb(KBD_COMMAND, 0x20)
_wait_read()
ccb: uint8 = asm.inb(KBD_DATA)
ccb = ccb | 0x01
ccb = ccb | 0x40
ccb = ccb & 0xEF
_wait_write()
asm.outb(KBD_COMMAND, 0x60)
_wait_write()
asm.outb(KBD_DATA, ccb)
_wait_write()
asm.outb(KBD_COMMAND, 0xAE)
drain = 0
while (asm.inb(KBD_STATUS) & 0x01) != 0:
asm.inb(KBD_DATA)
drain += 1
if drain > 1000: break
_wait_write()
asm.outb(KBD_DATA, 0xF4)
_wait_read()
asm.inb(KBD_DATA)
idt.irqInstallHandler(1, irq_handler, "keyboard")
+136 -136
View File
@@ -1,136 +1,136 @@
import asm
import intr.idt as idt
import platform.pch.pic as pic
import drivers.serial.uart.serial as serial
import t, c
MOUSE_DATA: t.CDefine = 0x60
MOUSE_STATUS: t.CDefine = 0x64
MOUSE_COMMAND: t.CDefine = 0x64
MOUSE_BUF_SIZE: t.CDefine = 1024
MOUSE_LEFT: t.CDefine = 0x01
MOUSE_RIGHT: t.CDefine = 0x02
MOUSE_MIDDLE: t.CDefine = 0x04
class mouse_packet:
flags: t.CUInt8T
dx: t.CInt8T
dy: t.CInt8T
buttons: t.CUInt8T
packets: t.CArray[mouse_packet, MOUSE_BUF_SIZE]
pack_head: t.CStatic | t.CUInt32T = 0
pack_tail: t.CStatic | t.CUInt32T = 0
pack_count: t.CStatic | t.CUInt32T = 0
mse_irq_cnt: t.CStatic | t.CUInt64T = 0
cycle: t.CStatic | t.CUInt8T = 0
byte1: t.CStatic | t.CUInt8T = 0
byte2: t.CStatic | t.CInt8T = 0
byte3: t.CStatic | t.CInt8T = 0
mouse_x: t.CStatic | t.CInt32T = 0
mouse_y: t.CStatic | t.CInt32T = 0
mouse_buttons: t.CStatic | t.CUInt8T = 0
def _wait_read():
timeout: t.CUInt32T = 100000
while timeout > 0:
if (asm.inb(MOUSE_STATUS) & 0x01) != 0: return
timeout -= 1
def _wait_write():
timeout: t.CUInt32T = 100000
while timeout > 0:
if (asm.inb(MOUSE_STATUS) & 0x02) == 0: return
timeout -= 1
def _write_cmd(cmd: t.CUInt8T):
_wait_write()
asm.outb(MOUSE_COMMAND, 0xD4)
_wait_write()
asm.outb(MOUSE_DATA, cmd)
_wait_read()
asm.inb(MOUSE_DATA)
def irq_handler() -> t.CInt:
global cycle, byte1, byte2, byte3, pack_tail, pack_count, mse_irq_cnt
mse_irq_cnt += 1
status: t.CUInt8T = asm.inb(MOUSE_STATUS)
if (status & 0x20) == 0: return 0
data: t.CUInt8T = asm.inb(MOUSE_DATA)
if cycle == 0:
if (data & 0x08) != 0:
byte1 = data
cycle = 1
return 0
if cycle == 1:
byte2 = data
cycle = 2
return 0
byte3 = data
cycle = 0
if pack_count < MOUSE_BUF_SIZE:
packets[pack_tail].flags = byte1
packets[pack_tail].dx = byte2
packets[pack_tail].dy = byte3
packets[pack_tail].buttons = byte1 & t.CUInt8T(0x07)
pack_tail = pack_tail + 1
if pack_tail >= MOUSE_BUF_SIZE:
pack_tail = 0
pack_count += 1
return 0
def read_packet(out: mouse_packet | t.CPtr) -> t.CInt:
global pack_head, pack_count
asm.cli()
if pack_count == 0:
asm.sti()
out.flags = 0
out.dx = 0
out.dy = 0
out.buttons = 0
return -1
out.flags = packets[pack_head].flags
out.dx = packets[pack_head].dx
out.dy = packets[pack_head].dy
out.buttons = packets[pack_head].buttons
pack_head = pack_head + 1
if pack_head >= MOUSE_BUF_SIZE:
pack_head = 0
pack_count -= 1
asm.sti()
return 0
def has_data() -> t.CInt:
return pack_count
def get_x() -> t.CInt32T:
return mouse_x
def get_y() -> t.CInt32T:
return mouse_y
def get_buttons() -> t.CUInt8T:
return mouse_buttons
def init():
_wait_write()
asm.outb(MOUSE_COMMAND, 0xA8)
_wait_write()
asm.outb(MOUSE_COMMAND, 0x20)
_wait_read()
status: t.CUInt8T = asm.inb(MOUSE_DATA)
status = status | 0x02
status = status & 0xDF
_wait_write()
asm.outb(MOUSE_COMMAND, 0x60)
_wait_write()
asm.outb(MOUSE_DATA, status)
_write_cmd(0xF6)
_write_cmd(0xF4)
pic.clearMask(12)
idt.irqInstallHandler(12, irq_handler, "mouse")
import asm
import intr.idt as idt
import platform.pch.pic as pic
import drivers.serial.uart.serial as serial
import t, c
MOUSE_DATA: t.CDefine = 0x60
MOUSE_STATUS: t.CDefine = 0x64
MOUSE_COMMAND: t.CDefine = 0x64
MOUSE_BUF_SIZE: t.CDefine = 1024
MOUSE_LEFT: t.CDefine = 0x01
MOUSE_RIGHT: t.CDefine = 0x02
MOUSE_MIDDLE: t.CDefine = 0x04
class mouse_packet:
flags: uint8
dx: int8
dy: int8
buttons: uint8
packets: t.CArray[mouse_packet, MOUSE_BUF_SIZE]
pack_head: t.CStatic | uint32 = 0
pack_tail: t.CStatic | uint32 = 0
pack_count: t.CStatic | uint32 = 0
mse_irq_cnt: t.CStatic | uint64 = 0
cycle: t.CStatic | uint8 = 0
byte1: t.CStatic | uint8 = 0
byte2: t.CStatic | int8 = 0
byte3: t.CStatic | int8 = 0
mouse_x: t.CStatic | int32 = 0
mouse_y: t.CStatic | int32 = 0
mouse_buttons: t.CStatic | uint8 = 0
def _wait_read():
timeout: uint32 = 100000
while timeout > 0:
if (asm.inb(MOUSE_STATUS) & 0x01) != 0: return
timeout -= 1
def _wait_write():
timeout: uint32 = 100000
while timeout > 0:
if (asm.inb(MOUSE_STATUS) & 0x02) == 0: return
timeout -= 1
def _write_cmd(cmd: uint8):
_wait_write()
asm.outb(MOUSE_COMMAND, 0xD4)
_wait_write()
asm.outb(MOUSE_DATA, cmd)
_wait_read()
asm.inb(MOUSE_DATA)
def irq_handler() -> int:
global cycle, byte1, byte2, byte3, pack_tail, pack_count, mse_irq_cnt
mse_irq_cnt += 1
status: uint8 = asm.inb(MOUSE_STATUS)
if (status & 0x20) == 0: return 0
data: uint8 = asm.inb(MOUSE_DATA)
if cycle == 0:
if (data & 0x08) != 0:
byte1 = data
cycle = 1
return 0
if cycle == 1:
byte2 = data
cycle = 2
return 0
byte3 = data
cycle = 0
if pack_count < MOUSE_BUF_SIZE:
packets[pack_tail].flags = byte1
packets[pack_tail].dx = byte2
packets[pack_tail].dy = byte3
packets[pack_tail].buttons = byte1 & uint8(0x07)
pack_tail = pack_tail + 1
if pack_tail >= MOUSE_BUF_SIZE:
pack_tail = 0
pack_count += 1
return 0
def read_packet(out: mouse_packet | t.CPtr) -> int:
global pack_head, pack_count
asm.cli()
if pack_count == 0:
asm.sti()
out.flags = 0
out.dx = 0
out.dy = 0
out.buttons = 0
return -1
out.flags = packets[pack_head].flags
out.dx = packets[pack_head].dx
out.dy = packets[pack_head].dy
out.buttons = packets[pack_head].buttons
pack_head = pack_head + 1
if pack_head >= MOUSE_BUF_SIZE:
pack_head = 0
pack_count -= 1
asm.sti()
return 0
def has_data() -> int:
return pack_count
def get_x() -> int32:
return mouse_x
def get_y() -> int32:
return mouse_y
def get_buttons() -> uint8:
return mouse_buttons
def init():
_wait_write()
asm.outb(MOUSE_COMMAND, 0xA8)
_wait_write()
asm.outb(MOUSE_COMMAND, 0x20)
_wait_read()
status: uint8 = asm.inb(MOUSE_DATA)
status = status | 0x02
status = status & 0xDF
_wait_write()
asm.outb(MOUSE_COMMAND, 0x60)
_wait_write()
asm.outb(MOUSE_DATA, status)
_write_cmd(0xF6)
_write_cmd(0xF4)
pic.clearMask(12)
idt.irqInstallHandler(12, irq_handler, "mouse")
+7 -7
View File
@@ -30,15 +30,15 @@ def puts(s: str):
putchar(i)
# 检查COM1是否有数据可读
def isDataAvailable() -> t.CInt:
def isDataAvailable() -> int:
return su8250.isDataAvailable(su8250.COM1_PORT)
# 检查COM1发送缓冲区是否为空
def isTransmitEmpty() -> t.CInt:
def isTransmitEmpty() -> int:
return su8250.isTransmitEmpty(su8250.COM1_PORT)
# 发送32位十六进制值到COM1
def put_hex32(value: t.CUInt32T):
def put_hex32(value: uint32):
hex_digits: t.CArray[t.CChar, None] = ["0123456789ABCDEF"]
buffer: t.CArray[t.CChar, 9]
for i in range(7, -1, -1):
@@ -51,24 +51,24 @@ def put_hex32(value: t.CUInt32T):
# 格式化输出到串口(printf 实现,覆盖 libc printf 的裸机缺失)
# 内部复用 viperlib.vsnprintf 格式化到栈缓冲,再逐字符送串口。
# print(...) 内建映射到 @printf(stdio extern),此定义提供裸机实现。
def printf(fmt: t.CConst | str, *args) -> t.CInt | t.CExport:
def printf(fmt: t.CConst | str, *args) -> int | t.CExport:
if fmt is None:
return 0
buf: t.CArray[t.CChar, 1024]
n: t.CInt = viperlib.vsnprintf(c.Addr(buf), 1024, fmt, args)
n: int = viperlib.vsnprintf(c.Addr(buf), 1024, fmt, args)
puts(buf)
return n
# 刷新输出流:串口是无缓冲直写(putchar 直接写 UART 端口),flush 即空操作。
# 覆盖 libc fflush 的裸机缺失(memhub 的诊断/终止路径 call @fflush)。
def fflush(stream: t.CConst | t.CVoid | t.CPtr) -> t.CInt | t.CExport:
def fflush(stream: t.CConst | t.CPtr) -> int | t.CExport:
return 0
# 系统退出:触发硬件关机(QEMU ACPI/Bochs 关机端口),失败则停机兜底。
# 覆盖 libc exit 的裸机缺失(memhub 等致命错误路径 call @exit)。
def exit(status: int) -> t.CInt | t.CExport:
def exit(status: int) -> int | t.CExport:
asm.outw(0x604, 0x2000) # QEMU ACPI 关机
asm.outw(0xB004, 0x2000) # Bochs/QEMU 备用端口
while True:
+8 -8
View File
@@ -40,7 +40,7 @@ BAUD_115200: t.CDefine = 1
# 初始化UART 8250/16550
def init(port: t.CUInt16T):
def init(port: uint16):
# 1. 禁用中断
asm.outb(port + UART_IER, 0x00)
delay(1000)
@@ -69,18 +69,18 @@ def init(port: t.CUInt16T):
delay(10000)
# 延迟函数
def delay(count: t.CInt):
def delay(count: int):
for i in range(count): c.Asm("nop")
# 检查发送缓冲区是否为空
def isTransmitEmpty(port: t.CUInt16T) -> t.CInt:
def isTransmitEmpty(port: uint16) -> int:
return asm.inb(port + UART_LSR) & UART_LSR_THRE
def putchar(port: t.CUInt16T, cr: t.CChar):
def putchar(port: uint16, cr: t.CChar):
# 1. 处理换行符:串口终端需要\r\n才会正确换行,只发\n会错位
if cr == '\n':
# 直接发送\r,避免递归调用
timeout: t.CUInt32T = 1000000
timeout: uint32 = 1000000
while ((asm.inb(port + UART_LSR) & UART_LSR_THRE) == 0) and timeout:
c.Asm("nop")
timeout -= 1
@@ -91,7 +91,7 @@ def putchar(port: t.CUInt16T, cr: t.CChar):
c.Asm("nop")
timeout -= 1
# 2. 等待发送缓冲区为空
timeout: t.CUInt32T = 1000000
timeout: uint32 = 1000000
while ((asm.inb(port + UART_LSR) & UART_LSR_THRE) == 0) and timeout:
c.Asm("nop")
timeout -= 1
@@ -105,11 +105,11 @@ def putchar(port: t.CUInt16T, cr: t.CChar):
timeout -= 1
# 检查是否有数据可读
def isDataAvailable(port: t.CUInt16T) -> t.CInt:
def isDataAvailable(port: uint16) -> int:
return asm.inb(port + UART_LSR) & UART_LSR_DR
# 读取一个字符
def getchar(port: t.CUInt16T) -> t.CChar:
def getchar(port: uint16) -> t.CChar:
# 等待数据可用
while not isDataAvailable(port): pass
# 读取字符
+51 -49
View File
@@ -29,12 +29,12 @@ IDE_STATUS_ERR: t.CDefine = 0x01
SECTOR_SIZE: t.CDefine = 512
_ide_initialized: t.CInt = 0
_ide_initialized: int = 0
def waitReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
timeout: t.CInt = 100000
def waitReady(baseport: uint16) -> t.CStatic | IDError:
timeout: int = 100000
while timeout > 0:
status: t.CUInt8T = asm.inb(baseport + 7)
status: uint8 = asm.inb(baseport + 7)
if status & IDE_STATUS_DF:
return IDError.IDE_ERR_DEVICE_FAILURE
if not status & IDE_STATUS_BSY and status & IDE_STATUS_DRDY:
@@ -42,10 +42,10 @@ def waitReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
timeout -= 1
return IDError.IDE_ERR_TIMEOUT
def waitDataReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
timeout: t.CInt = 100000
def waitDataReady(baseport: uint16) -> t.CStatic | IDError:
timeout: int = 100000
while timeout > 0:
status: t.CUInt8T = asm.inb(baseport + 7)
status: uint8 = asm.inb(baseport + 7)
if status & IDE_STATUS_ERR: return IDError.IDE_ERR_DEVICE_ERROR
if status & IDE_STATUS_DF: return IDError.IDE_ERR_DEVICE_FAILURE
if not status & IDE_STATUS_BSY and (status & IDE_STATUS_DRQ or status & IDE_STATUS_DRDY):
@@ -53,110 +53,112 @@ def waitDataReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
timeout -= 1
return IDError.IDE_ERR_TIMEOUT
def init() -> t.CInt:
def init() -> int:
global _ide_initialized
if _ide_initialized: return IDError.IDE_ERR_NONE
dbg: t.CArray[t.CChar, 120]
bus: t.CUInt8T
dev_n: t.CUInt8T
func: t.CUInt8T
bus: uint8
dev_n: uint8
func: uint8
for bus in range(2):
for dev_n in range(32):
for func in range(8):
vendor: t.CUInt16T = pci.pci_read16(bus, dev_n, func, 0x00)
vendor: uint16 = pci.pci_read16(bus, dev_n, func, 0x00)
if vendor == 0xFFFF: continue
cls: t.CUInt32T = pci.pci_get_class(bus, dev_n, func)
cls: uint32 = pci.pci_get_class(bus, dev_n, func)
if cls == 0x010180 or cls == 0x0101:
cmd: t.CUInt16T = pci.pci_read16(bus, dev_n, func, 0x04)
pci.pci_write32(bus, dev_n, func, 0x04, t.CUInt32T(cmd | 0x0007))
viperlib.snprintf(c.Addr(dbg), 120, "[ide] found at %d:%d:%d cmd=0x%04x\n", t.CInt(bus), t.CInt(dev_n), t.CInt(func), t.CUInt32T(pci.pci_read16(bus, dev_n, func, 0x04)))
cmd: uint16 = pci.pci_read16(bus, dev_n, func, 0x04)
pci.pci_write32(bus, dev_n, func, 0x04, uint32(cmd | 0x0007))
viperlib.snprintf(c.Addr(dbg), 120, "[ide] found at %d:%d:%d cmd=0x%04x\n", int(bus), int(dev_n), int(func), uint32(pci.pci_read16(bus, dev_n, func, 0x04)))
serial.puts(dbg)
asm.outb(0x3F6, 0x04)
i: t.CInt
i: int
for i in range(10000):
asm.nop()
asm.outb(0x3F6, 0x00)
for i in range(10000):
asm.nop()
status: t.CUInt8T = asm.inb(0x1F7)
viperlib.snprintf(c.Addr(dbg), 120, "[ide] status=0x%02x\n", t.CUInt32T(status))
status: uint8 = asm.inb(0x1F7)
viperlib.snprintf(c.Addr(dbg), 120, "[ide] status=0x%02x\n", uint32(status))
serial.puts(dbg)
_ide_initialized = 1
return IDError.IDE_ERR_NONE
def readSector(lba: t.CUInt32T, buffer: t.CVoid | t.CPtr) -> t.CInt:
def readSector(lba: uint32, buffer: t.CPtr) -> int:
if buffer is None: return IDError.IDE_ERR_BUFFER_NULL
dbg: t.CArray[t.CChar, 120]
err: IDError = waitReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE:
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitReady err=%d\n", t.CInt(err))
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitReady err=%d\n", int(err))
serial.puts(dbg)
return err
asm.outb(0x3F6, 0x00)
asm.outb(0x1F2, 1)
asm.outb(0x1F3, t.CUInt8T(lba & 0xFF))
asm.outb(0x1F4, t.CUInt8T((lba >> 8) & 0xFF))
asm.outb(0x1F5, t.CUInt8T((lba >> 16) & 0xFF))
asm.outb(0x1F6, t.CUInt8T(0xE0 | ((lba >> 24) & 0x0F)))
asm.outb(0x1F3, uint8(lba & 0xFF))
asm.outb(0x1F4, uint8((lba >> 8) & 0xFF))
asm.outb(0x1F5, uint8((lba >> 16) & 0xFF))
asm.outb(0x1F6, uint8(0xE0 | ((lba >> 24) & 0x0F)))
asm.outb(0x1F7, 0x20)
err = waitDataReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE:
st: t.CUInt8T = asm.inb(0x1F7)
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitDataReady err=%d status=0x%02x\n", t.CInt(err), t.CUInt32T(st))
st: uint8 = asm.inb(0x1F7)
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitDataReady err=%d status=0x%02x\n", int(err), uint32(st))
serial.puts(dbg)
return err
st2: t.CUInt8T = asm.inb(0x1F7)
buf: t.CUInt16T | t.CPtr = t.CUInt16T(buffer, t.CPtr)
st2: uint8 = asm.inb(0x1F7)
buf: uint16 | t.CPtr = uint16(buffer, t.CPtr)
for j in range(256):
c.Set(c.Deref(buf), asm.inw(0x1F0))
buf += 1
first_byte: t.CUInt8T = c.Deref(t.CUInt8T(buffer, t.CPtr))
# viperlib.snprintf(c.Addr(dbg), 120, "[readSector] lba=%lu status=0x%02x first=%02x\n", lba, t.CUInt32T(st2), t.CUInt32T(first_byte))
# buf 为字节指针(uint16|t.CPtr → i8*),每次按 u16 读写须前进 2 字节
buf = buf + 2
first_byte: uint8 = c.Deref(uint8(buffer, t.CPtr))
# viperlib.snprintf(c.Addr(dbg), 120, "[readSector] lba=%lu status=0x%02x first=%02x\n", lba, uint32(st2), uint32(first_byte))
# serial.puts(dbg)
return IDError.IDE_ERR_NONE
def writeSector(lba: t.CUInt32T, buffer: t.CConst | t.CVoid | t.CPtr) -> t.CInt:
def writeSector(lba: uint32, buffer: t.CConst | t.CPtr) -> int:
if buffer is None: return IDError.IDE_ERR_BUFFER_NULL
err: IDError = waitReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE: return err
asm.outb(0x3F6, 0x00)
asm.outb(0x1F2, 1)
asm.outb(0x1F3, t.CUInt8T(lba & 0xFF))
asm.outb(0x1F4, t.CUInt8T((lba >> 8) & 0xFF))
asm.outb(0x1F5, t.CUInt8T((lba >> 16) & 0xFF))
asm.outb(0x1F6, t.CUInt8T(0xE0 | ((lba >> 24) & 0x0F)))
asm.outb(0x1F3, uint8(lba & 0xFF))
asm.outb(0x1F4, uint8((lba >> 8) & 0xFF))
asm.outb(0x1F5, uint8((lba >> 16) & 0xFF))
asm.outb(0x1F6, uint8(0xE0 | ((lba >> 24) & 0x0F)))
asm.outb(0x1F7, 0x30)
err = waitDataReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE: return err
buf: t.CUInt16T | t.CPtr = t.CUInt16T(buffer, t.CPtr)
buf: uint16 | t.CPtr = uint16(buffer, t.CPtr)
for j in range(256):
val: t.CUInt16T = c.Deref(buf)
val: uint16 = c.Deref(buf)
asm.outw(0x1F0, val)
buf += 1
# buf 为字节指针(uint16|t.CPtr → i8*),每次按 u16 读写须前进 2 字节
buf = buf + 2
asm.outb(0x1F7, 0xE7)
waitReady(IDE_baseport_PRIMARY)
return IDError.IDE_ERR_NONE
def getDiskSize() -> t.CUInt64T:
def getDiskSize() -> uint64:
err: IDError = waitReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE: return 0
asm.outb(0x1F6, 0xE0)
asm.outb(0x1F7, 0xEC)
err = waitDataReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE: return 0
status: t.CUInt8T = asm.inb(0x1F7)
status: uint8 = asm.inb(0x1F7)
if not status & IDE_STATUS_DRDY: return 0
if status & IDE_STATUS_ERR: return 0
identify_data: t.CArray[t.CUInt16T, 256]
identify_data: t.CArray[uint16, 256]
for i in range(256):
identify_data[i] = asm.inw(0x1F0)
totalSectors: t.CUInt64T = identify_data[60] | t.CUInt64T(identify_data[61]) << 16
totalSectors: uint64 = identify_data[60] | uint64(identify_data[61]) << 16
if identify_data[83] & (1 << 10):
lba48_sectors: t.CUInt64T = (
t.CUInt64T(identify_data[100]) |
t.CUInt64T(identify_data[101]) << 16 |
t.CUInt64T(identify_data[102]) << 32 |
t.CUInt64T(identify_data[103]) << 48)
lba48_sectors: uint64 = (
uint64(identify_data[100]) |
uint64(identify_data[101]) << 16 |
uint64(identify_data[102]) << 32 |
uint64(identify_data[103]) << 48)
if lba48_sectors > totalSectors:
totalSectors = lba48_sectors
return totalSectors
+37 -37
View File
@@ -1,37 +1,37 @@
import t, c
import drivers.usb.usb as usb
HID_BOOT_PROTOCOL: t.CDefine = 0
HID_REPORT_PROTOCOL: t.CDefine = 1
HID_KBD_REPORT_SIZE: t.CDefine = 8
HID_MOUSE_REPORT_SIZE: t.CDefine = 4
class hid_kbd_report(t.CStruct):
modifier: t.CUInt8T
reserved: t.CUInt8T
keycode: t.CArray[t.CUInt8T, 6]
class hid_mouse_report(t.CStruct):
buttons: t.CUInt8T
dx: t.CInt8T
dy: t.CInt8T
wheel: t.CInt8T
def init_keyboard(dev: usb.usb_device | t.CPtr) -> t.CInt:
if dev.iface_class != 0x03: return -1
if dev.iface_protocol != 0x01: return -2
if dev.ep_in == 0: return -3
return 0
def init_mouse(dev: usb.usb_device | t.CPtr) -> t.CInt:
if dev.iface_class != 0x03: return -1
if dev.iface_protocol != 0x02: return -2
if dev.ep_in == 0: return -3
return 0
def read_keyboard(dev: usb.usb_device | t.CPtr, report: hid_kbd_report | t.CPtr) -> t.CInt:
return usb.read_interrupt(dev, c.Addr(report))
def read_mouse(dev: usb.usb_device | t.CPtr, report: hid_mouse_report | t.CPtr) -> t.CInt:
return usb.read_interrupt(dev, c.Addr(report))
import t, c
import drivers.usb.usb as usb
HID_BOOT_PROTOCOL: t.CDefine = 0
HID_REPORT_PROTOCOL: t.CDefine = 1
HID_KBD_REPORT_SIZE: t.CDefine = 8
HID_MOUSE_REPORT_SIZE: t.CDefine = 4
class hid_kbd_report(t.CStruct):
modifier: uint8
reserved: uint8
keycode: t.CArray[uint8, 6]
class hid_mouse_report(t.CStruct):
buttons: uint8
dx: int8
dy: int8
wheel: int8
def init_keyboard(dev: usb.usb_device | t.CPtr) -> int:
if dev.iface_class != 0x03: return -1
if dev.iface_protocol != 0x01: return -2
if dev.ep_in == 0: return -3
return 0
def init_mouse(dev: usb.usb_device | t.CPtr) -> int:
if dev.iface_class != 0x03: return -1
if dev.iface_protocol != 0x02: return -2
if dev.ep_in == 0: return -3
return 0
def read_keyboard(dev: usb.usb_device | t.CPtr, report: hid_kbd_report | t.CPtr) -> int:
return usb.read_interrupt(dev, c.Addr(report))
def read_mouse(dev: usb.usb_device | t.CPtr, report: hid_mouse_report | t.CPtr) -> int:
return usb.read_interrupt(dev, c.Addr(report))
+116 -111
View File
@@ -1,111 +1,116 @@
import t, c
import drivers.usb.usb as usb
import drivers.usb.hid.hid as hid
import drivers.usb.uhci as uhci
import drivers.serial.uart.serial as serial
KBD_BUF_SIZE: t.CDefine = 1024
KBD_EVT_PRESS: t.CDefine = 0
KBD_EVT_RELEASE: t.CDefine = 1
class usb_kbd_event(t.CStruct):
modifier: t.CUInt8T
keycode: t.CUInt8T
event_type: t.CUInt8T
kbd_buf: t.CArray[usb_kbd_event, KBD_BUF_SIZE]
kbd_buf_head: t.CInt = 0
kbd_buf_tail: t.CInt = 0
kbd_buf_count: t.CInt = 0
kbd_dev: usb.usb_device | t.CPtr = None
kbd_report: hid.hid_kbd_report
kbd_prev_keycodes: t.CArray[t.CUInt8T, 6]
kbd_initialized: t.CInt = 0
kbd_slot_id: t.CInt = -1
def init() -> t.CInt:
global kbd_dev, kbd_initialized, kbd_slot_id
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x01)
if dev is None:
serial.puts("[usb_kbd] no USB keyboard found\n")
return -1
kbd_dev = dev
if hid.init_keyboard(dev) != 0:
serial.puts("[usb_kbd] init failed\n")
return -2
kbd_initialized = 1
serial.puts("[usb_kbd] initialized\n")
kbd_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
if kbd_slot_id < 0:
serial.puts("[usb_kbd] register callback failed\n")
kbd_initialized = 0
return -3
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), c.Addr(dev.ep_in_toggle), c.Addr(kbd_report))
return 0
def _on_int_complete() -> t.CInt:
global kbd_buf_head, kbd_buf_tail, kbd_buf_count, kbd_prev_keycodes
if kbd_initialized == 0: return 0
i: t.CInt
j: t.CInt
for i in range(6):
code: t.CUInt8T = kbd_report.keycode[i]
if code == 0: continue
found: t.CInt = 0
for j in range(6):
if code == kbd_prev_keycodes[j]:
found = 1
break
if found == 0:
if kbd_buf_count < KBD_BUF_SIZE:
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
kbd_buf[kbd_buf_tail].keycode = code
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_PRESS
kbd_buf_tail = kbd_buf_tail + 1
if kbd_buf_tail >= KBD_BUF_SIZE:
kbd_buf_tail = 0
kbd_buf_count += 1
for i in range(6):
prev: t.CUInt8T = kbd_prev_keycodes[i]
if prev == 0: continue
found2: t.CInt = 0
for j in range(6):
if prev == kbd_report.keycode[j]:
found2 = 1
break
if found2 == 0:
if kbd_buf_count < KBD_BUF_SIZE:
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
kbd_buf[kbd_buf_tail].keycode = prev
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_RELEASE
kbd_buf_tail = kbd_buf_tail + 1
if kbd_buf_tail >= KBD_BUF_SIZE:
kbd_buf_tail = 0
kbd_buf_count += 1
for i in range(6):
kbd_prev_keycodes[i] = kbd_report.keycode[i]
dev: usb.usb_device | t.CPtr = kbd_dev
if dev is not None and kbd_slot_id >= 0:
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), c.Addr(dev.ep_in_toggle), c.Addr(kbd_report))
return 0
def has_data() -> t.CInt:
if kbd_buf_count > 0: return 1
return 0
def poll() -> t.CInt:
if kbd_initialized == 0: return 0
if kbd_buf_count > 0: return 1
return 0
def read_event(out: usb_kbd_event | t.CPtr) -> t.CInt:
global kbd_buf_head, kbd_buf_count
if kbd_buf_count == 0: return -1
out.modifier = kbd_buf[kbd_buf_head].modifier
out.keycode = kbd_buf[kbd_buf_head].keycode
out.event_type = kbd_buf[kbd_buf_head].event_type
kbd_buf_head = kbd_buf_head + 1
if kbd_buf_head >= KBD_BUF_SIZE:
kbd_buf_head = 0
kbd_buf_count -= 1
return 0
import t, c
import drivers.usb.usb as usb
import drivers.usb.hid.hid as hid
import drivers.usb.uhci as uhci
import drivers.serial.uart.serial as serial
KBD_BUF_SIZE: t.CDefine = 1024
KBD_EVT_PRESS: t.CDefine = 0
KBD_EVT_RELEASE: t.CDefine = 1
class usb_kbd_event(t.CStruct):
modifier: uint8
keycode: uint8
event_type: uint8
kbd_buf: t.CArray[usb_kbd_event, KBD_BUF_SIZE]
kbd_buf_head: int = 0
kbd_buf_tail: int = 0
kbd_buf_count: int = 0
kbd_dev: usb.usb_device | t.CPtr = None
kbd_report: hid.hid_kbd_report
kbd_prev_keycodes: t.CArray[uint8, 6]
kbd_initialized: int = 0
kbd_slot_id: int = -1
def init() -> int:
global kbd_dev, kbd_initialized, kbd_slot_id
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x01)
if dev is None:
serial.puts("[usb_kbd] no USB keyboard found\n")
return -1
kbd_dev = dev
if hid.init_keyboard(dev) != 0:
serial.puts("[usb_kbd] init failed\n")
return -2
kbd_initialized = 1
serial.puts("[usb_kbd] initialized\n")
kbd_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
if kbd_slot_id < 0:
serial.puts("[usb_kbd] register callback failed\n")
kbd_initialized = 0
return -3
# 中断传输长度不得超过 kbd_report(8 字节),否则 DMA 越界写全局
kbd_pkt_len: uint8 = 8
if dev.ep_in_max < 8: kbd_pkt_len = uint8(dev.ep_in_max)
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, kbd_pkt_len, c.Addr(dev.ep_in_toggle), c.Addr(kbd_report))
return 0
def _on_int_complete() -> int:
global kbd_buf_head, kbd_buf_tail, kbd_buf_count, kbd_prev_keycodes
if kbd_initialized == 0: return 0
i: int
j: int
for i in range(6):
code: uint8 = kbd_report.keycode[i]
if code == 0: continue
found: int = 0
for j in range(6):
if code == kbd_prev_keycodes[j]:
found = 1
break
if found == 0:
if kbd_buf_count < KBD_BUF_SIZE:
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
kbd_buf[kbd_buf_tail].keycode = code
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_PRESS
kbd_buf_tail = kbd_buf_tail + 1
if kbd_buf_tail >= KBD_BUF_SIZE:
kbd_buf_tail = 0
kbd_buf_count += 1
for i in range(6):
prev: uint8 = kbd_prev_keycodes[i]
if prev == 0: continue
found2: int = 0
for j in range(6):
if prev == kbd_report.keycode[j]:
found2 = 1
break
if found2 == 0:
if kbd_buf_count < KBD_BUF_SIZE:
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
kbd_buf[kbd_buf_tail].keycode = prev
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_RELEASE
kbd_buf_tail = kbd_buf_tail + 1
if kbd_buf_tail >= KBD_BUF_SIZE:
kbd_buf_tail = 0
kbd_buf_count += 1
for i in range(6):
kbd_prev_keycodes[i] = kbd_report.keycode[i]
dev: usb.usb_device | t.CPtr = kbd_dev
if dev is not None and kbd_slot_id >= 0:
kbd_pkt_len2: uint8 = 8
if dev.ep_in_max < 8: kbd_pkt_len2 = uint8(dev.ep_in_max)
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, kbd_pkt_len2, c.Addr(dev.ep_in_toggle), c.Addr(kbd_report))
return 0
def has_data() -> int:
if kbd_buf_count > 0: return 1
return 0
def poll() -> int:
if kbd_initialized == 0: return 0
if kbd_buf_count > 0: return 1
return 0
def read_event(out: usb_kbd_event | t.CPtr) -> int:
global kbd_buf_head, kbd_buf_count
if kbd_buf_count == 0: return -1
out.modifier = kbd_buf[kbd_buf_head].modifier
out.keycode = kbd_buf[kbd_buf_head].keycode
out.event_type = kbd_buf[kbd_buf_head].event_type
kbd_buf_head = kbd_buf_head + 1
if kbd_buf_head >= KBD_BUF_SIZE:
kbd_buf_head = 0
kbd_buf_count -= 1
return 0
+82 -77
View File
@@ -1,77 +1,82 @@
import t, c
import drivers.usb.usb as usb
import drivers.usb.hid.hid as hid
import drivers.usb.uhci as uhci
import drivers.serial.uart.serial as serial
MOUSE_BUF_SIZE: t.CDefine = 1024
class usb_mouse_packet(t.CStruct):
buttons: t.CUInt8T
dx: t.CInt16T
dy: t.CInt16T
wheel: t.CInt8T
mse_buf: t.CArray[usb_mouse_packet, MOUSE_BUF_SIZE]
mse_buf_head: t.CInt = 0
mse_buf_tail: t.CInt = 0
mse_buf_count: t.CInt = 0
mse_dev: usb.usb_device | t.CPtr = None
mse_report: hid.hid_mouse_report
mse_initialized: t.CInt = 0
mse_slot_id: t.CInt = -1
def init() -> t.CInt:
global mse_dev, mse_initialized, mse_slot_id
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x02)
if dev is None:
serial.puts("[usb_mse] no USB mouse found\n")
return -1
mse_dev = dev
if hid.init_mouse(dev) != 0:
serial.puts("[usb_mse] init failed\n")
return -2
mse_initialized = 1
serial.puts("[usb_mse] initialized\n")
mse_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
if mse_slot_id < 0:
serial.puts("[usb_mse] register callback failed\n")
mse_initialized = 0
return -3
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), c.Addr(dev.ep_in_toggle), c.Addr(mse_report))
return 0
def _on_int_complete() -> t.CInt:
global mse_buf_head, mse_buf_tail, mse_buf_count
if mse_initialized == 0: return 0
if mse_report.dx != 0 or mse_report.dy != 0 or mse_report.buttons != 0:
if mse_buf_count < MOUSE_BUF_SIZE:
mse_buf[mse_buf_tail].buttons = mse_report.buttons
mse_buf[mse_buf_tail].dx = t.CInt16T(mse_report.dx)
mse_buf[mse_buf_tail].dy = t.CInt16T(mse_report.dy)
mse_buf[mse_buf_tail].wheel = mse_report.wheel
mse_buf_tail = mse_buf_tail + 1
if mse_buf_tail >= MOUSE_BUF_SIZE:
mse_buf_tail = 0
mse_buf_count += 1
dev: usb.usb_device | t.CPtr = mse_dev
if dev is not None and mse_slot_id >= 0:
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), c.Addr(dev.ep_in_toggle), c.Addr(mse_report))
return 0
def has_data() -> t.CInt:
if mse_buf_count > 0: return 1
return 0
def read_packet(out: usb_mouse_packet | t.CPtr) -> t.CInt:
global mse_buf_head, mse_buf_count
if mse_buf_count == 0: return -1
out.buttons = mse_buf[mse_buf_head].buttons
out.dx = mse_buf[mse_buf_head].dx
out.dy = mse_buf[mse_buf_head].dy
out.wheel = mse_buf[mse_buf_head].wheel
mse_buf_head = mse_buf_head + 1
if mse_buf_head >= MOUSE_BUF_SIZE:
mse_buf_head = 0
mse_buf_count -= 1
return 0
import t, c
import drivers.usb.usb as usb
import drivers.usb.hid.hid as hid
import drivers.usb.uhci as uhci
import drivers.serial.uart.serial as serial
MOUSE_BUF_SIZE: t.CDefine = 1024
class usb_mouse_packet(t.CStruct):
buttons: uint8
dx: int16
dy: int16
wheel: int8
mse_buf: t.CArray[usb_mouse_packet, MOUSE_BUF_SIZE]
mse_buf_head: int = 0
mse_buf_tail: int = 0
mse_buf_count: int = 0
mse_dev: usb.usb_device | t.CPtr = None
mse_report: hid.hid_mouse_report
mse_initialized: int = 0
mse_slot_id: int = -1
def init() -> int:
global mse_dev, mse_initialized, mse_slot_id
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x02)
if dev is None:
serial.puts("[usb_mse] no USB mouse found\n")
return -1
mse_dev = dev
if hid.init_mouse(dev) != 0:
serial.puts("[usb_mse] init failed\n")
return -2
mse_initialized = 1
serial.puts("[usb_mse] initialized\n")
mse_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
if mse_slot_id < 0:
serial.puts("[usb_mse] register callback failed\n")
mse_initialized = 0
return -3
# 中断传输长度不得超过 mse_report(4 字节),否则 DMA 越界写全局
mse_pkt_len: uint8 = 4
if dev.ep_in_max < 4: mse_pkt_len = uint8(dev.ep_in_max)
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, mse_pkt_len, c.Addr(dev.ep_in_toggle), c.Addr(mse_report))
return 0
def _on_int_complete() -> int:
global mse_buf_head, mse_buf_tail, mse_buf_count
if mse_initialized == 0: return 0
if mse_report.dx != 0 or mse_report.dy != 0 or mse_report.buttons != 0:
if mse_buf_count < MOUSE_BUF_SIZE:
mse_buf[mse_buf_tail].buttons = mse_report.buttons
mse_buf[mse_buf_tail].dx = int16(mse_report.dx)
mse_buf[mse_buf_tail].dy = int16(mse_report.dy)
mse_buf[mse_buf_tail].wheel = mse_report.wheel
mse_buf_tail = mse_buf_tail + 1
if mse_buf_tail >= MOUSE_BUF_SIZE:
mse_buf_tail = 0
mse_buf_count += 1
dev: usb.usb_device | t.CPtr = mse_dev
if dev is not None and mse_slot_id >= 0:
mse_pkt_len2: uint8 = 4
if dev.ep_in_max < 4: mse_pkt_len2 = uint8(dev.ep_in_max)
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, mse_pkt_len2, c.Addr(dev.ep_in_toggle), c.Addr(mse_report))
return 0
def has_data() -> int:
if mse_buf_count > 0: return 1
return 0
def read_packet(out: usb_mouse_packet | t.CPtr) -> int:
global mse_buf_head, mse_buf_count
if mse_buf_count == 0: return -1
out.buttons = mse_buf[mse_buf_head].buttons
out.dx = mse_buf[mse_buf_head].dx
out.dy = mse_buf[mse_buf_head].dy
out.wheel = mse_buf[mse_buf_head].wheel
mse_buf_head = mse_buf_head + 1
if mse_buf_head >= MOUSE_BUF_SIZE:
mse_buf_head = 0
mse_buf_count -= 1
return 0
+93 -93
View File
@@ -1,93 +1,93 @@
import t, c
import asm
PCI_CONFIG_ADDR: t.CDefine = 0xCF8
PCI_CONFIG_DATA: t.CDefine = 0xCFC
PCI_CLASS_SERIAL_USB: t.CDefine = 0x0C03
PCI_CLASS_SERIAL_UHCI: t.CDefine = 0x0C0300
PCI_CLASS_SERIAL_OHCI: t.CDefine = 0x0C0310
PCI_CLASS_SERIAL_EHCI: t.CDefine = 0x0C0320
PCI_CLASS_SERIAL_XHCI: t.CDefine = 0x0C0330
PCI_CMD_IO_SPACE: t.CDefine = 0x0001
PCI_CMD_BUS_MASTER: t.CDefine = 0x0004
class pci_device(t.CStruct):
bus: t.CUInt8T
dev: t.CUInt8T
func: t.CUInt8T
vendor_id: t.CUInt16T
device_id: t.CUInt16T
class_code: t.CUInt32T
irq: t.CUInt8T
bar: t.CArray[t.CUInt32T, 6]
def pci_read32(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt32T:
addr: t.CUInt32T = 0x80000000 | (t.CUInt32T(bus) << 16) | (t.CUInt32T(dev) << 11) | (t.CUInt32T(func) << 8) | (t.CUInt32T(offset) & 0xFC)
asm.outl(PCI_CONFIG_ADDR, addr)
return asm.inl(PCI_CONFIG_DATA)
def pci_write32(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T, value: t.CUInt32T):
addr: t.CUInt32T = 0x80000000 | (t.CUInt32T(bus) << 16) | (t.CUInt32T(dev) << 11) | (t.CUInt32T(func) << 8) | (t.CUInt32T(offset) & 0xFC)
asm.outl(PCI_CONFIG_ADDR, addr)
asm.outl(PCI_CONFIG_DATA, value)
def pci_read16(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt16T:
val: t.CUInt32T = pci_read32(bus, dev, func, offset)
shift: t.CUInt32T = (t.CUInt32T(offset) & 0x02) * 8
return t.CUInt16T((val >> shift) & 0xFFFF)
def pci_read8(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt8T:
val: t.CUInt32T = pci_read32(bus, dev, func, offset)
shift: t.CUInt32T = (t.CUInt32T(offset) & 0x03) * 8
return t.CUInt8T((val >> shift) & 0xFF)
def pci_get_class(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T) -> t.CUInt32T:
cls: t.CUInt8T = pci_read8(bus, dev, func, 0x0B)
sub: t.CUInt8T = pci_read8(bus, dev, func, 0x0A)
proto: t.CUInt8T = pci_read8(bus, dev, func, 0x09)
return (t.CUInt32T(cls) << 16) | (t.CUInt32T(sub) << 8) | t.CUInt32T(proto)
def pci_get_bar(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, bar_idx: t.CUInt8T) -> t.CUInt32T:
return pci_read32(bus, dev, func, 0x10 + bar_idx * 4)
def pci_enable_device(dev: pci_device | t.CPtr):
cmd: t.CUInt16T = pci_read16(dev.bus, dev.dev, dev.func, 0x04)
cmd = cmd | PCI_CMD_IO_SPACE | PCI_CMD_BUS_MASTER
pci_write32(dev.bus, dev.dev, dev.func, 0x04, t.CUInt32T(cmd))
def pci_fill_device(bus: t.CUInt8T, dev_n: t.CUInt8T, func: t.CUInt8T, out: pci_device | t.CPtr):
out.bus = bus
out.dev = dev_n
out.func = func
out.vendor_id = pci_read16(bus, dev_n, func, 0x00)
out.device_id = pci_read16(bus, dev_n, func, 0x02)
out.class_code = pci_get_class(bus, dev_n, func)
out.irq = pci_read8(bus, dev_n, func, 0x3C)
i: t.CInt
for i in range(6):
out.bar[i] = pci_get_bar(bus, dev_n, func, t.CUInt8T(i))
_uhci_dev: pci_device
_uhci_found: t.CInt = 0
def find_uhci() -> t.CUInt16T:
global _uhci_dev, _uhci_found
bus: t.CUInt8T
dev_n: t.CUInt8T
func: t.CUInt8T
for bus in range(1):
for dev_n in range(32):
for func in range(8):
vendor: t.CUInt16T = pci_read16(bus, dev_n, func, 0x00)
if vendor == 0xFFFF: continue
cls: t.CUInt32T = pci_get_class(bus, dev_n, func)
if cls == PCI_CLASS_SERIAL_UHCI:
pci_fill_device(bus, dev_n, func, c.Addr(_uhci_dev))
pci_enable_device(c.Addr(_uhci_dev))
_uhci_found = 1
bar: t.CUInt32T = _uhci_dev.bar[4]
io_base: t.CUInt16T = t.CUInt16T(bar & 0xFFFE)
return io_base
return 0
import t, c
import asm
PCI_CONFIG_ADDR: t.CDefine = 0xCF8
PCI_CONFIG_DATA: t.CDefine = 0xCFC
PCI_CLASS_SERIAL_USB: t.CDefine = 0x0C03
PCI_CLASS_SERIAL_UHCI: t.CDefine = 0x0C0300
PCI_CLASS_SERIAL_OHCI: t.CDefine = 0x0C0310
PCI_CLASS_SERIAL_EHCI: t.CDefine = 0x0C0320
PCI_CLASS_SERIAL_XHCI: t.CDefine = 0x0C0330
PCI_CMD_IO_SPACE: t.CDefine = 0x0001
PCI_CMD_BUS_MASTER: t.CDefine = 0x0004
class pci_device(t.CStruct):
bus: uint8
dev: uint8
func: uint8
vendor_id: uint16
device_id: uint16
class_code: uint32
irq: uint8
bar: t.CArray[uint32, 6]
def pci_read32(bus: uint8, dev: uint8, func: uint8, offset: uint8) -> uint32:
addr: uint32 = 0x80000000 | (uint32(bus) << 16) | (uint32(dev) << 11) | (uint32(func) << 8) | (uint32(offset) & 0xFC)
asm.outl(PCI_CONFIG_ADDR, addr)
return asm.inl(PCI_CONFIG_DATA)
def pci_write32(bus: uint8, dev: uint8, func: uint8, offset: uint8, value: uint32):
addr: uint32 = 0x80000000 | (uint32(bus) << 16) | (uint32(dev) << 11) | (uint32(func) << 8) | (uint32(offset) & 0xFC)
asm.outl(PCI_CONFIG_ADDR, addr)
asm.outl(PCI_CONFIG_DATA, value)
def pci_read16(bus: uint8, dev: uint8, func: uint8, offset: uint8) -> uint16:
val: uint32 = pci_read32(bus, dev, func, offset)
shift: uint32 = (uint32(offset) & 0x02) * 8
return uint16((val >> shift) & 0xFFFF)
def pci_read8(bus: uint8, dev: uint8, func: uint8, offset: uint8) -> uint8:
val: uint32 = pci_read32(bus, dev, func, offset)
shift: uint32 = (uint32(offset) & 0x03) * 8
return uint8((val >> shift) & 0xFF)
def pci_get_class(bus: uint8, dev: uint8, func: uint8) -> uint32:
cls: uint8 = pci_read8(bus, dev, func, 0x0B)
sub: uint8 = pci_read8(bus, dev, func, 0x0A)
proto: uint8 = pci_read8(bus, dev, func, 0x09)
return (uint32(cls) << 16) | (uint32(sub) << 8) | uint32(proto)
def pci_get_bar(bus: uint8, dev: uint8, func: uint8, bar_idx: uint8) -> uint32:
return pci_read32(bus, dev, func, 0x10 + bar_idx * 4)
def pci_enable_device(dev: pci_device | t.CPtr):
cmd: uint16 = pci_read16(dev.bus, dev.dev, dev.func, 0x04)
cmd = cmd | PCI_CMD_IO_SPACE | PCI_CMD_BUS_MASTER
pci_write32(dev.bus, dev.dev, dev.func, 0x04, uint32(cmd))
def pci_fill_device(bus: uint8, dev_n: uint8, func: uint8, out: pci_device | t.CPtr):
out.bus = bus
out.dev = dev_n
out.func = func
out.vendor_id = pci_read16(bus, dev_n, func, 0x00)
out.device_id = pci_read16(bus, dev_n, func, 0x02)
out.class_code = pci_get_class(bus, dev_n, func)
out.irq = pci_read8(bus, dev_n, func, 0x3C)
i: int
for i in range(6):
out.bar[i] = pci_get_bar(bus, dev_n, func, uint8(i))
_uhci_dev: pci_device
_uhci_found: int = 0
def find_uhci() -> uint16:
global _uhci_dev, _uhci_found
bus: uint8
dev_n: uint8
func: uint8
for bus in range(1):
for dev_n in range(32):
for func in range(8):
vendor: uint16 = pci_read16(bus, dev_n, func, 0x00)
if vendor == 0xFFFF: continue
cls: uint32 = pci_get_class(bus, dev_n, func)
if cls == PCI_CLASS_SERIAL_UHCI:
pci_fill_device(bus, dev_n, func, c.Addr(_uhci_dev))
pci_enable_device(c.Addr(_uhci_dev))
_uhci_found = 1
bar: uint32 = _uhci_dev.bar[4]
io_base: uint16 = uint16(bar & 0xFFFE)
return io_base
return 0
+419 -419
View File
@@ -1,419 +1,419 @@
import t, c
import asm
import mm.mm as mm
import viperstring as string
import drivers.serial.uart.serial as serial
import platform.pch.timer as timer
import intr.idt as idt
import platform.pch.pic as pic
import drivers.usb.pci as pci
import viperlib
UHCI_USBCMD: t.CDefine = 0x00
UHCI_USBSTS: t.CDefine = 0x02
UHCI_USBINTR: t.CDefine = 0x04
UHCI_FRNUM: t.CDefine = 0x06
UHCI_FLBASEADD: t.CDefine = 0x08
UHCI_SOFMOD: t.CDefine = 0x0C
UHCI_PORTSC1: t.CDefine = 0x10
UHCI_PORTSC2: t.CDefine = 0x12
UHCI_CMD_RUN: t.CDefine = 0x0001
UHCI_CMD_HCRESET: t.CDefine = 0x0002
UHCI_CMD_GRESET: t.CDefine = 0x0004
UHCI_CMD_MAXPKT: t.CDefine = 0x0080
UHCI_CMD_CF: t.CDefine = 0x0040
UHCI_STS_HCHALTED: t.CDefine = 0x0020
UHCI_STS_USBINT: t.CDefine = 0x0001
UHCI_STS_USBERRINT: t.CDefine = 0x0002
UHCI_STS_RESUME: t.CDefine = 0x0004
UHCI_INTR_TIMEOUT: t.CDefine = 0x0001
UHCI_INTR_RESUME: t.CDefine = 0x0002
UHCI_INTR_IOC: t.CDefine = 0x0004
UHCI_INTR_SHORT: t.CDefine = 0x0008
UHCI_PORT_CONNECT: t.CDefine = 0x0001
UHCI_PORT_CONNECT_CHANGE: t.CDefine = 0x0002
UHCI_PORT_ENABLE: t.CDefine = 0x0004
UHCI_PORT_ENABLE_CHANGE: t.CDefine = 0x0008
UHCI_PORT_RESET: t.CDefine = 0x0200
UHCI_PORT_LOW_SPEED: t.CDefine = 0x0100
TD_CTRL_ACTIVE: t.CDefine = 0x00800000
TD_CTRL_IOC: t.CDefine = 0x01000000
TD_CTRL_LS: t.CDefine = 0x04000000
TD_CTRL_SPD: t.CDefine = 0x20000000
TD_CTRL_CERR_SHIFT: t.CDefine = 27
TD_CTRL_CERR_MASK: t.CDefine = 0x18000000
TD_TOKEN_SETUP: t.CDefine = 0x2D
TD_TOKEN_IN: t.CDefine = 0x69
TD_TOKEN_OUT: t.CDefine = 0xE1
TD_TOKEN_DATA0: t.CDefine = 0
TD_TOKEN_DATA1: t.CDefine = 1
TD_LINK_TERMINATE: t.CDefine = 0x00000001
TD_LINK_QH: t.CDefine = 0x00000002
TD_LINK_DEPTH_FIRST: t.CDefine = 0x00000004
UHCI_NUM_FRAMES: t.CDefine = 1024
UHCI_INT_SLOTS: t.CDefine = 4
class uhci_td(t.CStruct):
link: t.CUInt32T
ctrl_status: t.CUInt32T
token: t.CUInt32T
buffer: t.CUInt32T
class uhci_qh(t.CStruct):
link: t.CUInt32T
element: t.CUInt32T
class int_slot(t.CStruct):
td: uhci_td | t.CPtr
callback: t.CInt | t.CPtr
active: t.CInt
qh: uhci_qh | t.CPtr
_io_base: t.CUInt16T = 0
_frame_list: t.CUInt32T | t.CPtr = None
_ctrl_qh: uhci_qh | t.CPtr = None
_bulk_qh: uhci_qh | t.CPtr = None
_irq: t.CInt = -1
_int_slots: t.CArray[int_slot, UHCI_INT_SLOTS]
_int_slot_count: t.CInt = 0
def _reg_read16(offset: t.CUInt16T) -> t.CUInt16T:
return asm.inw(_io_base + offset)
def _reg_write16(offset: t.CUInt16T, value: t.CUInt16T):
asm.outw(_io_base + offset, value)
def _reg_read32(offset: t.CUInt16T) -> t.CUInt32T:
return asm.inl(_io_base + offset)
def _reg_write32(offset: t.CUInt16T, value: t.CUInt32T):
asm.outl(_io_base + offset, value)
def _uhci_irq_handler() -> t.CInt:
sts: t.CUInt16T = _reg_read16(UHCI_USBSTS)
_reg_write16(UHCI_USBSTS, sts)
if (sts & (UHCI_STS_USBINT | UHCI_STS_USBERRINT)) == 0:
return 0
for si in range(_int_slot_count):
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
if slot.active and slot.td is not None and slot.callback is not None:
status: t.CUInt32T = slot.td.ctrl_status
if (status & TD_CTRL_ACTIVE) == 0:
slot.active = 0
c.Asm(f"""mov rbp, rsp
and rsp, -16
call {c.AsmInp(slot.callback, t.ASM_DESCR.REG_ANY)}
mov rsp, rbp""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RBX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11,
t.ASM_DESCR.CLOBBER_RBP])
return 0
def register_int_callback(cb: t.CInt | t.CPtr) -> t.CInt:
global _int_slot_count
if _int_slot_count >= UHCI_INT_SLOTS:
return -1
si: t.CInt = _int_slot_count
qh: uhci_qh | t.CPtr = mm.malloc_direct(uhci_qh.__sizeof__())
if qh is None:
return -2
string.memset(c.Addr(qh), 0, uhci_qh.__sizeof__())
_qh_set_link(qh, 0, 0, 1)
_qh_set_element(qh, 0, 1)
td: uhci_td | t.CPtr = mm.malloc_direct(uhci_td.__sizeof__())
if td is None:
return -3
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
slot.td = td
slot.callback = cb
slot.active = 0
slot.qh = qh
_int_slot_count = si + 1
_rebuild_int_chain()
return si
def schedule_int_transfer(slot_id: t.CInt, dev_addr: t.CUInt8T, endpoint: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, toggle_ptr: t.CUInt8T | t.CPtr, buf: t.CVoid | t.CPtr):
if slot_id < 0 or slot_id >= _int_slot_count:
return
slot: int_slot | t.CPtr = c.Addr(_int_slots[slot_id])
td: uhci_td | t.CPtr = slot.td
qh: uhci_qh | t.CPtr = slot.qh
if td is None or qh is None:
return
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
_td_set_link(td, 0, 0, 1)
_td_set_ctrl(td, ls, max_pkt)
_td_set_token(td, TD_TOKEN_IN, dev_addr, endpoint, toggle_ptr, max_pkt)
td.ctrl_status = td.ctrl_status | TD_CTRL_IOC
td.buffer = t.CUInt32T(t.CUInt64T(buf))
_qh_set_element(qh, t.CUInt32T(t.CUInt64T(td)), 0)
slot.active = 1
def _rebuild_int_chain():
if _int_slot_count == 0:
return
first_qh: uhci_qh | t.CPtr = None
prev_qh: uhci_qh | t.CPtr = None
for si in range(_int_slot_count):
cur_qh: uhci_qh | t.CPtr = _int_slots[si].qh
if cur_qh is not None:
if first_qh is None:
first_qh = cur_qh
if prev_qh is not None:
_qh_set_link(prev_qh, t.CUInt32T(t.CUInt64T(cur_qh)) | TD_LINK_QH, 1, 0)
prev_qh = cur_qh
if prev_qh is not None:
_qh_set_link(prev_qh, t.CUInt32T(t.CUInt64T(_ctrl_qh)) | TD_LINK_QH, 1, 0)
if first_qh is not None:
qh_addr: t.CUInt32T = t.CUInt32T(t.CUInt64T(first_qh)) | TD_LINK_QH
i: t.CInt
for i in range(UHCI_NUM_FRAMES):
entry_ptr: t.CUInt32T | t.CPtr = _frame_list + t.CUInt64T(i) * 4
c.Set(c.Deref(entry_ptr), qh_addr)
def _td_set_link(td: uhci_td | t.CPtr, addr: t.CUInt32T, is_qh: t.CInt, terminate: t.CInt):
val: t.CUInt32T = (addr & 0xFFFFFFF0)
if is_qh: val = val | TD_LINK_QH
if terminate: val = val | TD_LINK_TERMINATE
td.link = val
def _td_set_token(td: uhci_td | t.CPtr, pid: t.CUInt8T, dev_addr: t.CUInt8T, endpoint: t.CUInt8T, toggle: t.CUInt8T, max_len: t.CUInt16T):
len_bits: t.CUInt32T
if max_len == 0:
len_bits = 0x7FF
else:
len_bits = t.CUInt32T(max_len) - 1
td.token = (t.CUInt32T(pid) << 0) | (t.CUInt32T(dev_addr) << 8) | (t.CUInt32T(endpoint & 0x0F) << 15) | (t.CUInt32T(toggle & 1) << 19) | (len_bits << 21)
def _td_set_ctrl(td: uhci_td | t.CPtr, ls: t.CInt, maxlen: t.CUInt16T):
td.ctrl_status = TD_CTRL_ACTIVE | (3 << TD_CTRL_CERR_SHIFT)
if ls: td.ctrl_status = td.ctrl_status | TD_CTRL_LS
def _qh_set_link(qh: uhci_qh | t.CPtr, addr: t.CUInt32T, is_qh: t.CInt, terminate: t.CInt):
val: t.CUInt32T = (addr & 0xFFFFFFF0)
if is_qh: val = val | TD_LINK_QH
if terminate: val = val | TD_LINK_TERMINATE
qh.link = val
def _qh_set_element(qh: uhci_qh | t.CPtr, addr: t.CUInt32T, terminate: t.CInt):
val: t.CUInt32T = (addr & 0xFFFFFFF0)
if terminate: val = val | TD_LINK_TERMINATE
qh.element = val
def _wait_for_complete(td: uhci_td | t.CPtr, timeout_ms: t.CInt) -> t.CInt:
start: t.CUInt64T = timer.timer_get_ticks()
deadline: t.CUInt64T = start + t.CUInt64T(timeout_ms)
poll_cnt: t.CInt = 0
while timer.timer_get_ticks() < deadline:
status: t.CUInt32T = td.ctrl_status
if (status & TD_CTRL_ACTIVE) == 0:
if (status & 0x00600000) != 0:
return -1
return 0
poll_cnt += 1
if poll_cnt >= 100:
poll_cnt = 0
asm.sti()
asm.hlt()
return -2
def reset(io_base: t.CUInt16T) -> t.CInt:
global _io_base
_io_base = io_base
_reg_write16(UHCI_USBCMD, UHCI_CMD_HCRESET)
i: t.CInt
for i in range(1000):
if (_reg_read16(UHCI_USBCMD) & UHCI_CMD_HCRESET) == 0:
break
_reg_write16(UHCI_USBSTS, 0xFFFF)
_reg_write16(UHCI_USBINTR, 0x0000)
return 0
def init(io_base: t.CUInt16T) -> t.CInt:
global _irq, _io_base, _frame_list, _ctrl_qh, _bulk_qh, _int_slot_count
_io_base = io_base
_int_slot_count = 0
serial.puts("[uhci] resetting...\n")
if reset(io_base) != 0:
serial.puts("[uhci] reset failed\n")
return -1
serial.puts("[uhci] allocating frame list...\n")
_frame_list = mm.malloc(UHCI_NUM_FRAMES * 4)
_dbg_fl: t.CArray[t.CChar, 96]
viperlib.snprintf(c.Addr(_dbg_fl), 96, "[dbg] frame_list ret=0x%lx\n", t.CUInt64T(_frame_list))
serial.puts(c.Addr(_dbg_fl))
if _frame_list is None:
serial.puts("[uhci] frame list alloc failed\n")
return -2
string.memset(_frame_list, 0, UHCI_NUM_FRAMES * 4)
_ctrl_qh = mm.malloc_direct(uhci_qh.__sizeof__())
if _ctrl_qh is None:
serial.puts("[uhci] ctrl_qh alloc failed\n")
return -3
string.memset(c.Addr(_ctrl_qh), 0, uhci_qh.__sizeof__())
_qh_set_link(_ctrl_qh, 0, 0, 1)
_qh_set_element(_ctrl_qh, 0, 1)
_bulk_qh = mm.malloc_direct(uhci_qh.__sizeof__())
if _bulk_qh is None:
serial.puts("[uhci] bulk_qh alloc failed\n")
return -4
string.memset(c.Addr(_bulk_qh), 0, uhci_qh.__sizeof__())
_qh_set_link(_bulk_qh, 0, 0, 1)
_qh_set_element(_bulk_qh, 0, 1)
serial.puts("[uhci] setting up frame list...\n")
qh_addr: t.CUInt32T = t.CUInt32T(c.Addr(_ctrl_qh)) | TD_LINK_QH
i: t.CInt
for i in range(UHCI_NUM_FRAMES):
entry_ptr: t.CUInt32T | t.CPtr = _frame_list + t.CUInt64T(i) * 4
c.Set(c.Deref(entry_ptr), qh_addr)
_reg_write32(UHCI_FLBASEADD, t.CUInt32T(t.CUInt64T(_frame_list)))
_reg_write16(UHCI_FRNUM, 0)
_reg_write16(UHCI_SOFMOD, 64)
_reg_write16(UHCI_USBCMD, UHCI_CMD_CF | UHCI_CMD_MAXPKT | UHCI_CMD_RUN)
timer.timer_msleep(10)
_reg_write16(UHCI_USBSTS, 0xFFFF)
_reg_write16(UHCI_USBINTR, UHCI_INTR_IOC | UHCI_INTR_SHORT)
_irq = t.CInt(pci._uhci_dev.irq)
if _irq > 0 and _irq < 16:
idt.irqInstallHandler(_irq, _uhci_irq_handler, "uhci")
pic.clearMask(t.CUInt8T(_irq))
serial.puts("[uhci] started\n")
return 0
def port_reset(port: t.CInt) -> t.CInt:
sc: t.CUInt16T
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if (sc & UHCI_PORT_CONNECT) == 0:
return -1
if port == 0:
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
else:
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
if port == 0:
_reg_write16(UHCI_PORTSC1, UHCI_PORT_RESET)
else:
_reg_write16(UHCI_PORTSC2, UHCI_PORT_RESET)
timer.timer_msleep(50)
if port == 0:
_reg_write16(UHCI_PORTSC1, 0x0000)
else:
_reg_write16(UHCI_PORTSC2, 0x0000)
timer.timer_msleep(10)
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
else:
sc = _reg_read16(UHCI_PORTSC2)
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
timer.timer_msleep(10)
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if (sc & UHCI_PORT_ENABLE) == 0:
return -2
return 0
def port_is_connected(port: t.CInt) -> t.CInt:
sc: t.CUInt16T
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if sc & UHCI_PORT_CONNECT: return 1
return 0
def port_is_low_speed(port: t.CInt) -> t.CInt:
sc: t.CUInt16T
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if sc & UHCI_PORT_LOW_SPEED: return 1
return 0
def control_transfer(dev_addr: t.CUInt8T, endpoint: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, setup_buf: t.CVoid | t.CPtr, data_buf: t.CVoid | t.CPtr, data_len: t.CUInt16T, data_in: t.CInt) -> t.CInt:
td_count: t.CInt = 2
if data_len > 0:
td_count = td_count + 1
total: t.CUInt64T = t.CUInt64T(td_count) * uhci_td.__sizeof__()
tds: uhci_td | t.CPtr = mm.malloc_direct(total)
if tds is None: return -1
string.memset(c.Addr(tds), 0, total)
setup_td: uhci_td | t.CPtr = tds
_td_set_link(setup_td, t.CUInt32T(t.CUInt64T(tds) + uhci_td.__sizeof__()), 0, 0)
_td_set_ctrl(setup_td, ls, 8)
_td_set_token(setup_td, TD_TOKEN_SETUP, dev_addr, endpoint, TD_TOKEN_DATA0, 8)
setup_td.buffer = t.CUInt32T(t.CUInt64T(setup_buf))
if data_len > 0:
data_td: uhci_td | t.CPtr = t.CPtr(t.CUInt64T(tds) + uhci_td.__sizeof__())
_td_set_link(data_td, t.CUInt32T(t.CUInt64T(data_td) + uhci_td.__sizeof__()), 0, 0)
_td_set_ctrl(data_td, ls, max_pkt)
if data_in:
_td_set_token(data_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
else:
_td_set_token(data_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
data_td.buffer = t.CUInt32T(t.CUInt64T(data_buf))
status_td: uhci_td | t.CPtr = t.CPtr(t.CUInt64T(data_td) + uhci_td.__sizeof__())
_td_set_link(status_td, 0, 0, 1)
_td_set_ctrl(status_td, ls, max_pkt)
if data_in:
_td_set_token(status_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
else:
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
status_td.buffer = 0
else:
status_td: uhci_td | t.CPtr = t.CPtr(t.CUInt64T(tds) + uhci_td.__sizeof__())
_td_set_link(status_td, 0, 0, 1)
_td_set_ctrl(status_td, ls, max_pkt)
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
status_td.buffer = 0
_qh_set_element(_ctrl_qh, t.CUInt32T(t.CUInt64T(setup_td)), 0)
result: t.CInt = _wait_for_complete(status_td, 500)
_qh_set_element(_ctrl_qh, 0, 1)
mm.free(tds)
return result
import t, c
import asm
import mm.mm as mm
import viperstring as string
import drivers.serial.uart.serial as serial
import platform.pch.timer as timer
import intr.idt as idt
import platform.pch.pic as pic
import drivers.usb.pci as pci
import viperlib
UHCI_USBCMD: t.CDefine = 0x00
UHCI_USBSTS: t.CDefine = 0x02
UHCI_USBINTR: t.CDefine = 0x04
UHCI_FRNUM: t.CDefine = 0x06
UHCI_FLBASEADD: t.CDefine = 0x08
UHCI_SOFMOD: t.CDefine = 0x0C
UHCI_PORTSC1: t.CDefine = 0x10
UHCI_PORTSC2: t.CDefine = 0x12
UHCI_CMD_RUN: t.CDefine = 0x0001
UHCI_CMD_HCRESET: t.CDefine = 0x0002
UHCI_CMD_GRESET: t.CDefine = 0x0004
UHCI_CMD_MAXPKT: t.CDefine = 0x0080
UHCI_CMD_CF: t.CDefine = 0x0040
UHCI_STS_HCHALTED: t.CDefine = 0x0020
UHCI_STS_USBINT: t.CDefine = 0x0001
UHCI_STS_USBERRINT: t.CDefine = 0x0002
UHCI_STS_RESUME: t.CDefine = 0x0004
UHCI_INTR_TIMEOUT: t.CDefine = 0x0001
UHCI_INTR_RESUME: t.CDefine = 0x0002
UHCI_INTR_IOC: t.CDefine = 0x0004
UHCI_INTR_SHORT: t.CDefine = 0x0008
UHCI_PORT_CONNECT: t.CDefine = 0x0001
UHCI_PORT_CONNECT_CHANGE: t.CDefine = 0x0002
UHCI_PORT_ENABLE: t.CDefine = 0x0004
UHCI_PORT_ENABLE_CHANGE: t.CDefine = 0x0008
UHCI_PORT_RESET: t.CDefine = 0x0200
UHCI_PORT_LOW_SPEED: t.CDefine = 0x0100
TD_CTRL_ACTIVE: t.CDefine = 0x00800000
TD_CTRL_IOC: t.CDefine = 0x01000000
TD_CTRL_LS: t.CDefine = 0x04000000
TD_CTRL_SPD: t.CDefine = 0x20000000
TD_CTRL_CERR_SHIFT: t.CDefine = 27
TD_CTRL_CERR_MASK: t.CDefine = 0x18000000
TD_TOKEN_SETUP: t.CDefine = 0x2D
TD_TOKEN_IN: t.CDefine = 0x69
TD_TOKEN_OUT: t.CDefine = 0xE1
TD_TOKEN_DATA0: t.CDefine = 0
TD_TOKEN_DATA1: t.CDefine = 1
TD_LINK_TERMINATE: t.CDefine = 0x00000001
TD_LINK_QH: t.CDefine = 0x00000002
TD_LINK_DEPTH_FIRST: t.CDefine = 0x00000004
UHCI_NUM_FRAMES: t.CDefine = 1024
UHCI_INT_SLOTS: t.CDefine = 4
class uhci_td(t.CStruct):
link: uint32
ctrl_status: uint32
token: uint32
buffer: uint32
class uhci_qh(t.CStruct):
link: uint32
element: uint32
class int_slot(t.CStruct):
td: uhci_td | t.CPtr
callback: int | t.CPtr
active: int
qh: uhci_qh | t.CPtr
_io_base: uint16 = 0
_frame_list: uint32 | t.CPtr = None
_ctrl_qh: uhci_qh | t.CPtr = None
_bulk_qh: uhci_qh | t.CPtr = None
_irq: int = -1
_int_slots: t.CArray[int_slot, UHCI_INT_SLOTS]
_int_slot_count: int = 0
def _reg_read16(offset: uint16) -> uint16:
return asm.inw(_io_base + offset)
def _reg_write16(offset: uint16, value: uint16):
asm.outw(_io_base + offset, value)
def _reg_read32(offset: uint16) -> uint32:
return asm.inl(_io_base + offset)
def _reg_write32(offset: uint16, value: uint32):
asm.outl(_io_base + offset, value)
def _uhci_irq_handler() -> int:
sts: uint16 = _reg_read16(UHCI_USBSTS)
_reg_write16(UHCI_USBSTS, sts)
if (sts & (UHCI_STS_USBINT | UHCI_STS_USBERRINT)) == 0:
return 0
for si in range(_int_slot_count):
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
if slot.active and slot.td is not None and slot.callback is not None:
status: uint32 = slot.td.ctrl_status
if (status & TD_CTRL_ACTIVE) == 0:
slot.active = 0
c.Asm(f"""mov rbp, rsp
and rsp, -16
call {c.AsmInp(slot.callback, t.ASM_DESCR.REG_ANY)}
mov rsp, rbp""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RBX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11,
t.ASM_DESCR.CLOBBER_RBP])
return 0
def register_int_callback(cb: int | t.CPtr) -> int:
global _int_slot_count
if _int_slot_count >= UHCI_INT_SLOTS:
return -1
si: int = _int_slot_count
qh: uhci_qh | t.CPtr = mm.malloc_direct(uhci_qh.__sizeof__())
if qh is None:
return -2
string.memset(c.Addr(qh), 0, uhci_qh.__sizeof__())
_qh_set_link(qh, 0, 0, 1)
_qh_set_element(qh, 0, 1)
td: uhci_td | t.CPtr = mm.malloc_direct(uhci_td.__sizeof__())
if td is None:
return -3
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
slot.td = td
slot.callback = cb
slot.active = 0
slot.qh = qh
_int_slot_count = si + 1
_rebuild_int_chain()
return si
def schedule_int_transfer(slot_id: int, dev_addr: uint8, endpoint: uint8, ls: int, max_pkt: uint8, toggle_ptr: uint8 | t.CPtr, buf: t.CPtr):
if slot_id < 0 or slot_id >= _int_slot_count:
return
slot: int_slot | t.CPtr = c.Addr(_int_slots[slot_id])
td: uhci_td | t.CPtr = slot.td
qh: uhci_qh | t.CPtr = slot.qh
if td is None or qh is None:
return
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
_td_set_link(td, 0, 0, 1)
_td_set_ctrl(td, ls, max_pkt)
_td_set_token(td, TD_TOKEN_IN, dev_addr, endpoint, toggle_ptr, max_pkt)
td.ctrl_status = td.ctrl_status | TD_CTRL_IOC
td.buffer = uint32(uint64(buf))
_qh_set_element(qh, uint32(uint64(td)), 0)
slot.active = 1
def _rebuild_int_chain():
if _int_slot_count == 0:
return
first_qh: uhci_qh | t.CPtr = None
prev_qh: uhci_qh | t.CPtr = None
for si in range(_int_slot_count):
cur_qh: uhci_qh | t.CPtr = _int_slots[si].qh
if cur_qh is not None:
if first_qh is None:
first_qh = cur_qh
if prev_qh is not None:
_qh_set_link(prev_qh, uint32(uint64(cur_qh)) | TD_LINK_QH, 1, 0)
prev_qh = cur_qh
if prev_qh is not None:
_qh_set_link(prev_qh, uint32(uint64(_ctrl_qh)) | TD_LINK_QH, 1, 0)
if first_qh is not None:
qh_addr: uint32 = uint32(uint64(first_qh)) | TD_LINK_QH
i: int
for i in range(UHCI_NUM_FRAMES):
entry_ptr: uint32 | t.CPtr = _frame_list + uint64(i) * 4
c.Set(c.Deref(entry_ptr), qh_addr)
def _td_set_link(td: uhci_td | t.CPtr, addr: uint32, is_qh: int, terminate: int):
val: uint32 = (addr & 0xFFFFFFF0)
if is_qh: val = val | TD_LINK_QH
if terminate: val = val | TD_LINK_TERMINATE
td.link = val
def _td_set_token(td: uhci_td | t.CPtr, pid: uint8, dev_addr: uint8, endpoint: uint8, toggle: uint8, max_len: uint16):
len_bits: uint32
if max_len == 0:
len_bits = 0x7FF
else:
len_bits = uint32(max_len) - 1
td.token = (uint32(pid) << 0) | (uint32(dev_addr) << 8) | (uint32(endpoint & 0x0F) << 15) | (uint32(toggle & 1) << 19) | (len_bits << 21)
def _td_set_ctrl(td: uhci_td | t.CPtr, ls: int, maxlen: uint16):
td.ctrl_status = TD_CTRL_ACTIVE | (3 << TD_CTRL_CERR_SHIFT)
if ls: td.ctrl_status = td.ctrl_status | TD_CTRL_LS
def _qh_set_link(qh: uhci_qh | t.CPtr, addr: uint32, is_qh: int, terminate: int):
val: uint32 = (addr & 0xFFFFFFF0)
if is_qh: val = val | TD_LINK_QH
if terminate: val = val | TD_LINK_TERMINATE
qh.link = val
def _qh_set_element(qh: uhci_qh | t.CPtr, addr: uint32, terminate: int):
val: uint32 = (addr & 0xFFFFFFF0)
if terminate: val = val | TD_LINK_TERMINATE
qh.element = val
def _wait_for_complete(td: uhci_td | t.CPtr, timeout_ms: int) -> int:
start: uint64 = timer.timer_get_ticks()
deadline: uint64 = start + uint64(timeout_ms)
poll_cnt: int = 0
while timer.timer_get_ticks() < deadline:
status: uint32 = td.ctrl_status
if (status & TD_CTRL_ACTIVE) == 0:
if (status & 0x00600000) != 0:
return -1
return 0
poll_cnt += 1
if poll_cnt >= 100:
poll_cnt = 0
asm.sti()
asm.hlt()
return -2
def reset(io_base: uint16) -> int:
global _io_base
_io_base = io_base
_reg_write16(UHCI_USBCMD, UHCI_CMD_HCRESET)
i: int
for i in range(1000):
if (_reg_read16(UHCI_USBCMD) & UHCI_CMD_HCRESET) == 0:
break
_reg_write16(UHCI_USBSTS, 0xFFFF)
_reg_write16(UHCI_USBINTR, 0x0000)
return 0
def init(io_base: uint16) -> int:
global _irq, _io_base, _frame_list, _ctrl_qh, _bulk_qh, _int_slot_count
_io_base = io_base
_int_slot_count = 0
serial.puts("[uhci] resetting...\n")
if reset(io_base) != 0:
serial.puts("[uhci] reset failed\n")
return -1
serial.puts("[uhci] allocating frame list...\n")
_frame_list = mm.malloc(UHCI_NUM_FRAMES * 4)
_dbg_fl: t.CArray[t.CChar, 96]
viperlib.snprintf(c.Addr(_dbg_fl), 96, "[dbg] frame_list ret=0x%lx\n", uint64(_frame_list))
serial.puts(c.Addr(_dbg_fl))
if _frame_list is None:
serial.puts("[uhci] frame list alloc failed\n")
return -2
string.memset(_frame_list, 0, UHCI_NUM_FRAMES * 4)
_ctrl_qh = mm.malloc_direct(uhci_qh.__sizeof__())
if _ctrl_qh is None:
serial.puts("[uhci] ctrl_qh alloc failed\n")
return -3
string.memset(c.Addr(_ctrl_qh), 0, uhci_qh.__sizeof__())
_qh_set_link(_ctrl_qh, 0, 0, 1)
_qh_set_element(_ctrl_qh, 0, 1)
_bulk_qh = mm.malloc_direct(uhci_qh.__sizeof__())
if _bulk_qh is None:
serial.puts("[uhci] bulk_qh alloc failed\n")
return -4
string.memset(c.Addr(_bulk_qh), 0, uhci_qh.__sizeof__())
_qh_set_link(_bulk_qh, 0, 0, 1)
_qh_set_element(_bulk_qh, 0, 1)
serial.puts("[uhci] setting up frame list...\n")
qh_addr: uint32 = uint32(c.Addr(_ctrl_qh)) | TD_LINK_QH
i: int
for i in range(UHCI_NUM_FRAMES):
entry_ptr: uint32 | t.CPtr = _frame_list + uint64(i) * 4
c.Set(c.Deref(entry_ptr), qh_addr)
_reg_write32(UHCI_FLBASEADD, uint32(uint64(_frame_list)))
_reg_write16(UHCI_FRNUM, 0)
_reg_write16(UHCI_SOFMOD, 64)
_reg_write16(UHCI_USBCMD, UHCI_CMD_CF | UHCI_CMD_MAXPKT | UHCI_CMD_RUN)
timer.timer_msleep(10)
_reg_write16(UHCI_USBSTS, 0xFFFF)
_reg_write16(UHCI_USBINTR, UHCI_INTR_IOC | UHCI_INTR_SHORT)
_irq = int(pci._uhci_dev.irq)
if _irq > 0 and _irq < 16:
idt.irqInstallHandler(_irq, _uhci_irq_handler, "uhci")
pic.clearMask(uint8(_irq))
serial.puts("[uhci] started\n")
return 0
def port_reset(port: int) -> int:
sc: uint16
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if (sc & UHCI_PORT_CONNECT) == 0:
return -1
if port == 0:
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
else:
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
if port == 0:
_reg_write16(UHCI_PORTSC1, UHCI_PORT_RESET)
else:
_reg_write16(UHCI_PORTSC2, UHCI_PORT_RESET)
timer.timer_msleep(50)
if port == 0:
_reg_write16(UHCI_PORTSC1, 0x0000)
else:
_reg_write16(UHCI_PORTSC2, 0x0000)
timer.timer_msleep(10)
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
else:
sc = _reg_read16(UHCI_PORTSC2)
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
timer.timer_msleep(10)
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if (sc & UHCI_PORT_ENABLE) == 0:
return -2
return 0
def port_is_connected(port: int) -> int:
sc: uint16
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if sc & UHCI_PORT_CONNECT: return 1
return 0
def port_is_low_speed(port: int) -> int:
sc: uint16
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if sc & UHCI_PORT_LOW_SPEED: return 1
return 0
def control_transfer(dev_addr: uint8, endpoint: uint8, ls: int, max_pkt: uint8, setup_buf: t.CPtr, data_buf: t.CPtr, data_len: uint16, data_in: int) -> int:
td_count: int = 2
if data_len > 0:
td_count = td_count + 1
total: uint64 = uint64(td_count) * uhci_td.__sizeof__()
tds: uhci_td | t.CPtr = mm.malloc_direct(total)
if tds is None: return -1
string.memset(c.Addr(tds), 0, total)
setup_td: uhci_td | t.CPtr = tds
_td_set_link(setup_td, uint32(uint64(tds) + uhci_td.__sizeof__()), 0, 0)
_td_set_ctrl(setup_td, ls, 8)
_td_set_token(setup_td, TD_TOKEN_SETUP, dev_addr, endpoint, TD_TOKEN_DATA0, 8)
setup_td.buffer = uint32(uint64(setup_buf))
if data_len > 0:
data_td: uhci_td | t.CPtr = t.CPtr(uint64(tds) + uhci_td.__sizeof__())
_td_set_link(data_td, uint32(uint64(data_td) + uhci_td.__sizeof__()), 0, 0)
_td_set_ctrl(data_td, ls, max_pkt)
if data_in:
_td_set_token(data_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
else:
_td_set_token(data_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
data_td.buffer = uint32(uint64(data_buf))
status_td: uhci_td | t.CPtr = t.CPtr(uint64(data_td) + uhci_td.__sizeof__())
_td_set_link(status_td, 0, 0, 1)
_td_set_ctrl(status_td, ls, max_pkt)
if data_in:
_td_set_token(status_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
else:
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
status_td.buffer = 0
else:
status_td: uhci_td | t.CPtr = t.CPtr(uint64(tds) + uhci_td.__sizeof__())
_td_set_link(status_td, 0, 0, 1)
_td_set_ctrl(status_td, ls, max_pkt)
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
status_td.buffer = 0
_qh_set_element(_ctrl_qh, uint32(uint64(setup_td)), 0)
result: int = _wait_for_complete(status_td, 500)
_qh_set_element(_ctrl_qh, 0, 1)
mm.free(tds)
return result
+333 -330
View File
@@ -1,330 +1,333 @@
import t, c
import mm.mm as mm
import viperstring as string
import drivers.serial.uart.serial as serial
import drivers.usb.uhci as uhci
import drivers.usb.pci as pci
import platform.pch.timer as timer
import viperlib
USB_DESC_DEVICE: t.CDefine = 1
USB_DESC_CONFIG: t.CDefine = 2
USB_DESC_STRING: t.CDefine = 3
USB_DESC_INTERFACE: t.CDefine = 4
USB_DESC_ENDPOINT: t.CDefine = 5
USB_REQ_GET_STATUS: t.CDefine = 0
USB_REQ_CLEAR_FEATURE: t.CDefine = 1
USB_REQ_SET_FEATURE: t.CDefine = 3
USB_REQ_SET_ADDRESS: t.CDefine = 5
USB_REQ_GET_DESCRIPTOR: t.CDefine = 6
USB_REQ_SET_DESCRIPTOR: t.CDefine = 7
USB_REQ_GET_CONFIGURATION: t.CDefine = 8
USB_REQ_SET_CONFIGURATION: t.CDefine = 9
USB_REQ_SET_INTERFACE: t.CDefine = 11
HID_CLASS: t.CDefine = 0x03
HID_SUBCLASS_BOOT: t.CDefine = 0x01
HID_PROTO_KEYBOARD: t.CDefine = 0x01
HID_PROTO_MOUSE: t.CDefine = 0x02
HID_REQ_SET_PROTOCOL: t.CDefine = 0x0B
HID_REQ_SET_IDLE: t.CDefine = 0x0A
HID_REQ_GET_REPORT: t.CDefine = 0x01
USB_MAX_DEVICES: t.CDefine = 8
class usb_dev_desc(t.CStruct):
bLength: t.CUInt8T
bDescriptorType: t.CUInt8T
bcdUSB: t.CUInt16T
bDeviceClass: t.CUInt8T
bDeviceSubClass: t.CUInt8T
bDeviceProtocol: t.CUInt8T
bMaxPacketSize0: t.CUInt8T
idVendor: t.CUInt16T
idProduct: t.CUInt16T
bcdDevice: t.CUInt16T
iManufacturer: t.CUInt8T
iProduct: t.CUInt8T
iSerialNumber: t.CUInt8T
bNumConfigurations: t.CUInt8T
class usb_config_desc(t.CStruct):
bLength: t.CUInt8T
bDescriptorType: t.CUInt8T
wTotalLength: t.CUInt16T
bNumInterfaces: t.CUInt8T
bConfigurationValue: t.CUInt8T
iConfiguration: t.CUInt8T
bmAttributes: t.CUInt8T
bMaxPower: t.CUInt8T
class usb_iface_desc(t.CStruct):
bLength: t.CUInt8T
bDescriptorType: t.CUInt8T
bInterfaceNumber: t.CUInt8T
bAlternateSetting: t.CUInt8T
bNumEndpoints: t.CUInt8T
bInterfaceClass: t.CUInt8T
bInterfaceSubClass: t.CUInt8T
bInterfaceProtocol: t.CUInt8T
iInterface: t.CUInt8T
class usb_ep_desc(t.CStruct):
bLength: t.CUInt8T
bDescriptorType: t.CUInt8T
bEndpointAddress: t.CUInt8T
bmAttributes: t.CUInt8T
wMaxPacketSize: t.CUInt16T
bInterval: t.CUInt8T
class usb_setup_pkt(t.CStruct):
bmRequestType: t.CUInt8T
bRequest: t.CUInt8T
wValue: t.CUInt16T
wIndex: t.CUInt16T
wLength: t.CUInt16T
class usb_device(t.CStruct):
addr: t.CUInt8T
ls: t.CInt
max_pkt0: t.CUInt8T
iface_class: t.CUInt8T
iface_subclass: t.CUInt8T
iface_protocol: t.CUInt8T
iface_num: t.CUInt8T
ep_in: t.CUInt8T
ep_in_max: t.CUInt16T
ep_in_interval: t.CUInt8T
ep_in_toggle: t.CUInt8T
configured: t.CInt
_devices: t.CArray[usb_device, USB_MAX_DEVICES]
_device_count: t.CInt = 0
def _setup_packet(bmRequestType: t.CUInt8T, bRequest: t.CUInt8T, wValue: t.CUInt16T, wIndex: t.CUInt16T, wLength: t.CUInt16T, buf: usb_setup_pkt | t.CPtr):
buf.bmRequestType = bmRequestType
buf.bRequest = bRequest
buf.wValue = wValue
buf.wIndex = wIndex
buf.wLength = wLength
def _send_control(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, setup: usb_setup_pkt | t.CPtr, data_buf: t.CVoid | t.CPtr, data_len: t.CUInt16T, data_in: t.CInt) -> t.CInt:
return uhci.control_transfer(dev_addr, 0, ls, max_pkt, c.Addr(setup), data_buf, data_len, data_in)
def get_descriptor(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, desc_type: t.CUInt8T, desc_idx: t.CUInt8T, buf: t.CVoid | t.CPtr, length: t.CUInt16T) -> t.CInt:
setup: usb_setup_pkt
_setup_packet(0x80, USB_REQ_GET_DESCRIPTOR, (t.CUInt16T(desc_type) << 8) | desc_idx, 0, length, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), buf, length, 1)
def set_address(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, new_addr: t.CUInt8T) -> t.CInt:
setup: usb_setup_pkt
_setup_packet(0x00, USB_REQ_SET_ADDRESS, new_addr, 0, 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def set_configuration(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, config_val: t.CUInt8T) -> t.CInt:
setup: usb_setup_pkt
_setup_packet(0x00, USB_REQ_SET_CONFIGURATION, config_val, 0, 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def hid_set_protocol(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, iface: t.CUInt8T, protocol: t.CUInt8T) -> t.CInt:
setup: usb_setup_pkt
_setup_packet(0x21, HID_REQ_SET_PROTOCOL, protocol, t.CUInt16T(iface), 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def hid_set_idle(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, iface: t.CUInt8T, duration: t.CUInt8T) -> t.CInt:
setup: usb_setup_pkt
_setup_packet(0x21, HID_REQ_SET_IDLE, t.CUInt16T(duration) << 8, t.CUInt16T(iface), 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def _parse_config(dev: usb_device | t.CPtr, config_buf: t.CVoid | t.CPtr, total_len: t.CUInt16T):
offset: t.CInt = 0
found_hid: t.CInt = 0
while offset < t.CInt(total_len):
p: t.CUInt8T | t.CPtr = config_buf + t.CUInt64T(offset)
desc_len: t.CUInt8T = c.Deref(p)
p2: t.CUInt8T | t.CPtr = config_buf + t.CUInt64T(offset) + 1
desc_type: t.CUInt8T = c.Deref(p2)
if desc_len == 0: break
if desc_type == USB_DESC_INTERFACE:
iface: usb_iface_desc | t.CPtr = config_buf + t.CUInt64T(offset)
if iface.bInterfaceClass == HID_CLASS:
found_hid = 1
dev.iface_class = HID_CLASS
dev.iface_subclass = iface.bInterfaceSubClass
dev.iface_protocol = iface.bInterfaceProtocol
dev.iface_num = iface.bInterfaceNumber
if desc_type == USB_DESC_ENDPOINT and found_hid:
ep: usb_ep_desc | t.CPtr = config_buf + t.CUInt64T(offset)
if (ep.bEndpointAddress & 0x80) != 0:
dev.ep_in = ep.bEndpointAddress & 0x0F
dev.ep_in_max = ep.wMaxPacketSize
dev.ep_in_interval = ep.bInterval
found_hid = 0
offset = offset + t.CInt(desc_len)
def enumerate_port(port: t.CInt) -> t.CInt:
global _device_count
if _device_count >= USB_MAX_DEVICES: return -1
ls: t.CInt = uhci.port_is_low_speed(port)
reset_ok: t.CInt = -1
reset_retry: t.CInt
for reset_retry in range(3):
if uhci.port_reset(port) == 0:
reset_ok = 0
break
timer.timer_msleep(50)
if reset_ok != 0:
return -2
timer.timer_msleep(10)
dev_buf: t.CVoid | t.CPtr = mm.malloc(usb_dev_desc.__sizeof__())
if dev_buf is None: return -3
string.memset(dev_buf, 0, usb_dev_desc.__sizeof__())
result: t.CInt = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
retry: t.CInt
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
uhci.port_reset(port)
timer.timer_msleep(10)
result = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
if result != 0:
mm.free(dev_buf)
return -4
desc: usb_dev_desc | t.CPtr = dev_buf
max_pkt: t.CUInt8T = desc.bMaxPacketSize0
if max_pkt < 8: max_pkt = 8
new_addr: t.CUInt8T = t.CUInt8T(_device_count + 1)
result = set_address(0, ls, max_pkt, new_addr)
for retry in range(3):
if result == 0: break
timer.timer_msleep(20)
result = set_address(0, ls, max_pkt, new_addr)
if result != 0:
mm.free(dev_buf)
return -5
timer.timer_msleep(10)
dev: usb_device | t.CPtr = c.Addr(_devices[_device_count])
dev.addr = new_addr
dev.ls = ls
dev.max_pkt0 = max_pkt
dev.configured = 0
dev.iface_class = 0
dev.iface_subclass = 0
dev.iface_protocol = 0
dev.ep_in = 0
dev.ep_in_max = 0
dev.ep_in_interval = 0
dev.ep_in_toggle = 0
config_buf: t.CVoid | t.CPtr = mm.malloc(256)
if config_buf is None:
mm.free(dev_buf)
return -6
string.memset(config_buf, 0, 256)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -7
cfg: usb_config_desc | t.CPtr = config_buf
total_len: t.CUInt16T = cfg.wTotalLength
if total_len > 256: total_len = 256
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -8
_parse_config(dev, config_buf, total_len)
result = set_configuration(new_addr, ls, max_pkt, cfg.bConfigurationValue)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -9
dev.configured = 1
if dev.iface_class == HID_CLASS:
hid_set_protocol(new_addr, ls, max_pkt, dev.iface_num, 0)
hid_set_idle(new_addr, ls, max_pkt, dev.iface_num, 0)
_device_count = _device_count + 1
mm.free(config_buf)
mm.free(dev_buf)
return t.CInt(new_addr)
def init() -> t.CInt:
global _device_count
_device_count = 0
io_base: t.CUInt16T = pci.find_uhci()
if io_base == 0:
serial.puts("[usb] UHCI controller not found\n")
return -1
buf: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(buf), 64, "[usb] UHCI at I/O 0x%04X\n", t.CUInt32T(io_base))
serial.puts(buf)
if uhci.init(io_base) != 0:
serial.puts("[usb] UHCI init failed\n")
return -2
serial.puts("[usb] UHCI initialized\n")
timer.timer_msleep(50)
port: t.CInt
for port in range(2):
if uhci.port_is_connected(port):
viperlib.snprintf(c.Addr(buf), 64, "[usb] port %d connected\n", t.CUInt32T(port))
serial.puts(buf)
dev_id: t.CInt = enumerate_port(port)
if dev_id > 0:
dev: usb_device | t.CPtr = c.Addr(_devices[dev_id - 1])
viperlib.snprintf(c.Addr(buf), 64, "[usb] device addr=%d class=%02X proto=%02X ep=%d\n",
t.CUInt32T(dev.addr), t.CUInt32T(dev.iface_class),
t.CUInt32T(dev.iface_protocol), t.CUInt32T(dev.ep_in))
serial.puts(buf)
else:
viperlib.snprintf(c.Addr(buf), 64, "[usb] enumerate port %d failed: %d\n", t.CUInt32T(port), t.CInt32T(dev_id))
serial.puts(buf)
return _device_count
def find_hid_device(protocol: t.CUInt8T) -> usb_device | t.CPtr:
i: t.CInt
for i in range(_device_count):
dev: usb_device | t.CPtr = c.Addr(_devices[i])
if dev.iface_class == HID_CLASS:
if dev.iface_protocol == protocol:
if dev.configured != 0:
return dev
return None
def read_interrupt(dev: usb_device | t.CPtr, buf: t.CVoid | t.CPtr) -> t.CInt:
return 0
import t, c
import mm.mm as mm
import viperstring as string
import drivers.serial.uart.serial as serial
import drivers.usb.uhci as uhci
import drivers.usb.pci as pci
import platform.pch.timer as timer
import viperlib
USB_DESC_DEVICE: t.CDefine = 1
USB_DESC_CONFIG: t.CDefine = 2
USB_DESC_STRING: t.CDefine = 3
USB_DESC_INTERFACE: t.CDefine = 4
USB_DESC_ENDPOINT: t.CDefine = 5
USB_REQ_GET_STATUS: t.CDefine = 0
USB_REQ_CLEAR_FEATURE: t.CDefine = 1
USB_REQ_SET_FEATURE: t.CDefine = 3
USB_REQ_SET_ADDRESS: t.CDefine = 5
USB_REQ_GET_DESCRIPTOR: t.CDefine = 6
USB_REQ_SET_DESCRIPTOR: t.CDefine = 7
USB_REQ_GET_CONFIGURATION: t.CDefine = 8
USB_REQ_SET_CONFIGURATION: t.CDefine = 9
USB_REQ_SET_INTERFACE: t.CDefine = 11
HID_CLASS: t.CDefine = 0x03
HID_SUBCLASS_BOOT: t.CDefine = 0x01
HID_PROTO_KEYBOARD: t.CDefine = 0x01
HID_PROTO_MOUSE: t.CDefine = 0x02
HID_REQ_SET_PROTOCOL: t.CDefine = 0x0B
HID_REQ_SET_IDLE: t.CDefine = 0x0A
HID_REQ_GET_REPORT: t.CDefine = 0x01
USB_MAX_DEVICES: t.CDefine = 8
class usb_dev_desc(t.CStruct):
bLength: uint8
bDescriptorType: uint8
bcdUSB: uint16
bDeviceClass: uint8
bDeviceSubClass: uint8
bDeviceProtocol: uint8
bMaxPacketSize0: uint8
idVendor: uint16
idProduct: uint16
bcdDevice: uint16
iManufacturer: uint8
iProduct: uint8
iSerialNumber: uint8
bNumConfigurations: uint8
class usb_config_desc(t.CStruct):
bLength: uint8
bDescriptorType: uint8
wTotalLength: uint16
bNumInterfaces: uint8
bConfigurationValue: uint8
iConfiguration: uint8
bmAttributes: uint8
bMaxPower: uint8
class usb_iface_desc(t.CStruct):
bLength: uint8
bDescriptorType: uint8
bInterfaceNumber: uint8
bAlternateSetting: uint8
bNumEndpoints: uint8
bInterfaceClass: uint8
bInterfaceSubClass: uint8
bInterfaceProtocol: uint8
iInterface: uint8
class usb_ep_desc(t.CStruct):
bLength: uint8
bDescriptorType: uint8
bEndpointAddress: uint8
bmAttributes: uint8
wMaxPacketSize: uint16
bInterval: uint8
class usb_setup_pkt(t.CStruct):
bmRequestType: uint8
bRequest: uint8
wValue: uint16
wIndex: uint16
wLength: uint16
class usb_device(t.CStruct):
addr: uint8
ls: int
max_pkt0: uint8
iface_class: uint8
iface_subclass: uint8
iface_protocol: uint8
iface_num: uint8
ep_in: uint8
ep_in_max: uint16
ep_in_interval: uint8
ep_in_toggle: uint8
configured: int
_devices: t.CArray[usb_device, USB_MAX_DEVICES]
_device_count: int = 0
def _setup_packet(bmRequestType: uint8, bRequest: uint8, wValue: uint16, wIndex: uint16, wLength: uint16, buf: usb_setup_pkt | t.CPtr):
buf.bmRequestType = bmRequestType
buf.bRequest = bRequest
buf.wValue = wValue
buf.wIndex = wIndex
buf.wLength = wLength
def _send_control(dev_addr: uint8, ls: int, max_pkt: uint8, setup: usb_setup_pkt | t.CPtr, data_buf: t.CPtr, data_len: uint16, data_in: int) -> int:
return uhci.control_transfer(dev_addr, 0, ls, max_pkt, c.Addr(setup), data_buf, data_len, data_in)
def get_descriptor(dev_addr: uint8, ls: int, max_pkt: uint8, desc_type: uint8, desc_idx: uint8, buf: t.CPtr, length: uint16) -> int:
setup: usb_setup_pkt
_setup_packet(0x80, USB_REQ_GET_DESCRIPTOR, (uint16(desc_type) << 8) | desc_idx, 0, length, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), buf, length, 1)
def set_address(dev_addr: uint8, ls: int, max_pkt: uint8, new_addr: uint8) -> int:
setup: usb_setup_pkt
_setup_packet(0x00, USB_REQ_SET_ADDRESS, new_addr, 0, 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def set_configuration(dev_addr: uint8, ls: int, max_pkt: uint8, config_val: uint8) -> int:
setup: usb_setup_pkt
_setup_packet(0x00, USB_REQ_SET_CONFIGURATION, config_val, 0, 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def hid_set_protocol(dev_addr: uint8, ls: int, max_pkt: uint8, iface: uint8, protocol: uint8) -> int:
setup: usb_setup_pkt
_setup_packet(0x21, HID_REQ_SET_PROTOCOL, protocol, uint16(iface), 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def hid_set_idle(dev_addr: uint8, ls: int, max_pkt: uint8, iface: uint8, duration: uint8) -> int:
setup: usb_setup_pkt
_setup_packet(0x21, HID_REQ_SET_IDLE, uint16(duration) << 8, uint16(iface), 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def _parse_config(dev: usb_device | t.CPtr, config_buf: t.CPtr, total_len: uint16):
offset: int = 0
found_hid: int = 0
while offset < int(total_len):
p: uint8 | t.CPtr = config_buf + uint64(offset)
desc_len: uint8 = c.Deref(p)
p2: uint8 | t.CPtr = config_buf + uint64(offset) + 1
desc_type: uint8 = c.Deref(p2)
if desc_len == 0: break
# 边界:描述符整体须落在 config_buf(total_len 字节)内,且不得短于
# 所访问的结构体(interface=9 / endpoint=7),否则越界读。
if offset + int(desc_len) > int(total_len): break
if desc_type == USB_DESC_INTERFACE and int(desc_len) >= 9:
iface: usb_iface_desc | t.CPtr = config_buf + uint64(offset)
if iface.bInterfaceClass == HID_CLASS:
found_hid = 1
dev.iface_class = HID_CLASS
dev.iface_subclass = iface.bInterfaceSubClass
dev.iface_protocol = iface.bInterfaceProtocol
dev.iface_num = iface.bInterfaceNumber
if desc_type == USB_DESC_ENDPOINT and found_hid and int(desc_len) >= 7:
ep: usb_ep_desc | t.CPtr = config_buf + uint64(offset)
if (ep.bEndpointAddress & 0x80) != 0:
dev.ep_in = ep.bEndpointAddress & 0x0F
dev.ep_in_max = ep.wMaxPacketSize
dev.ep_in_interval = ep.bInterval
found_hid = 0
offset = offset + int(desc_len)
def enumerate_port(port: int) -> int:
global _device_count
if _device_count >= USB_MAX_DEVICES: return -1
ls: int = uhci.port_is_low_speed(port)
reset_ok: int = -1
reset_retry: int
for reset_retry in range(3):
if uhci.port_reset(port) == 0:
reset_ok = 0
break
timer.timer_msleep(50)
if reset_ok != 0:
return -2
timer.timer_msleep(10)
dev_buf: t.CPtr = mm.malloc(usb_dev_desc.__sizeof__())
if dev_buf is None: return -3
string.memset(dev_buf, 0, usb_dev_desc.__sizeof__())
result: int = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
retry: int
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
uhci.port_reset(port)
timer.timer_msleep(10)
result = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
if result != 0:
mm.free(dev_buf)
return -4
desc: usb_dev_desc | t.CPtr = dev_buf
max_pkt: uint8 = desc.bMaxPacketSize0
if max_pkt < 8: max_pkt = 8
new_addr: uint8 = uint8(_device_count + 1)
result = set_address(0, ls, max_pkt, new_addr)
for retry in range(3):
if result == 0: break
timer.timer_msleep(20)
result = set_address(0, ls, max_pkt, new_addr)
if result != 0:
mm.free(dev_buf)
return -5
timer.timer_msleep(10)
dev: usb_device | t.CPtr = c.Addr(_devices[_device_count])
dev.addr = new_addr
dev.ls = ls
dev.max_pkt0 = max_pkt
dev.configured = 0
dev.iface_class = 0
dev.iface_subclass = 0
dev.iface_protocol = 0
dev.ep_in = 0
dev.ep_in_max = 0
dev.ep_in_interval = 0
dev.ep_in_toggle = 0
config_buf: t.CPtr = mm.malloc(256)
if config_buf is None:
mm.free(dev_buf)
return -6
string.memset(config_buf, 0, 256)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -7
cfg: usb_config_desc | t.CPtr = config_buf
total_len: uint16 = cfg.wTotalLength
if total_len > 256: total_len = 256
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -8
_parse_config(dev, config_buf, total_len)
result = set_configuration(new_addr, ls, max_pkt, cfg.bConfigurationValue)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -9
dev.configured = 1
if dev.iface_class == HID_CLASS:
hid_set_protocol(new_addr, ls, max_pkt, dev.iface_num, 0)
hid_set_idle(new_addr, ls, max_pkt, dev.iface_num, 0)
_device_count = _device_count + 1
mm.free(config_buf)
mm.free(dev_buf)
return int(new_addr)
def init() -> int:
global _device_count
_device_count = 0
io_base: uint16 = pci.find_uhci()
if io_base == 0:
serial.puts("[usb] UHCI controller not found\n")
return -1
buf: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(buf), 64, "[usb] UHCI at I/O 0x%04X\n", uint32(io_base))
serial.puts(buf)
if uhci.init(io_base) != 0:
serial.puts("[usb] UHCI init failed\n")
return -2
serial.puts("[usb] UHCI initialized\n")
timer.timer_msleep(50)
port: int
for port in range(2):
if uhci.port_is_connected(port):
viperlib.snprintf(c.Addr(buf), 64, "[usb] port %d connected\n", uint32(port))
serial.puts(buf)
dev_id: int = enumerate_port(port)
if dev_id > 0:
dev: usb_device | t.CPtr = c.Addr(_devices[dev_id - 1])
viperlib.snprintf(c.Addr(buf), 64, "[usb] device addr=%d class=%02X proto=%02X ep=%d\n",
uint32(dev.addr), uint32(dev.iface_class),
uint32(dev.iface_protocol), uint32(dev.ep_in))
serial.puts(buf)
else:
viperlib.snprintf(c.Addr(buf), 64, "[usb] enumerate port %d failed: %d\n", uint32(port), int32(dev_id))
serial.puts(buf)
return _device_count
def find_hid_device(protocol: uint8) -> usb_device | t.CPtr:
i: int
for i in range(_device_count):
dev: usb_device | t.CPtr = c.Addr(_devices[i])
if dev.iface_class == HID_CLASS:
if dev.iface_protocol == protocol:
if dev.configured != 0:
return dev
return None
def read_interrupt(dev: usb_device | t.CPtr, buf: t.CPtr) -> int:
return 0
+22 -19
View File
@@ -5,25 +5,25 @@ import t, c
MAX_SHEETS: t.CDefine = 64
MAX_UI_COMPONENTS: t.CDefine = 256
_next_sheet_id: t.CInt = 0
_next_component_id: t.CInt = 0
_next_sheet_id: int = 0
_next_component_id: int = 0
@t.Object
class Sheet:
id: t.CInt
x: t.CInt
y: t.CInt
w: t.CInt
h: t.CInt
visible: t.CInt
id: int
x: int
y: int
w: int
h: int
visible: int
_surf_obj: gfx.Surface
_renderer_obj: gfx.Renderer
surf: gfx.Surface | t.CPtr
renderer: gfx.Renderer | t.CPtr
parent: 'Sheet | t.CPtr'
bg_color: t.CUInt32T
bg_color: uint32
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, parent: 'Sheet | t.CPtr' = None):
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, x: int, y: int, w: int, h: int, parent: 'Sheet | t.CPtr' = None):
global _next_sheet_id
self.id = _next_sheet_id
_next_sheet_id += 1
@@ -34,16 +34,19 @@ class Sheet:
self.visible = 1
self._surf_obj = gfx.Surface(fb, zb, w, h)
self.surf = c.Addr(self._surf_obj)
self._renderer_obj = gfx.Renderer(self.surf)
# gfx.Renderer.__init__(fb, zb, w, h):此前只传 self.surf(Surface*)→
# fb 被 bitcast 错位、w/h 缺省为 0 → Renderer 的 _w/_h = 0 →
# Sheet.Clear/Fill/DrawRect(走 renderer)全部空操作。按 Surface 同参构造。
self._renderer_obj = gfx.Renderer(fb, zb, w, h)
self.renderer = c.Addr(self._renderer_obj)
self.parent = parent
self.bg_color = gfx.COLOR_RGB(20, 20, 30)
def MoveTo(self, nx: t.CInt, ny: t.CInt):
def MoveTo(self, nx: int, ny: int):
self.x = nx
self.y = ny
def Resize(self, nw: t.CInt, nh: t.CInt):
def Resize(self, nw: int, nh: int):
self.w = nw
self.h = nh
@@ -57,29 +60,29 @@ class Sheet:
r: gfx.Renderer = c.Deref(self.renderer)
r.Clear(self.bg_color)
def Fill(self, color: t.CUInt32T):
def Fill(self, color: uint32):
r: gfx.Renderer = c.Deref(self.renderer)
r.Clear(color)
def DrawRect(self, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T):
def DrawRect(self, rx: int, ry: int, rw: int, rh: int, color: uint32):
r: gfx.Renderer = c.Deref(self.renderer)
r.DrawLine2D(rx, ry, rx + rw - 1, ry, color)
r.DrawLine2D(rx + rw - 1, ry, rx + rw - 1, ry + rh - 1, color)
r.DrawLine2D(rx + rw - 1, ry + rh - 1, rx, ry + rh - 1, color)
r.DrawLine2D(rx, ry + rh - 1, rx, ry, color)
def DrawFilledRect(self, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T):
def DrawFilledRect(self, rx: int, ry: int, rw: int, rh: int, color: uint32):
surf: gfx.Surface = c.Deref(self.surf)
fb: UINT32PTR = surf.fb
w: t.CInt = surf.w
h: t.CInt = surf.h
w: int = surf.w
h: int = surf.h
for py in range(ry, ry + rh):
if py < 0 or py >= h: continue
for px in range(rx, rx + rw):
if px < 0 or px >= w: continue
fb[py * w + px] = color
def Contains(self, px: t.CInt, py: t.CInt) -> t.CInt:
def Contains(self, px: int, py: int) -> int:
if px >= self.x and px < self.x + self.w and py >= self.y and py < self.y + self.h:
return 1
return 0
+29 -29
View File
@@ -11,21 +11,21 @@ UI_PROGRESS: t.CDefine = 3
@t.Object
class UIComponent:
id: t.CInt
ctype: t.CInt
x: t.CInt
y: t.CInt
w: t.CInt
h: t.CInt
visible: t.CInt
id: int
ctype: int
x: int
y: int
w: int
h: int
visible: int
sheet: sheet.Sheet | t.CPtr
fg_color: t.CUInt32T
bg_color: t.CUInt32T
fg_color: uint32
bg_color: uint32
text: t.CArray[t.CChar, 128]
text_len: t.CInt
value: t.CInt
text_len: int
value: int
def __init__(self, ctype: t.CInt, sh: sheet.Sheet | t.CPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt):
def __init__(self, ctype: int, sh: sheet.Sheet | t.CPtr, x: int, y: int, w: int, h: int):
self.id = sheet._next_component_id
sheet._next_component_id += 1
self.ctype = ctype
@@ -42,7 +42,7 @@ class UIComponent:
self.value = 0
def SetText(self, s: str):
i: t.CInt = 0
i: int = 0
for ch in s:
if i >= 127: break
self.text[i] = ch
@@ -50,7 +50,7 @@ class UIComponent:
self.text[i] = 0
self.text_len = i
def SetValue(self, v: t.CInt):
def SetValue(self, v: int):
self.value = v
def Render(self):
@@ -79,12 +79,12 @@ class UIComponent:
def _RenderProgress(self, sh: sheet.Sheet):
sh.DrawFilledRect(self.x, self.y, self.w, self.h, gfx.COLOR_RGB(30, 30, 40))
fill_w: t.CInt = self.w * self.value / 100
fill_w: int = self.w * self.value / 100
if fill_w > 0:
sh.DrawFilledRect(self.x, self.y, fill_w, self.h, gfx.COLOR_RGB(0, 180, 255))
sh.DrawRect(self.x, self.y, self.w, self.h, gfx.COLOR_RGB(80, 80, 100))
def Contains(self, px: t.CInt, py: t.CInt) -> t.CInt:
def Contains(self, px: int, py: int) -> int:
if px >= self.x and px < self.x + self.w and py >= self.y and py < self.y + self.h:
return 1
return 0
@@ -93,37 +93,37 @@ class UIComponent:
@t.Object
class UIManager:
sheets: t.CArray[sheet.Sheet | t.CPtr, 64]
sheet_count: t.CInt
sheet_count: int
components: t.CArray[UIComponent | t.CPtr, 256]
component_count: t.CInt
screen_w: t.CInt
screen_h: t.CInt
component_count: int
screen_w: int
screen_h: int
def __init__(self, w: t.CInt, h: t.CInt):
def __init__(self, w: int, h: int):
self.sheet_count = 0
self.component_count = 0
self.screen_w = w
self.screen_h = h
i: t.CInt
i: int
for i in range(64):
self.sheets[i] = None
for i in range(256):
self.components[i] = None
def AddSheet(self, sh: sheet.Sheet | t.CPtr) -> t.CInt:
def AddSheet(self, sh: sheet.Sheet | t.CPtr) -> int:
if self.sheet_count >= 64: return -1
self.sheets[self.sheet_count] = sh
self.sheet_count += 1
return 0
def AddComponent(self, comp: UIComponent | t.CPtr) -> t.CInt:
def AddComponent(self, comp: UIComponent | t.CPtr) -> int:
if self.component_count >= 256: return -1
self.components[self.component_count] = comp
self.component_count += 1
return 0
def FindComponent(self, cid: t.CInt) -> UIComponent | t.CPtr:
i: t.CInt
def FindComponent(self, cid: int) -> UIComponent | t.CPtr:
i: int
for i in range(self.component_count):
p: UIComponent | t.CPtr = self.components[i]
if p is not None:
@@ -132,15 +132,15 @@ class UIManager:
return None
def RenderAll(self):
i: t.CInt
i: int
for i in range(self.component_count):
p: UIComponent | t.CPtr = self.components[i]
if p is not None:
comp: UIComponent = c.Deref(p)
comp.Render()
def HitTest(self, px: t.CInt, py: t.CInt) -> UIComponent | t.CPtr:
i: t.CInt = self.component_count - 1
def HitTest(self, px: int, py: int) -> UIComponent | t.CPtr:
i: int = self.component_count - 1
while i >= 0:
p: UIComponent | t.CPtr = self.components[i]
if p is not None:
+12 -12
View File
@@ -10,7 +10,7 @@ SPHERE_SLICES: t.CDefine = (24 * 1)
SPHERE_STACKS: t.CDefine = (16 * 1)
SIN_WAVE_GRID: t.CDefine = (40 * 1)
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | t.CInt:
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | int:
return (255 << 24) | (r << 16) | (g << 8) | (b)
@t.Object
@@ -115,7 +115,7 @@ class Renderer:
self._w = w
self._h = h
def Clear(self, color: t.CUInt32T):
def Clear(self, color: uint32):
fb: UINT32PTR = self._fb
zb: float | t.CPtr = self._zb
size: int = self._w * self._h
@@ -123,7 +123,7 @@ class Renderer:
fb[i] = color
zb[i] = float(1.0)
def DrawLine2D(self, x0: int, y0: int, x1: int, y1: int, col: t.CUInt32T):
def DrawLine2D(self, x0: int, y0: int, x1: int, y1: int, col: uint32):
fb: UINT32PTR = self._fb
w: int = self._w; h: int = self._h
dx: int = abs(x1-x0); dy: int = abs(y1-y0)
@@ -136,7 +136,7 @@ class Renderer:
if e2 > -dy: err -= dy; x0 += sx
if e2 < dx: err += dx; y0 += sy
def DrawTriangle(self, v0: Vec3, v1: Vec3, v2: Vec3, col: t.CUInt32T):
def DrawTriangle(self, v0: Vec3, v1: Vec3, v2: Vec3, col: uint32):
if v0.z < float(0.0) or v1.z < float(0.0) or v2.z < float(0.0): return
if (v0.x > float(10.0) or v0.x < float(-10.0) or v0.y > float(10.0) or v0.y < float(-10.0) or
v1.x > float(10.0) or v1.x < float(-10.0) or v1.y > float(10.0) or v1.y < float(-10.0) or
@@ -179,7 +179,7 @@ class Renderer:
fb[idx] = col
dxP += float(1.0)
def DrawGlowDot(self, x: float, y: float, radius: float, core_col: t.CUInt32T, intensity: float):
def DrawGlowDot(self, x: float, y: float, radius: float, core_col: uint32, intensity: float):
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
r: int = int(radius) + 4
ix: int = int(x); iy: int = int(y)
@@ -196,13 +196,13 @@ class Renderer:
fade: float = 1.0 - (dist - radius) / 4.0
self.BlendPixel(px, py, core_col, intensity * fade * 0.5)
def BlendPixel(self, x: int, y: int, col: t.CUInt32T, alpha: float):
def BlendPixel(self, x: int, y: int, col: uint32, alpha: float):
if alpha <= 0.0: return
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
if x < 0 or x >= w or y < 0 or y >= h: return
idx: int = y * w + x
bg: t.CUInt32T = fb[idx]
bg: uint32 = fb[idx]
bg_b: int = bg & 0xFF; bg_g: int = (bg >> 8) & 0xFF; bg_r: int = (bg >> 16) & 0xFF
f_b: int = col & 0xFF; f_g: int = (col >> 8) & 0xFF; f_r: int = (col >> 16) & 0xFF
@@ -240,7 +240,7 @@ class Scene3D:
cubeMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(cubeX, 0, 0))
self._DrawCube(cubeMVP, COLOR_RGB(180, 180, 180))
colors: t.CArray[t.CUInt32T, 4] = [COLOR_RGB(255,50,50), COLOR_RGB(50,50,255), COLOR_RGB(255,255,50), COLOR_RGB(50,255,255)]
colors: t.CArray[uint32, 4] = [COLOR_RGB(255,50,50), COLOR_RGB(50,50,255), COLOR_RGB(255,255,50), COLOR_RGB(50,255,255)]
for i in range(4):
a: float = time * float(1.5) + i * (PI / float(2.0)); r: float = float(3.0)
pos: Vec3 = Vec3(vipermath.cosf(a) * r + cubeX, 0, vipermath.sinf(a) * r)
@@ -259,7 +259,7 @@ class Scene3D:
self.renderer.DrawLine2D(prev_x, prev_y, cx, cy, COLOR_RGB(0, 255, 100))
prev_x = cx; prev_y = cy
def _DrawCube(self, mvp: Mat4, col: t.CUInt32T):
def _DrawCube(self, mvp: Mat4, col: uint32):
v: t.CArray[Vec3, 8] = [
Vec3(-1, -1, -1), Vec3(-1, -1, 1), Vec3(-1, 1, -1), Vec3(-1, 1, 1),
Vec3( 1, -1, -1), Vec3( 1, -1, 1), Vec3( 1, 1, -1), Vec3( 1, 1, 1)
@@ -271,7 +271,7 @@ class Scene3D:
]
for i in range(12): self.renderer.DrawTriangle(v[faces[i][0]], v[faces[i][1]], v[faces[i][2]], col)
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: t.CUInt32T):
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: uint32):
step_pi: float = PI / SPHERE_STACKS; step_2pi: float = float(2.0) * PI / SPHERE_SLICES
for i in range(SPHERE_STACKS):
for j in range(SPHERE_SLICES):
@@ -296,9 +296,9 @@ class Scene3D:
y01: float = vipermath.sinf(x0) * vipermath.cosf(z1) * scale; y11: float = vipermath.sinf(x1) * vipermath.cosf(z1) * scale
t1: float = (y00 / scale + float(1.0)) * float(0.5); r1: int = int(50 + 205 * t1); g1: int = int(80 + 120 * vipermath.sinf(t1 * PI)); b1: int = int(255 - 205 * t1)
col1: t.CUInt32T = COLOR_RGB(255 if (r1 > 255) else (0 if (r1 < 0) else r1), 255 if (g1 > 255) else (0 if (g1 < 0) else g1), 255 if (b1 > 255) else (0 if (b1 < 0) else b1))
col1: uint32 = COLOR_RGB(255 if (r1 > 255) else (0 if (r1 < 0) else r1), 255 if (g1 > 255) else (0 if (g1 < 0) else g1), 255 if (b1 > 255) else (0 if (b1 < 0) else b1))
t2: float = (y11 / scale + float(1.0)) * float(0.5); r2: int = int(50 + 205 * t2); g2: int = int(80 + 120 * vipermath.sinf(t2 * PI)); b2: int = int(255 - 205 * t2)
col2: t.CUInt32T = COLOR_RGB(255 if (r2 > 255) else (0 if (r2 < 0) else r2), 255 if (g2 > 255) else (0 if (g2 < 0) else g2), 255 if (b2 > 255) else (0 if (b2 < 0) else b2))
col2: uint32 = COLOR_RGB(255 if (r2 > 255) else (0 if (r2 < 0) else r2), 255 if (g2 > 255) else (0 if (g2 < 0) else g2), 255 if (b2 > 255) else (0 if (b2 < 0) else b2))
v00: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y00, z0)); v10: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y10, z0))
v01: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y01, z1)); v11: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y11, z1))
+8 -8
View File
@@ -19,7 +19,7 @@ DEFAULT_CHAR: t.CDefine = 0 # 非ASCII字符的默认替换字符
SERIAL_PORT: t.CDefine = 0x3F8 # 串口调试端口地址
# 8x16字符点阵字库 (每个字符16字节,共256个字符)
font: t.CArray[t.CArray[t.CUInt8T, 16], 256] = [
font: t.CArray[t.CArray[uint8, 16], 256] = [
# 字符编号 0x00 - 0x0F
{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x00
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x01
@@ -312,7 +312,7 @@ font: t.CArray[t.CArray[t.CUInt8T, 16], 256] = [
@t.Object
class _VGAScreenDriver:
# 帧缓冲区信息
fbv: t.CVoid | t.CPtr # = None
fbv: t.CPtr # = None
fb: t.CUnsignedChar | t.CPtr # = None
fw: int # = 800
fh: int # = 600
@@ -321,7 +321,7 @@ class _VGAScreenDriver:
BgColor: t.CUnsignedInt = 0xFF000080 # RGBA: 不透明深蓝色
# 初始化VGA驱动
def __init__(self, fb: t.CVoid | t.CPtr, width: int, height: int, pitch: int, format: int):
def __init__(self, fb: t.CPtr, width: int, height: int, pitch: int, format: int):
# 先做参数合法性检查
if fb is None or width <= 0 or height <= 0 or pitch <= 0: return
# 更新帧缓冲区参数
@@ -350,7 +350,7 @@ class _VGAScreenDriver:
testY: int = 0
offset: int = testY * self.fp + testX * 4
# 保存测试位置原始像素值,避免污染屏幕
OriginalPixel: t.CUInt32T = c.Deref(t.CUInt32T(fb + offset, t.CPtr))
OriginalPixel: uint32 = c.Deref(uint32(fb + offset, t.CPtr))
# 写入测试颜色:青色 (RGBA逻辑值: 0xFF00FFFF)
fb[offset + 0] = 0xFF # B
fb[offset + 1] = 0xFF # G
@@ -362,7 +362,7 @@ class _VGAScreenDriver:
r: t.CUnsignedChar = fb[offset + 2]
# t.CVoid(fb[offset + 3]) # 忽略Alpha
# 恢复原始像素
c.Set(c.Deref(t.CUInt32T(fb + offset, t.CPtr)), OriginalPixel)
c.Set(c.Deref(uint32(fb + offset, t.CPtr)), OriginalPixel)
# 判定颜色格式
if r == 0x00 and g == 0xFF and b == 0xFF: self.ColorFormat = __ColorFormat.ColorFormat_BGRA
elif r == 0xFF and g == 0xFF and b == 0x00: self.ColorFormat = __ColorFormat.ColorFormat_RGBA
@@ -370,7 +370,7 @@ class _VGAScreenDriver:
# 设置像素颜色 - 统一接口,输入为RGBA逻辑颜色
# color格式: 0xAARRGGBB (Alpha, Red, Green, Blue)
def SetPixel(self, x: int, y: int, color: t.CUInt32T):
def SetPixel(self, x: int, y: int, color: uint32):
fb: t.CUnsignedChar | t.CPtr = self.fb
if fb is None: return
if x < 0 or x >= self.fw or y < 0 or y >= self.fh: return
@@ -408,7 +408,7 @@ class _VGAScreenDriver:
fb[offset + 3] = a
# 清除屏幕 - 优化循环效率,减少函数调用开销
def ClearScreen(self, color: t.CUInt32T):
def ClearScreen(self, color: uint32):
fb: t.CUnsignedChar | t.CPtr = self.fb
fp: int = self.fp
if fb is None: return
@@ -458,7 +458,7 @@ class _VGAScreenDriver:
ch: t.CUnsignedChar = t.CUnsignedChar(cr)
if ch >= 128: ch = DEFAULT_CHAR
# 预解析背景色Alpha,避免内层循环重复计算
bg_alpha: t.CUInt8T = (bgcolor >> 24) & 0xFF
bg_alpha: uint8 = (bgcolor >> 24) & 0xFF
draw_bg: int = (bg_alpha != 0) # 背景是否需要绘制
# 渲染8x16点阵字符
for fy in range(FONT_HEIGHT):
File diff suppressed because it is too large. Load diff
+142 -142
View File
@@ -1,142 +1,142 @@
import t, c
@c.Attribute(t.attr.packed)
class gdt_entry:
limit_low: t.CUInt16T
base_low: t.CUInt16T
base_middle: t.CUInt8T
access: t.CUInt8T
granularity: t.CUInt8T
base_high: t.CUInt8T
@c.Attribute(t.attr.packed)
class gdt_entry64:
limit_low: t.CUInt16T
base_low: t.CUInt16T
base_middle: t.CUInt8T
access: t.CUInt8T
granularity: t.CUInt8T
base_high: t.CUInt8T
base_upper: t.CUInt32T
reserved: t.CUInt32T
@c.Attribute(t.attr.packed)
class gdt_ptr:
limit: t.CUInt16T
base: t.CUInt64T
gdt: t.CArray[gdt_entry, 7] | t.CExport = []
gp: t.CArray[t.CUInt8T, 10] | t.CExport
# TSS buffer: 104 bytes, raw byte array to avoid packed struct issues
# x86_64 TSS layout: reserved0(4) rsp0(8) rsp1(8) rsp2(8) reserved1(8) ist1-ist7(56) reserved2(8) reserved3(2) iomap_base(2)
tss_buf: t.CArray[t.CUInt8T, 104]
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
DATA_SEG: t.CDefine | t.CUInt16T = 0x10
USER_CODE_SEG: t.CDefine | t.CUInt16T = 0x18
USER_DATA_SEG: t.CDefine | t.CUInt16T = 0x20
TSS_SEG: t.CDefine | t.CUInt16T = 0x28
def init():
global gp, gdt, tss_buf
gdt[0].limit_low = 0
gdt[0].base_low = 0
gdt[0].base_middle = 0
gdt[0].access = 0
gdt[0].granularity = 0
gdt[0].base_high = 0
gdt[1].limit_low = 0
gdt[1].base_low = 0
gdt[1].base_middle = 0
gdt[1].access = 0x9A
gdt[1].granularity = 0x20
gdt[1].base_high = 0
gdt[2].limit_low = 0
gdt[2].base_low = 0
gdt[2].base_middle = 0
gdt[2].access = 0x92
gdt[2].granularity = 0xCF
gdt[2].base_high = 0
gdt[3].limit_low = 0
gdt[3].base_low = 0
gdt[3].base_middle = 0
gdt[3].access = 0xFA
gdt[3].granularity = 0x20
gdt[3].base_high = 0
gdt[4].limit_low = 0
gdt[4].base_low = 0
gdt[4].base_middle = 0
gdt[4].access = 0xF2
gdt[4].granularity = 0xCF
gdt[4].base_high = 0
# Set up TSS descriptor in GDT entries 5-6 (selector 0x28)
setTSS64(5, t.CUInt64T(c.Addr(tss_buf)), 103)
c.Asm("""lea rax, [rip + gdt]
lea rcx, [rip + gp]
mov word ptr [rcx], 0x37
mov qword ptr [rcx+2], rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX])
c.Asm("sfence; mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
flush()
# Initialize TSS: set iomap_base = 104 (0x68) at offset 102
tss_buf[102] = 0x68
tss_buf[103] = 0x00
# Load Task Register with TSS selector 0x28
c.Asm("""mov ax, 0x28
ltr ax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
@c.Attribute(t.attr.naked)
def flush():
c.Asm("""lea rax, [rip + gp]
lgdt [rax]
push 0x08
lea rax, [rip+2f]
push rax
.byte 0x48, 0xcb
2:
mov eax, 0x10
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
ret""", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
def set_tss_rsp0(rsp0: t.CUInt64T):
global tss_buf
# TSS RSP0 is at offset 4 (8 bytes) in x86_64 TSS layout
tss_buf[4] = t.CUInt8T(rsp0 & 0xFF)
tss_buf[5] = t.CUInt8T((rsp0 >> 8) & 0xFF)
tss_buf[6] = t.CUInt8T((rsp0 >> 16) & 0xFF)
tss_buf[7] = t.CUInt8T((rsp0 >> 24) & 0xFF)
tss_buf[8] = t.CUInt8T((rsp0 >> 32) & 0xFF)
tss_buf[9] = t.CUInt8T((rsp0 >> 40) & 0xFF)
tss_buf[10] = t.CUInt8T((rsp0 >> 48) & 0xFF)
tss_buf[11] = t.CUInt8T((rsp0 >> 56) & 0xFF)
def setGate(num: int, base: t.CUInt64T, limit: t.CUInt32T, access: t.CUInt8T, gran: t.CUInt8T):
global gdt
gdt[num].limit_low = (limit & 0xFFFF)
gdt[num].base_low = (base & 0xFFFF)
gdt[num].base_middle = (base >> 16) & 0xFF
gdt[num].base_high = (base >> 24) & 0xFF
gdt[num].granularity = ((limit >> 16) & 0x0F) | (gran & 0xF0)
gdt[num].access = access
def setTSS64(num: int, base: t.CUInt64T, limit: t.CUInt32T):
global gdt
gdt[num].limit_low = limit & 0xFFFF
gdt[num].base_low = base & 0xFFFF
gdt[num].base_middle = (base >> 16) & 0xFF
gdt[num].access = 0x89
gdt[num].granularity = 0x00
gdt[num].base_high = (base >> 24) & 0xFF
gdt[num + 1].limit_low = (base >> 32) & 0xFFFF
gdt[num + 1].base_low = (base >> 48) & 0xFFFF
gdt[num + 1].base_middle = 0
gdt[num + 1].access = 0
gdt[num + 1].granularity = 0
gdt[num + 1].base_high = 0
import t, c
@c.Attribute(t.attr.packed)
class gdt_entry:
limit_low: uint16
base_low: uint16
base_middle: uint8
access: uint8
granularity: uint8
base_high: uint8
@c.Attribute(t.attr.packed)
class gdt_entry64:
limit_low: uint16
base_low: uint16
base_middle: uint8
access: uint8
granularity: uint8
base_high: uint8
base_upper: uint32
reserved: uint32
@c.Attribute(t.attr.packed)
class gdt_ptr:
limit: uint16
base: uint64
gdt: t.CArray[gdt_entry, 7] | t.CExport = []
gp: t.CArray[uint8, 10] | t.CExport
# TSS buffer: 104 bytes, raw byte array to avoid packed struct issues
# x86_64 TSS layout: reserved0(4) rsp0(8) rsp1(8) rsp2(8) reserved1(8) ist1-ist7(56) reserved2(8) reserved3(2) iomap_base(2)
tss_buf: t.CArray[uint8, 104]
CODE_SEG: t.CDefine | uint16 = 0x08
DATA_SEG: t.CDefine | uint16 = 0x10
USER_CODE_SEG: t.CDefine | uint16 = 0x18
USER_DATA_SEG: t.CDefine | uint16 = 0x20
TSS_SEG: t.CDefine | uint16 = 0x28
def init():
global gp, gdt, tss_buf
gdt[0].limit_low = 0
gdt[0].base_low = 0
gdt[0].base_middle = 0
gdt[0].access = 0
gdt[0].granularity = 0
gdt[0].base_high = 0
gdt[1].limit_low = 0
gdt[1].base_low = 0
gdt[1].base_middle = 0
gdt[1].access = 0x9A
gdt[1].granularity = 0x20
gdt[1].base_high = 0
gdt[2].limit_low = 0
gdt[2].base_low = 0
gdt[2].base_middle = 0
gdt[2].access = 0x92
gdt[2].granularity = 0xCF
gdt[2].base_high = 0
gdt[3].limit_low = 0
gdt[3].base_low = 0
gdt[3].base_middle = 0
gdt[3].access = 0xFA
gdt[3].granularity = 0x20
gdt[3].base_high = 0
gdt[4].limit_low = 0
gdt[4].base_low = 0
gdt[4].base_middle = 0
gdt[4].access = 0xF2
gdt[4].granularity = 0xCF
gdt[4].base_high = 0
# Set up TSS descriptor in GDT entries 5-6 (selector 0x28)
setTSS64(5, uint64(c.Addr(tss_buf)), 103)
c.Asm("""lea rax, [rip + gdt]
lea rcx, [rip + gp]
mov word ptr [rcx], 0x37
mov qword ptr [rcx+2], rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX])
c.Asm("sfence; mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
flush()
# Initialize TSS: set iomap_base = 104 (0x68) at offset 102
tss_buf[102] = 0x68
tss_buf[103] = 0x00
# Load Task Register with TSS selector 0x28
c.Asm("""mov ax, 0x28
ltr ax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
@c.Attribute(t.attr.naked)
def flush():
c.Asm("""lea rax, [rip + gp]
lgdt [rax]
push 0x08
lea rax, [rip+2f]
push rax
.byte 0x48, 0xcb
2:
mov eax, 0x10
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
ret""", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
def set_tss_rsp0(rsp0: uint64):
global tss_buf
# TSS RSP0 is at offset 4 (8 bytes) in x86_64 TSS layout
tss_buf[4] = uint8(rsp0 & 0xFF)
tss_buf[5] = uint8((rsp0 >> 8) & 0xFF)
tss_buf[6] = uint8((rsp0 >> 16) & 0xFF)
tss_buf[7] = uint8((rsp0 >> 24) & 0xFF)
tss_buf[8] = uint8((rsp0 >> 32) & 0xFF)
tss_buf[9] = uint8((rsp0 >> 40) & 0xFF)
tss_buf[10] = uint8((rsp0 >> 48) & 0xFF)
tss_buf[11] = uint8((rsp0 >> 56) & 0xFF)
def setGate(num: int, base: uint64, limit: uint32, access: uint8, gran: uint8):
global gdt
gdt[num].limit_low = (limit & 0xFFFF)
gdt[num].base_low = (base & 0xFFFF)
gdt[num].base_middle = (base >> 16) & 0xFF
gdt[num].base_high = (base >> 24) & 0xFF
gdt[num].granularity = ((limit >> 16) & 0x0F) | (gran & 0xF0)
gdt[num].access = access
def setTSS64(num: int, base: uint64, limit: uint32):
global gdt
gdt[num].limit_low = limit & 0xFFFF
gdt[num].base_low = base & 0xFFFF
gdt[num].base_middle = (base >> 16) & 0xFF
gdt[num].access = 0x89
gdt[num].granularity = 0x00
gdt[num].base_high = (base >> 24) & 0xFF
gdt[num + 1].limit_low = (base >> 32) & 0xFFFF
gdt[num + 1].base_low = (base >> 48) & 0xFFFF
gdt[num + 1].base_middle = 0
gdt[num + 1].access = 0
gdt[num + 1].granularity = 0
gdt[num + 1].base_high = 0
+95 -88
View File
@@ -7,20 +7,20 @@ import viperlib
import asm
import t, c
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
CODE_SEG: t.CDefine | uint16 = 0x08
@c.Attribute(t.attr.packed)
class idt_entry:
base_low: t.CUInt16T
selector: t.CUInt16T
ist_attr: t.CUInt8T
type_attr: t.CUInt8T
base_middle: t.CUInt16T
base_high: t.CUInt32T
reserved1: t.CUInt32T
base_low: uint16
selector: uint16
ist_attr: uint8
type_attr: uint8
base_middle: uint16
base_high: uint32
reserved1: uint32
idt: t.CArray[idt_entry, 256] | t.CExport = []
irq_handler_t: t.CTypedef = t.Callable[[], t.CInt]
irq_handler_t: t.CTypedef = t.Callable[[], int]
def isr0() -> t.State: pass
def isr1() -> t.State: pass
@@ -75,7 +75,7 @@ def isr80() -> t.State: pass
def isr_default() -> t.State: pass
def setGate(num: int, base: t.CUInt64T, sel: t.CUInt16T, flags: t.CUInt8T):
def setGate(num: int, base: uint64, sel: uint16, flags: uint8):
global idt
idt[num].base_low = (base & 0xFFFF)
idt[num].base_middle = (base >> 16) & 0xFFFF
@@ -85,7 +85,7 @@ def setGate(num: int, base: t.CUInt64T, sel: t.CUInt16T, flags: t.CUInt8T):
idt[num].type_attr = flags
idt[num].reserved1 = 0
def isrCommonhandler(interrupt: t.CInt):
def isrCommonhandler(interrupt: int):
c.Asm(f"""mov dx, 0x3F8
mov al, 91
out dx, al
@@ -112,12 +112,12 @@ def isrCommonhandler(interrupt: t.CInt):
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
# Print CR2 for page faults (ISR 14)
if interrupt == 14:
cr2: t.CUInt64T = 0
cr2: uint64 = 0
c.Asm(f"""mov {c.AsmOut(cr2, t.ASM_DESCR.OUTPUT_REG)}, cr2""",
op=[t.ASM_DESCR.CLOBBER_RAX])
fault_rip: t.CUInt64T = 0
fault_err: t.CUInt64T = 0
fault_rsp: t.CUInt64T = 0
fault_rip: uint64 = 0
fault_err: uint64 = 0
fault_rsp: uint64 = 0
c.Asm(f"""mov {c.AsmOut(fault_rip, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rip]
mov {c.AsmOut(fault_err, t.ASM_DESCR.OUTPUT_REG)}, [_fault_err]
mov {c.AsmOut(fault_rsp, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rsp]""",
@@ -128,14 +128,14 @@ def isrCommonhandler(interrupt: t.CInt):
# [CR3] 当前 pml4:定位栈区/对象写缺页是否因 pml4 被 switch_pid 切走
# (内核 pml4=0xf801000,用户 pml4=0x9781xxx —— 若显示用户 pml4 而 rsp
# 在 bootloader 栈区 0x60000-0x80000,则是进程切换后未切回内核页表)。
cur_cr3: t.CUInt64T = 0
cur_cr3: uint64 = 0
c.Asm(f"mov {c.AsmOut(cur_cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3",
op=[t.ASM_DESCR.CLOBBER_RAX])
cr3_buf: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr3_buf), 80, "[CR3] pml4=0x%lx\n", cur_cr3)
serial.puts(cr3_buf)
# [RAX] 崩溃时 rax(isr.s 保存):定位 cr2 与 rax 关系(rax-偏移=cr2)
f_rax: t.CUInt64T = 0
f_rax: uint64 = 0
c.Asm(f"""mov {c.AsmOut(f_rax, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rax]""",
op=[t.ASM_DESCR.CLOBBER_RAX])
rax_buf: t.CArray[t.CChar, 80]
@@ -143,7 +143,7 @@ def isrCommonhandler(interrupt: t.CInt):
serial.puts(rax_buf)
# [STK] rbp 链回溯(定位栈损坏源:崩溃帧 + 4 级调用链的返回地址)
# 先读崩溃 rbp 判断(用户 rbp 不回溯,避免读用户地址嵌套 #PF)
fr0: t.CUInt64T = 0
fr0: uint64 = 0
c.Asm(f"""mov rax, [_fault_rbp]
mov {c.AsmOut(fr0, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
@@ -153,10 +153,10 @@ def isrCommonhandler(interrupt: t.CInt):
viperlib.snprintf(c.Addr(stk_buf), 160, "[STK] user rbp=0x%lx, chain skipped\n", fr0)
serial.puts(stk_buf)
else:
fr1: t.CUInt64T = 0
fr2: t.CUInt64T = 0
fr3: t.CUInt64T = 0
fr4: t.CUInt64T = 0
fr1: uint64 = 0
fr2: uint64 = 0
fr3: uint64 = 0
fr4: uint64 = 0
c.Asm(f"""mov rax, [_fault_rbp]
mov rax, [rax + 8]
mov {c.AsmOut(fr1, t.ASM_DESCR.OUTPUT_REG)}, rax
@@ -175,11 +175,11 @@ def isrCommonhandler(interrupt: t.CInt):
fr0, fr1, fr2, fr3, fr4)
serial.puts(stk_buf)
elif interrupt == 13:
gp_rip: t.CUInt64T = 0
gp_err: t.CUInt64T = 0
gp_rsp: t.CUInt64T = 0
gp_cr4: t.CUInt64T = 0
gp_cr0: t.CUInt64T = 0
gp_rip: uint64 = 0
gp_err: uint64 = 0
gp_rsp: uint64 = 0
gp_cr4: uint64 = 0
gp_cr0: uint64 = 0
c.Asm(f"""mov {c.AsmOut(gp_rip, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rip]
mov {c.AsmOut(gp_err, t.ASM_DESCR.OUTPUT_REG)}, [_fault_err]
mov {c.AsmOut(gp_rsp, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rsp]
@@ -194,8 +194,8 @@ def isrCommonhandler(interrupt: t.CInt):
serial.puts(gp_buf)
else:
# 其他异常(#UD 等):打印 rip/rsp 定位执行位置(isr.s 已保存 _fault_rip)
ex_rip: t.CUInt64T = 0
ex_rsp: t.CUInt64T = 0
ex_rip: uint64 = 0
ex_rsp: uint64 = 0
c.Asm(f"""mov {c.AsmOut(ex_rip, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rip]
mov {c.AsmOut(ex_rsp, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rsp]""",
op=[t.ASM_DESCR.CLOBBER_RAX])
@@ -203,18 +203,18 @@ def isrCommonhandler(interrupt: t.CInt):
viperlib.snprintf(c.Addr(ex_buf), 100, "[EX] int=%d rip=0x%lx rsp=0x%lx\n", interrupt, ex_rip, ex_rsp)
serial.puts(ex_buf)
# [RAX] 崩溃时 rax(isr.s 保存)
f_rax: t.CUInt64T = 0
f_rax: uint64 = 0
c.Asm(f"""mov {c.AsmOut(f_rax, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rax]""",
op=[t.ASM_DESCR.CLOBBER_RAX])
rax_buf: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(rax_buf), 80, "[RAX] rax=0x%lx\n", f_rax)
serial.puts(rax_buf)
# [STK] rbp 链回溯(与 #PF 分支一致,定位栈损坏源)
fr0: t.CUInt64T = 0
fr1: t.CUInt64T = 0
fr2: t.CUInt64T = 0
fr3: t.CUInt64T = 0
fr4: t.CUInt64T = 0
fr0: uint64 = 0
fr1: uint64 = 0
fr2: uint64 = 0
fr3: uint64 = 0
fr4: uint64 = 0
c.Asm(f"""mov rax, [_fault_rbp]
mov {c.AsmOut(fr0, t.ASM_DESCR.OUTPUT_REG)}, rax
mov rax, [rax + 8]
@@ -246,13 +246,20 @@ def isrCommonhandler(interrupt: t.CInt):
asm.sti()
asm.hlt()
pass
tid: t.CInt = s.current_tid
tid: int = s.current_tid
if tid == 0:
serial.puts(" KERNEL PANIC\n")
while True:
asm.sti()
asm.hlt()
pass
# s.threads 为 [16 x Thread](sched.MAX_THREADS),越界写会破坏调度器状态
if tid < 0 or tid >= 16:
serial.puts(" KERNEL PANIC (bad tid)\n")
while True:
asm.sti()
asm.hlt()
pass
buf2: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(buf2), 64, " exc in tid=%d, terminating\n", tid)
serial.puts(buf2)
@@ -460,78 +467,78 @@ def isr47_handler() -> t.CExport | t.CVoid:
apic.eoi()
def init_exceptions():
setGate(0, t.CUInt64T(isr0), CODE_SEG, 0x8E)
setGate(1, t.CUInt64T(isr1), CODE_SEG, 0x8E)
setGate(2, t.CUInt64T(isr2), CODE_SEG, 0x8E)
setGate(3, t.CUInt64T(isr3), CODE_SEG, 0x8E)
setGate(4, t.CUInt64T(isr4), CODE_SEG, 0x8E)
setGate(5, t.CUInt64T(isr5), CODE_SEG, 0x8E)
setGate(6, t.CUInt64T(isr6), CODE_SEG, 0x8E)
setGate(7, t.CUInt64T(isr7), CODE_SEG, 0x8E)
setGate(8, t.CUInt64T(isr8), CODE_SEG, 0x8E)
setGate(9, t.CUInt64T(isr9), CODE_SEG, 0x8E)
setGate(10, t.CUInt64T(isr10), CODE_SEG, 0x8E)
setGate(11, t.CUInt64T(isr11), CODE_SEG, 0x8E)
setGate(12, t.CUInt64T(isr12), CODE_SEG, 0x8E)
setGate(13, t.CUInt64T(isr13), CODE_SEG, 0x8E)
setGate(14, t.CUInt64T(isr14), CODE_SEG, 0x8E)
setGate(15, t.CUInt64T(isr15), CODE_SEG, 0x8E)
setGate(16, t.CUInt64T(isr16), CODE_SEG, 0x8E)
setGate(17, t.CUInt64T(isr17), CODE_SEG, 0x8E)
setGate(18, t.CUInt64T(isr18), CODE_SEG, 0x8E)
setGate(19, t.CUInt64T(isr19), CODE_SEG, 0x8E)
setGate(20, t.CUInt64T(isr20), CODE_SEG, 0x8E)
setGate(21, t.CUInt64T(isr21), CODE_SEG, 0x8E)
setGate(22, t.CUInt64T(isr22), CODE_SEG, 0x8E)
setGate(23, t.CUInt64T(isr23), CODE_SEG, 0x8E)
setGate(24, t.CUInt64T(isr24), CODE_SEG, 0x8E)
setGate(25, t.CUInt64T(isr25), CODE_SEG, 0x8E)
setGate(26, t.CUInt64T(isr26), CODE_SEG, 0x8E)
setGate(27, t.CUInt64T(isr27), CODE_SEG, 0x8E)
setGate(28, t.CUInt64T(isr28), CODE_SEG, 0x8E)
setGate(29, t.CUInt64T(isr29), CODE_SEG, 0x8E)
setGate(30, t.CUInt64T(isr30), CODE_SEG, 0x8E)
setGate(31, t.CUInt64T(isr31), CODE_SEG, 0x8E)
setGate(0, uint64(isr0), CODE_SEG, 0x8E)
setGate(1, uint64(isr1), CODE_SEG, 0x8E)
setGate(2, uint64(isr2), CODE_SEG, 0x8E)
setGate(3, uint64(isr3), CODE_SEG, 0x8E)
setGate(4, uint64(isr4), CODE_SEG, 0x8E)
setGate(5, uint64(isr5), CODE_SEG, 0x8E)
setGate(6, uint64(isr6), CODE_SEG, 0x8E)
setGate(7, uint64(isr7), CODE_SEG, 0x8E)
setGate(8, uint64(isr8), CODE_SEG, 0x8E)
setGate(9, uint64(isr9), CODE_SEG, 0x8E)
setGate(10, uint64(isr10), CODE_SEG, 0x8E)
setGate(11, uint64(isr11), CODE_SEG, 0x8E)
setGate(12, uint64(isr12), CODE_SEG, 0x8E)
setGate(13, uint64(isr13), CODE_SEG, 0x8E)
setGate(14, uint64(isr14), CODE_SEG, 0x8E)
setGate(15, uint64(isr15), CODE_SEG, 0x8E)
setGate(16, uint64(isr16), CODE_SEG, 0x8E)
setGate(17, uint64(isr17), CODE_SEG, 0x8E)
setGate(18, uint64(isr18), CODE_SEG, 0x8E)
setGate(19, uint64(isr19), CODE_SEG, 0x8E)
setGate(20, uint64(isr20), CODE_SEG, 0x8E)
setGate(21, uint64(isr21), CODE_SEG, 0x8E)
setGate(22, uint64(isr22), CODE_SEG, 0x8E)
setGate(23, uint64(isr23), CODE_SEG, 0x8E)
setGate(24, uint64(isr24), CODE_SEG, 0x8E)
setGate(25, uint64(isr25), CODE_SEG, 0x8E)
setGate(26, uint64(isr26), CODE_SEG, 0x8E)
setGate(27, uint64(isr27), CODE_SEG, 0x8E)
setGate(28, uint64(isr28), CODE_SEG, 0x8E)
setGate(29, uint64(isr29), CODE_SEG, 0x8E)
setGate(30, uint64(isr30), CODE_SEG, 0x8E)
setGate(31, uint64(isr31), CODE_SEG, 0x8E)
def init_irqs():
setGate(32, t.CUInt64T(isr32), CODE_SEG, 0x8E)
setGate(33, t.CUInt64T(isr33), CODE_SEG, 0x8E)
setGate(34, t.CUInt64T(isr34), CODE_SEG, 0x8E)
setGate(35, t.CUInt64T(isr35), CODE_SEG, 0x8E)
setGate(36, t.CUInt64T(isr36), CODE_SEG, 0x8E)
setGate(37, t.CUInt64T(isr37), CODE_SEG, 0x8E)
setGate(38, t.CUInt64T(isr38), CODE_SEG, 0x8E)
setGate(39, t.CUInt64T(isr39), CODE_SEG, 0x8E)
setGate(40, t.CUInt64T(isr40), CODE_SEG, 0x8E)
setGate(41, t.CUInt64T(isr41), CODE_SEG, 0x8E)
setGate(42, t.CUInt64T(isr42), CODE_SEG, 0x8E)
setGate(43, t.CUInt64T(isr43), CODE_SEG, 0x8E)
setGate(44, t.CUInt64T(isr44), CODE_SEG, 0x8E)
setGate(45, t.CUInt64T(isr45), CODE_SEG, 0x8E)
setGate(46, t.CUInt64T(isr46), CODE_SEG, 0x8E)
setGate(47, t.CUInt64T(isr47), CODE_SEG, 0x8E)
setGate(32, uint64(isr32), CODE_SEG, 0x8E)
setGate(33, uint64(isr33), CODE_SEG, 0x8E)
setGate(34, uint64(isr34), CODE_SEG, 0x8E)
setGate(35, uint64(isr35), CODE_SEG, 0x8E)
setGate(36, uint64(isr36), CODE_SEG, 0x8E)
setGate(37, uint64(isr37), CODE_SEG, 0x8E)
setGate(38, uint64(isr38), CODE_SEG, 0x8E)
setGate(39, uint64(isr39), CODE_SEG, 0x8E)
setGate(40, uint64(isr40), CODE_SEG, 0x8E)
setGate(41, uint64(isr41), CODE_SEG, 0x8E)
setGate(42, uint64(isr42), CODE_SEG, 0x8E)
setGate(43, uint64(isr43), CODE_SEG, 0x8E)
setGate(44, uint64(isr44), CODE_SEG, 0x8E)
setGate(45, uint64(isr45), CODE_SEG, 0x8E)
setGate(46, uint64(isr46), CODE_SEG, 0x8E)
setGate(47, uint64(isr47), CODE_SEG, 0x8E)
irq_handlers: t.CStatic | t.CArray[irq_handler_t, 16] = [None]
def irqInstallHandler(irq: t.CInt, handler: irq_handler_t, name: str) -> t.CInt:
def irqInstallHandler(irq: int, handler: irq_handler_t, name: str) -> int:
global irq_handlers
if irq < 0 or irq > 15: return -1
irq_handlers[irq] = handler
return 0
def irqGetHandler(irq: t.CInt) -> irq_handler_t:
def irqGetHandler(irq: int) -> irq_handler_t:
if irq < 0 or irq > 15: return None
return irq_handlers[irq]
def init():
global idt
for i in range(256):
setGate(i, t.CUInt64T(isr_default), CODE_SEG, 0x8E)
setGate(i, uint64(isr_default), CODE_SEG, 0x8E)
pic.init()
init_exceptions()
init_irqs()
# Register ISR 0x80 for int 0x80 syscall interface (user-mode ELF apps)
setGate(0x80, t.CUInt64T(isr80), CODE_SEG, 0xEE) # DPL=3 allows Ring 3 to call int 0x80
setGate(0x80, uint64(isr80), CODE_SEG, 0xEE) # DPL=3 allows Ring 3 to call int 0x80
# Build idt_ptr on stack and load directly in one asm block
c.Asm("""lea rax, [rip + idt]
sub rsp, 16
+142 -142
View File
@@ -50,18 +50,18 @@ IA32_STAR: t.CDefine = 0xC0000081
IA32_LSTAR: t.CDefine = 0xC0000082
IA32_FMASK: t.CDefine = 0xC0000084
def wrmsr(msr: t.CUInt32T, val: t.CUInt64T):
lo: t.CUInt32T = t.CUInt32T(val & 0xFFFFFFFF)
hi: t.CUInt32T = t.CUInt32T(val >> 32)
def wrmsr(msr: uint32, val: uint64):
lo: uint32 = uint32(val & 0xFFFFFFFF)
hi: uint32 = uint32(val >> 32)
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
mov eax, {c.AsmInp(lo, t.ASM_DESCR.REG_ANY)}
mov edx, {c.AsmInp(hi, t.ASM_DESCR.REG_ANY)}
wrmsr""",
op=[t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
def rdmsr(msr: t.CUInt32T) -> t.CUInt64T:
lo: t.CUInt32T
hi: t.CUInt32T
def rdmsr(msr: uint32) -> uint64:
lo: uint32
hi: uint32
# rdmsr 固定写 EDX:EAX;out 绑定 + CLOBBER_RAX/RDX 冲突会导致 lo/hi
# 分配到非 EAX/EDX 读到垃圾。显式 mov 到输出寄存器(与 asm.inb 修复同模式)。
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
@@ -70,67 +70,67 @@ def rdmsr(msr: t.CUInt32T) -> t.CUInt64T:
mov {c.AsmOut(hi, t.ASM_DESCR.OUTPUT_REG)}, edx""",
out=[c.AsmOut(lo, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(hi, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
return t.CUInt64T(lo) | (t.CUInt64T(hi) << 32)
return uint64(lo) | (uint64(hi) << 32)
def _current_proc() -> process.Process | t.CPtr:
return process.ProcessManager.current()
def _fd_alloc(p: process.Process | t.CPtr) -> t.CInt:
def _fd_alloc(p: process.Process | t.CPtr) -> int:
for i in range(process.PROC_MAX_FDS):
if not p.fd_used[i]:
p.fd_used[i] = 1
return i
return -1
def _fd_free(p: process.Process | t.CPtr, fd: t.CInt):
def _fd_free(p: process.Process | t.CPtr, fd: int):
if fd >= 0 and fd < process.PROC_MAX_FDS:
p.fd_used[fd] = 0
p.fd_table[fd] = t.CVoid(0, t.CPtr)
def _dir_alloc(p: process.Process | t.CPtr) -> t.CInt:
def _dir_alloc(p: process.Process | t.CPtr) -> int:
for i in range(process.PROC_MAX_DIRS):
if not p.dir_used[i]:
p.dir_used[i] = 1
return i
return -1
def _dir_free(p: process.Process | t.CPtr, dd: t.CInt):
def _dir_free(p: process.Process | t.CPtr, dd: int):
if dd >= 0 and dd < process.PROC_MAX_DIRS:
p.dir_used[dd] = 0
p.dir_table[dd] = t.CVoid(0, t.CPtr)
def CREATE_WINDOW(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | t.CChar | t.CPtr, style: t.CInt) -> t.CInt:
def CREATE_WINDOW(x: int, y: int, w: int, h: int, title: t.CConst | t.CChar | t.CPtr, style: int) -> int:
desktop.set_app_pid(process.current())
return desktop.create(x, y, w, h, title, style)
def DRAW_TEXT(win_id: t.CInt, x: t.CInt, y: t.CInt, text: t.CConst | t.CChar | t.CPtr, color: t.CUInt32T) -> t.CInt:
def DRAW_TEXT(win_id: int, x: int, y: int, text: t.CConst | t.CChar | t.CPtr, color: uint32) -> int:
return desktop.draw_text(win_id, x, y, text, color)
def EXIT(code: t.CInt) -> t.CInt:
def EXIT(code: int) -> int:
serial.puts("[syscall] exit called\n")
desktop.destroy_by_pid(process.current())
return 0
def WAIT_WINDOW(win_id: t.CInt) -> t.CInt:
def WAIT_WINDOW(win_id: int) -> int:
while desktop.is_active(win_id):
sched.Scheduler.try_reschedule()
return 0
def SERIAL_PUTS(str_ptr: t.CVoid | t.CPtr) -> t.CInt:
def SERIAL_PUTS(str_ptr: t.CPtr) -> int:
s: t.CConst | t.CChar | t.CPtr = t.CVoid(str_ptr, t.CPtr)
serial.puts(s)
return 0
_loaded_so_base: t.CVoid | t.CPtr = None
_loaded_so_base: t.CPtr = None
_loaded_so_path: t.CArray[t.CChar, 64]
def LOAD_SO(path_ptr: t.CVoid | t.CPtr) -> t.CUInt64T:
def LOAD_SO(path_ptr: t.CPtr) -> uint64:
global _loaded_so_base
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
serial.puts("[so] loading: ")
serial.puts(path)
serial.puts("\n")
base: t.CVoid | t.CPtr = elf.load_so(path)
base: t.CPtr = elf.load_so(path)
if base is not None:
_loaded_so_base = base
for i in range(63):
@@ -138,13 +138,13 @@ def LOAD_SO(path_ptr: t.CVoid | t.CPtr) -> t.CUInt64T:
_loaded_so_path[i] = ch
if ch == 0: break
_loaded_so_path[63] = 0
return t.CUInt64T(base)
return uint64(base)
return 0
def SO_CALL1(sym_name_ptr: t.CVoid | t.CPtr, arg1: t.CVoid | t.CPtr) -> t.CInt:
def SO_CALL1(sym_name_ptr: t.CPtr, arg1: t.CPtr) -> int:
if _loaded_so_base is None: return -1
sym_name: t.CConst | t.CChar | t.CPtr = t.CVoid(sym_name_ptr, t.CPtr)
fn: t.CVoid | t.CPtr = elf.get_so_symbol(_loaded_so_base, sym_name, c.Addr(_loaded_so_path[0]))
fn: t.CPtr = elf.get_so_symbol(_loaded_so_base, sym_name, c.Addr(_loaded_so_path[0]))
if fn is None:
serial.puts("[so] symbol not found\n")
return -2
@@ -158,29 +158,29 @@ def SO_CALL1(sym_name_ptr: t.CVoid | t.CPtr, arg1: t.CVoid | t.CPtr) -> t.CInt:
serial.puts("[so] call returned\n")
return 0
def GET_WINBUF(win_id: t.CInt) -> t.CUInt64T:
buf: t.CVoid | t.CPtr = desktop.get_fb(win_id)
def GET_WINBUF(win_id: int) -> uint64:
buf: t.CPtr = desktop.get_fb(win_id)
if buf is None:
return 0
return t.CUInt64T(buf)
return uint64(buf)
def WIN_FLUSH(win_id: t.CInt) -> t.CInt:
def WIN_FLUSH(win_id: int) -> int:
desktop.flush(win_id)
return 0
def SET_CURSOR(win_id: t.CInt, cursor_t: t.CInt) -> t.CInt:
def SET_CURSOR(win_id: int, cursor_t: int) -> int:
desktop.set_cursor_type(win_id, cursor_t)
return 0
def OPEN(path_ptr: t.CVoid | t.CPtr, mode: t.CUInt32T) -> t.CInt:
def OPEN(path_ptr: t.CPtr, mode: uint32) -> int:
p: process.Process | t.CPtr = _current_proc()
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
fat32.lock()
fp: t.CVoid | t.CPtr = fat32.open(path, t.CUInt8T(mode))
fp: t.CPtr = fat32.open(path, uint8(mode))
if not fp:
fat32.unlock()
return -1
fd: t.CInt = _fd_alloc(p)
fd: int = _fd_alloc(p)
if fd < 0:
fat32.close(fp)
fat32.unlock()
@@ -189,146 +189,146 @@ def OPEN(path_ptr: t.CVoid | t.CPtr, mode: t.CUInt32T) -> t.CInt:
fat32.unlock()
return fd
def CLOSE(fd: t.CInt) -> t.CInt:
def CLOSE(fd: int) -> int:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fp: t.CVoid | t.CPtr = p.fd_table[fd]
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
fp: t.CPtr = p.fd_table[fd]
if not fp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
res: t.CInt = t.CInt(fat32.close(fp))
res: int = int(fat32.close(fp))
fat32.unlock()
_fd_free(p, fd)
return res
def READ(fd: t.CInt, buf_ptr: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
def READ(fd: int, buf_ptr: t.CPtr, count: uint32) -> int:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return -1
fp: t.CVoid | t.CPtr = p.fd_table[fd]
fp: t.CPtr = p.fd_table[fd]
if not fp:
return -1
fat32.lock()
br: t.CUInt32T = fat32.read(fp, buf_ptr, count)
br: uint32 = fat32.read(fp, buf_ptr, count)
fat32.unlock()
return t.CInt(br)
return int(br)
def WRITE(fd: t.CInt, buf_ptr: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
def WRITE(fd: int, buf_ptr: t.CPtr, count: uint32) -> int:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return -1
fp: t.CVoid | t.CPtr = p.fd_table[fd]
fp: t.CPtr = p.fd_table[fd]
if not fp:
return -1
fat32.lock()
bw: t.CUInt32T = fat32.write(fp, buf_ptr, count)
bw: uint32 = fat32.write(fp, buf_ptr, count)
fat32.unlock()
return t.CInt(bw)
return int(bw)
def SEEK(fd: t.CInt, offset: t.CUInt32T) -> t.CInt:
def SEEK(fd: int, offset: uint32) -> int:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fp: t.CVoid | t.CPtr = p.fd_table[fd]
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
fp: t.CPtr = p.fd_table[fd]
if not fp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
r: t.CInt = t.CInt(fat32.seek(fp, offset))
r: int = int(fat32.seek(fp, offset))
fat32.unlock()
return r
def TELL(fd: t.CInt) -> t.CUInt32T:
def TELL(fd: int) -> uint32:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return 0
fp: t.CVoid | t.CPtr = p.fd_table[fd]
fp: t.CPtr = p.fd_table[fd]
if not fp:
return 0
fat32.lock()
pos: t.CUInt32T = fat32.tell(fp)
pos: uint32 = fat32.tell(fp)
fat32.unlock()
return pos
def fsize(fd: t.CInt) -> t.CUInt32T:
def fsize(fd: int) -> uint32:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return 0
fp: t.CVoid | t.CPtr = p.fd_table[fd]
fp: t.CPtr = p.fd_table[fd]
if not fp:
return 0
fat32.lock()
sz: t.CUInt32T = fat32.size(fp)
sz: uint32 = fat32.size(fp)
fat32.unlock()
return sz
def MKDIR(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
def MKDIR(path_ptr: t.CPtr) -> int:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
fat32.lock()
r: t.CInt = t.CInt(fat32.mkdir(path))
r: int = int(fat32.mkdir(path))
fat32.unlock()
return r
def REMOVE(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
def REMOVE(path_ptr: t.CPtr) -> int:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
fat32.lock()
r: t.CInt = t.CInt(fat32.remove(path))
r: int = int(fat32.remove(path))
fat32.unlock()
return r
def OPENdir(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
def OPENdir(path_ptr: t.CPtr) -> int:
p: process.Process | t.CPtr = _current_proc()
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
dd: t.CInt = _dir_alloc(p)
dd: int = _dir_alloc(p)
if dd < 0:
return -1
dp: fat32_types.dirobj | t.CPtr = c.Addr(p.dir_pool[dd])
fat32.lock()
res: t.CInt = t.CInt(fat32.opendir(path, dp))
res: int = int(fat32.opendir(path, dp))
fat32.unlock()
if res != 0:
_dir_free(p, dd)
return -1
p.dir_table[dd] = t.CVoid(t.CUInt64T(dp), t.CPtr)
p.dir_table[dd] = t.CVoid(uint64(dp), t.CPtr)
return dd
def READdir(dd: t.CInt, info_ptr: t.CVoid | t.CPtr) -> t.CInt:
def READdir(dd: int, info_ptr: t.CPtr) -> int:
p: process.Process | t.CPtr = _current_proc()
if dd < 0 or dd >= process.PROC_MAX_DIRS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
dp: t.CVoid | t.CPtr = p.dir_table[dd]
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
dp: t.CPtr = p.dir_table[dd]
if not dp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
info: fat32_types.fileinfo | t.CPtr = info_ptr
fat32.lock()
r: t.CInt = t.CInt(fat32.readdir(dp, info))
r: int = int(fat32.readdir(dp, info))
fat32.unlock()
return r
def CLOSEdir(dd: t.CInt) -> t.CInt:
def CLOSEdir(dd: int) -> int:
p: process.Process | t.CPtr = _current_proc()
if dd < 0 or dd >= process.PROC_MAX_DIRS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
dp: t.CVoid | t.CPtr = p.dir_table[dd]
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
dp: t.CPtr = p.dir_table[dd]
if not dp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
fat32.closedir(dp)
fat32.unlock()
_dir_free(p, dd)
return 0
def STAT(path_ptr: t.CVoid | t.CPtr, info_ptr: t.CVoid | t.CPtr) -> t.CInt:
def STAT(path_ptr: t.CPtr, info_ptr: t.CPtr) -> int:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
info: fat32_types.fileinfo | t.CPtr = info_ptr
fat32.lock()
r: t.CInt = t.CInt(fat32.stat(path, info))
r: int = int(fat32.stat(path, info))
fat32.unlock()
return r
def SPAWN(path_ptr: t.CVoid | t.CPtr, blocking: t.CInt) -> t.CInt:
def SPAWN(path_ptr: t.CPtr, blocking: int) -> int:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
pid: t.CInt = elf.spawn_elf(path)
pid: int = elf.spawn_elf(path)
if pid < 0:
return pid
if blocking:
@@ -340,135 +340,135 @@ def SPAWN(path_ptr: t.CVoid | t.CPtr, blocking: t.CInt) -> t.CInt:
USER_HEAP_BASE: t.CDefine = 0x20000000
def MMAP(size: t.CUInt64T) -> t.CUInt64T:
def MMAP(size: uint64) -> uint64:
p: process.Process | t.CPtr = _current_proc()
if size == 0: return 0
aligned_size: t.CUInt64T = (size + 4095) & ~t.CUInt64T(4095)
aligned_size: uint64 = (size + 4095) & ~uint64(4095)
if p.heap_start == 0:
p.heap_start = USER_HEAP_BASE
heap_end: t.CUInt64T = p.heap_start + p.heap_size
new_end: t.CUInt64T = heap_end + aligned_size
heap_end: uint64 = p.heap_start + p.heap_size
new_end: uint64 = heap_end + aligned_size
for va in range(heap_end, new_end, 4096):
phys_page: t.CVoid | t.CPtr = mm.malloc(4096)
phys_page: t.CPtr = mm.malloc(4096)
if phys_page is None: return 0
paging.MapPage(va, t.CUInt64T(phys_page), paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
paging.MapPage(va, uint64(phys_page), paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
p.heap_size = p.heap_size + aligned_size
return heap_end
def MUNMAP(ptr: t.CUInt64T, size: t.CUInt64T) -> t.CInt:
def MUNMAP(ptr: uint64, size: uint64) -> int:
return 0
def syscall_entry() -> t.CExtern | t.CVoid | t.State: pass
def syscall_handler(num: t.CUInt64T, arg1: t.CUInt64T, arg2: t.CUInt64T, arg3: t.CUInt64T, arg4: t.CUInt64T, arg5: t.CUInt64T, arg6: t.CUInt64T) -> t.CExport | t.CUInt64T:
n: t.CInt = t.CInt(num)
def syscall_handler(num: uint64, arg1: uint64, arg2: uint64, arg3: uint64, arg4: uint64, arg5: uint64, arg6: uint64) -> t.CExport | uint64:
n: int = int(num)
if n == CREATE_WINDOW:
title_ptr: t.CVoid | t.CPtr = t.CVoid(arg5, t.CPtr)
return t.CUInt64T(CREATE_WINDOW(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), t.CInt(arg4), title_ptr, t.CInt(arg6)))
title_ptr: t.CPtr = t.CVoid(arg5, t.CPtr)
return uint64(CREATE_WINDOW(int(arg1), int(arg2), int(arg3), int(arg4), title_ptr, int(arg6)))
elif n == DRAW_TEXT:
text_ptr: t.CVoid | t.CPtr = t.CVoid(arg4, t.CPtr)
return t.CUInt64T(DRAW_TEXT(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), text_ptr, t.CUInt32T(arg5)))
text_ptr: t.CPtr = t.CVoid(arg4, t.CPtr)
return uint64(DRAW_TEXT(int(arg1), int(arg2), int(arg3), text_ptr, uint32(arg5)))
elif n == EXIT:
return t.CUInt64T(EXIT(t.CInt(arg1)))
return uint64(EXIT(int(arg1)))
elif n == OPEN:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(OPEN(path_ptr, t.CUInt32T(arg2)))
path_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
return uint64(OPEN(path_ptr, uint32(arg2)))
elif n == CLOSE:
return t.CUInt64T(CLOSE(t.CInt(arg1)))
return uint64(CLOSE(int(arg1)))
elif n == READ:
buf_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(READ(t.CInt(arg1), buf_ptr, t.CUInt32T(arg3)))
buf_ptr: t.CPtr = t.CVoid(arg2, t.CPtr)
return uint64(READ(int(arg1), buf_ptr, uint32(arg3)))
elif n == WRITE:
buf_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(WRITE(t.CInt(arg1), buf_ptr, t.CUInt32T(arg3)))
buf_ptr: t.CPtr = t.CVoid(arg2, t.CPtr)
return uint64(WRITE(int(arg1), buf_ptr, uint32(arg3)))
elif n == SEEK:
return t.CUInt64T(SEEK(t.CInt(arg1), t.CUInt32T(arg2)))
return uint64(SEEK(int(arg1), uint32(arg2)))
elif n == TELL:
return t.CUInt64T(TELL(t.CInt(arg1)))
return uint64(TELL(int(arg1)))
elif n == SIZE:
return t.CUInt64T(fsize(t.CInt(arg1)))
return uint64(fsize(int(arg1)))
elif n == MKDIR:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(MKDIR(path_ptr))
path_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
return uint64(MKDIR(path_ptr))
elif n == REMOVE:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(REMOVE(path_ptr))
path_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
return uint64(REMOVE(path_ptr))
elif n == OPENDIR:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(OPENdir(path_ptr))
path_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
return uint64(OPENdir(path_ptr))
elif n == READDIR:
info_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(READdir(t.CInt(arg1), info_ptr))
info_ptr: t.CPtr = t.CVoid(arg2, t.CPtr)
return uint64(READdir(int(arg1), info_ptr))
elif n == CLOSEDIR:
return t.CUInt64T(CLOSEdir(t.CInt(arg1)))
return uint64(CLOSEdir(int(arg1)))
elif n == STAT:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
info_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(STAT(path_ptr, info_ptr))
path_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
info_ptr: t.CPtr = t.CVoid(arg2, t.CPtr)
return uint64(STAT(path_ptr, info_ptr))
elif n == WAIT_WINDOW:
if t.CInt(arg2) == 1:
return t.CUInt64T(desktop.is_active(t.CInt(arg1)))
elif t.CInt(arg2) == 2:
if int(arg2) == 1:
return uint64(desktop.is_active(int(arg1)))
elif int(arg2) == 2:
sched.Scheduler.try_reschedule()
return 0
return t.CUInt64T(WAIT_WINDOW(t.CInt(arg1)))
return uint64(WAIT_WINDOW(int(arg1)))
elif n == SERIAL_PUTS:
str_ptr_sp: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(SERIAL_PUTS(str_ptr_sp))
str_ptr_sp: t.CPtr = t.CVoid(arg1, t.CPtr)
return uint64(SERIAL_PUTS(str_ptr_sp))
elif n == LOAD_SO:
path_ptr_so: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
path_ptr_so: t.CPtr = t.CVoid(arg1, t.CPtr)
return LOAD_SO(path_ptr_so)
elif n == SO_CALL1:
sym_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(SO_CALL1(sym_ptr, t.CPtr(arg2)))
sym_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
return uint64(SO_CALL1(sym_ptr, t.CPtr(arg2)))
elif n == GET_WINBUF:
return GET_WINBUF(t.CInt(arg1))
return GET_WINBUF(int(arg1))
elif n == WIN_FLUSH:
return t.CUInt64T(WIN_FLUSH(t.CInt(arg1)))
return uint64(WIN_FLUSH(int(arg1)))
elif n == POLL_EVENT:
buf_ptr_ev: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
caller_pid_ev: t.CInt = process.current()
return t.CUInt64T(desktop.poll_event(buf_ptr_ev, caller_pid_ev))
buf_ptr_ev: t.CPtr = t.CVoid(arg1, t.CPtr)
caller_pid_ev: int = process.current()
return uint64(desktop.poll_event(buf_ptr_ev, caller_pid_ev))
elif n == SET_CURSOR:
desktop.set_cursor_type(t.CInt(arg1), t.CInt(arg2))
desktop.set_cursor_type(int(arg1), int(arg2))
return 0
elif n == YIELD:
sched.Scheduler.try_reschedule()
return 0
elif n == SET_TITLE:
title_ptr_st: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(desktop.set_title(t.CInt(arg1), title_ptr_st))
title_ptr_st: t.CPtr = t.CVoid(arg2, t.CPtr)
return uint64(desktop.set_title(int(arg1), title_ptr_st))
elif n == SET_GEOMETRY:
return t.CUInt64T(desktop.set_geometry(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), t.CInt(arg4), t.CInt(arg5)))
return uint64(desktop.set_geometry(int(arg1), int(arg2), int(arg3), int(arg4), int(arg5)))
elif n == SET_RESIZABLE:
return t.CUInt64T(desktop.set_resizable(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3)))
return uint64(desktop.set_resizable(int(arg1), int(arg2), int(arg3)))
elif n == GET_WIN_SIZE:
return t.CUInt64T(desktop.get_size(t.CInt(arg1)))
return uint64(desktop.get_size(int(arg1)))
elif n == SPAWN:
path_ptr_sp: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(SPAWN(path_ptr_sp, t.CInt(arg2)))
path_ptr_sp: t.CPtr = t.CVoid(arg1, t.CPtr)
return uint64(SPAWN(path_ptr_sp, int(arg2)))
elif n == MMAP:
return MMAP(arg1)
elif n == MUNMAP:
return t.CUInt64T(MUNMAP(arg1, arg2))
return uint64(MUNMAP(arg1, arg2))
elif n == THREAD_CREATE:
func_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
arg_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
cur_pid: t.CInt = process.current()
func_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
arg_ptr: t.CPtr = t.CVoid(arg2, t.CPtr)
cur_pid: int = process.current()
th: sched.Thread | t.CPtr = sched.Scheduler.create_thread(func_ptr, arg_ptr, cur_pid)
if th is None: return t.CUInt64T(0xFFFFFFFFFFFFFFFF)
if th is None: return uint64(0xFFFFFFFFFFFFFFFF)
p: process.Process | t.CPtr = process.ProcessManager.get_process(cur_pid)
if p:
p.addThread(th.tid)
return t.CUInt64T(th.tid)
return uint64(th.tid)
return 0
def init():
efer: t.CUInt64T = rdmsr(IA32_EFER)
efer: uint64 = rdmsr(IA32_EFER)
efer = efer | 1
wrmsr(IA32_EFER, efer)
star_val: t.CUInt64T = (t.CUInt64T(0x08) << 32) | (t.CUInt64T(0x1B) << 48)
star_val: uint64 = (uint64(0x08) << 32) | (uint64(0x1B) << 48)
wrmsr(IA32_STAR, star_val)
wrmsr(IA32_LSTAR, t.CUInt64T(syscall_entry))
wrmsr(IA32_LSTAR, uint64(syscall_entry))
wrmsr(IA32_FMASK, 0x200)
serial.puts("[syscall] MSR init done\n")
+44 -44
View File
@@ -32,8 +32,8 @@ import t, c
import asm
kbd_tid: t.CInt = -1
mse_tid: t.CInt = -1
kbd_tid: int = -1
mse_tid: int = -1
BootInfo: bootinfo.bootinfo | t.CPtr
@@ -61,7 +61,7 @@ class ViperKernel:
# Set IA32_KERNEL_GS_BASE = &_per_cpu so swapgs in ISR/syscall works.
# _CPUObject is never instantiated, so __init_tss__ never runs;
# without this, GS base stays 0 and gs:[0] writes hit null -> triple fault.
cpu.msr_write(cpu.IA32_KERNEL_GS_BASE, t.CUInt64T(c.Addr(cpu._per_cpu)))
cpu.msr_write(cpu.IA32_KERNEL_GS_BASE, uint64(c.Addr(cpu._per_cpu)))
serial.puts("[main] gdt init done\n")
intr.idt.init()
syscall.init()
@@ -84,12 +84,12 @@ class ViperKernel:
serial.puts("[main] apic init done\n")
# [DBG] 综合诊断:判定 LAPIC MMIO 是否真正可访问/可写(用后移除)
_dbg_base: t.CUInt64T = apic.get_base()
_dbg_ver: t.CUInt32T = apic.read(0x030) # LAPIC_VERSION:真 LAPIC 应为 0x50014
_dbg_svr: t.CUInt32T = apic.read(0x0F0) # LAPIC_SVR:init 已写 0x1FF
_dbg_base: uint64 = apic.get_base()
_dbg_ver: uint32 = apic.read(0x030) # LAPIC_VERSION:真 LAPIC 应为 0x50014
_dbg_svr: uint32 = apic.read(0x0F0) # LAPIC_SVR:init 已写 0x1FF
apic.write(0x350, 0x700) # 再次写 LINT0,验证写粘性
_dbg_lint0: t.CUInt32T = apic.read(0x350)
_dbg_feat: t.CUInt32T = cpu.detect_features_static()
_dbg_lint0: uint32 = apic.read(0x350)
_dbg_feat: uint32 = cpu.detect_features_static()
_dbg_buf: t.CArray[t.CChar, 160]
viperlib.snprintf(c.Addr(_dbg_buf), 160,
"[DBG] base=0x%lx ver=0x%x svr=0x%x lint0=0x%x feat=0x%x apic=%d\n",
@@ -98,9 +98,9 @@ class ViperKernel:
serial.puts(c.Addr(_dbg_buf))
# [DBG] 读回 IDT 门 32,验证 isr32 分发地址是否正确安装(用后移除)
_g32: t.CUInt64T = (t.CUInt64T(intr.idt.idt[32].base_low) |
(t.CUInt64T(intr.idt.idt[32].base_middle) << 16) |
(t.CUInt64T(intr.idt.idt[32].base_high) << 32))
_g32: uint64 = (uint64(intr.idt.idt[32].base_low) |
(uint64(intr.idt.idt[32].base_middle) << 16) |
(uint64(intr.idt.idt[32].base_high) << 32))
_g32buf: t.CArray[t.CChar, 96]
viperlib.snprintf(c.Addr(_g32buf), 96, "[DBG] idt32 base=0x%lx sel=0x%x type=0x%x\n",
_g32, intr.idt.idt[32].selector, intr.idt.idt[32].type_attr)
@@ -118,7 +118,7 @@ class ViperKernel:
# [DBG] 读 PIC1 ISR:bit0 置位说明 PIT IRQ0 已到达 PIC 并被响应(用后移除)
asm.outb(0x20, 0x0B) # OCW3 读 ISR
asm.io_wait()
_pic_isr: t.CUInt8T = asm.inb(0x20)
_pic_isr: uint8 = asm.inb(0x20)
_isrbuf: t.CArray[t.CChar, 48]
viperlib.snprintf(c.Addr(_isrbuf), 48, "[DBG] pic_isr=0x%x\n", _pic_isr)
serial.puts(c.Addr(_isrbuf))
@@ -127,7 +127,7 @@ class ViperKernel:
serial.puts("[main] msleep done\n")
rtc.rtc_init()
serial.puts("[main] rtc init done\n")
ncpu: t.CUInt32T = apic.get_cpu_count()
ncpu: uint32 = apic.get_cpu_count()
ncpu_cr: t.CArray[t.CChar, 32]
viperlib.snprintf(c.Addr(ncpu_cr), 32, "[main] cpu_count=%u\n", ncpu)
serial.puts(ncpu_cr)
@@ -135,26 +135,26 @@ class ViperKernel:
apic.start_aps()
serial.puts("[main] kernel init done\n")
fb: t.CVoid | t.CPtr = t.CPtr(BootInfo.framebuffer_addr)
width: t.CUInt64T = BootInfo.framebuffer_width
height: t.CUInt64T = BootInfo.framebuffer_height
pitch: t.CUInt64T = BootInfo.framebuffer_pitch
fb_format: t.CUInt64T = BootInfo.framebuffer_format
fb_size: t.CUInt64T = BootInfo.framebuffer_size
fb: t.CPtr = t.CPtr(BootInfo.framebuffer_addr)
width: uint64 = BootInfo.framebuffer_width
height: uint64 = BootInfo.framebuffer_height
pitch: uint64 = BootInfo.framebuffer_pitch
fb_format: uint64 = BootInfo.framebuffer_format
fb_size: uint64 = BootInfo.framebuffer_size
# [DBG] 打印 BootInfo 指针与 memmap 原始字段,定位全 0 根因(用后移除)
_dbbuf: t.CArray[t.CChar, 140]
viperlib.snprintf(c.Addr(_dbbuf), 140, "[main] BootInfo=0x%lx mmap=0x%lx mmsz=%lu mmd=%lu fb=0x%lx\n",
t.CUInt64T(BootInfo), BootInfo.MemmapAddr, BootInfo.MemmapSize,
uint64(BootInfo), BootInfo.MemmapAddr, BootInfo.MemmapSize,
BootInfo.MemmapDescSize, BootInfo.framebuffer_addr)
serial.puts(c.Addr(_dbbuf))
# [DBG] 转储 BootInfo 地址处原始 88 字节(用后移除)
_dbraw: t.CArray[t.CChar, 16]
_dbi: t.CInt = 0
_dbi: int = 0
while _dbi < 88:
if (_dbi % 16) == 0:
viperlib.snprintf(c.Addr(_dbraw), 16, "\n[DB] %04x:", _dbi)
serial.puts(c.Addr(_dbraw))
_dbv: t.CUInt8T = c.Deref(t.CUInt8T(t.CUInt64T(BootInfo) + t.CUInt64T(_dbi), t.CPtr))
_dbv: uint8 = c.Deref(uint8(uint64(BootInfo) + uint64(_dbi), t.CPtr))
viperlib.snprintf(c.Addr(_dbraw), 16, " %02x", _dbv)
serial.puts(c.Addr(_dbraw))
_dbi += 1
@@ -162,20 +162,20 @@ class ViperKernel:
if BootInfo is not None:
paging.init(BootInfo.MemmapAddr, BootInfo.MemmapSize)
fb_pages: t.CUInt64T = (fb_size + t.CUInt64T(0xFFF)) >> t.CUInt64T(12)
fpi: t.CUInt64T = 0
fb_pages: uint64 = (fb_size + uint64(0xFFF)) >> uint64(12)
fpi: uint64 = 0
while fpi < fb_pages:
fva: t.CUInt64T = t.CUInt64T(fb) + fpi * t.CUInt64T(0x1000)
fva: uint64 = uint64(fb) + fpi * uint64(0x1000)
paging.MapPage(fva, fva, paging.PTE_WRITABLE | paging.PTE_PCD)
fpi += 1
mm.init(BootInfo.MemmapAddr, BootInfo.MemmapSize, BootInfo.MemmapDescSize, BootInfo.framebuffer_addr, fb_size)
pt_pool_buf: t.CVoid | t.CPtr = mm.malloc(t.CUInt64T(513) * t.CUInt64T(4096))
paging.init_pool(pt_pool_buf, t.CUInt64T(513) * t.CUInt64T(4096))
pt_pool_buf: t.CPtr = mm.malloc(uint64(513) * uint64(4096))
paging.init_pool(pt_pool_buf, uint64(513) * uint64(4096))
else:
paging.init(0, 0)
mm.init(0, 0, 0, 0, 0)
pt_pool_buf2: t.CVoid | t.CPtr = mm.malloc(t.CUInt64T(513) * t.CUInt64T(4096))
paging.init_pool(pt_pool_buf2, t.CUInt64T(513) * t.CUInt64T(4096))
pt_pool_buf2: t.CPtr = mm.malloc(uint64(513) * uint64(4096))
paging.init_pool(pt_pool_buf2, uint64(513) * uint64(4096))
serial.puts("[main] paging and mm init done\n")
# 把 .rodata(字符串常量/vtable)映射只读 + CR0.WP=1:
# 越界写立即 #PF 暴露 cr2/rip(此前静默破坏格式串/路径/符号名 → P2/P3/P4/P5 连锁)
@@ -192,26 +192,26 @@ class ViperKernel:
serial.puts("[main] ide init done\n")
serial.puts("[main] initializing FAT32 filesystem\n")
scan_res: t.CInt = fat32.scan_drives()
ndrives: t.CInt = fat32.get_drive_count()
scan_res: int = fat32.scan_drives()
ndrives: int = fat32.get_drive_count()
ndrives_cr: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(ndrives_cr), 64, "[fat32] scan_res=%d found %d drives\n", scan_res, ndrives)
serial.puts(ndrives_cr)
if ndrives > 0:
mount_res: t.CInt = fat32.mount()
mount_res: int = fat32.mount()
if mount_res == 0:
dp: fat32_types.dirobj
res: t.CInt = fat32.opendir("/", c.Addr(dp))
res: int = fat32.opendir("/", c.Addr(dp))
if res == 0:
serial.puts("[fat32] listing 0:/\n")
count: t.CInt = 0
count: int = 0
while count < 20:
info: fat32_types.fileinfo
res2: t.CInt = fat32.readdir(c.Addr(dp), c.Addr(info))
res2: int = fat32.readdir(c.Addr(dp), c.Addr(info))
if res2 != 0: break
if info.fname[0] == 0: break
is_dir: t.CInt = 1 if (info.attr & fat32_types.AM_DIR) else 0
is_dir: int = 1 if (info.attr & fat32_types.AM_DIR) else 0
entry_cr: t.CArray[t.CChar, 300]
viperlib.snprintf(c.Addr(entry_cr), 300, " %s size=%lu dir=%d\n", c.Addr(info.fname[0]), info.file_size, is_dir)
serial.puts(entry_cr)
@@ -224,13 +224,13 @@ class ViperKernel:
# Load ELF apps BEFORE running destructive FAT32 tests
serial.puts("[main] loading ELF apps...\n")
dp_apps: fat32_types.dirobj
apps_res: t.CInt = fat32.opendir("/APPS", c.Addr(dp_apps))
apps_res: int = fat32.opendir("/APPS", c.Addr(dp_apps))
if apps_res == 0:
serial.puts("[main] APPS dir listing:\n")
ac: t.CInt = 0
ac: int = 0
while ac < 20:
ai: fat32_types.fileinfo
ar: t.CInt = fat32.readdir(c.Addr(dp_apps), c.Addr(ai))
ar: int = fat32.readdir(c.Addr(dp_apps), c.Addr(ai))
if ar != 0: break
if ai.fname[0] == 0: break
ae: t.CArray[t.CChar, 300]
@@ -265,7 +265,7 @@ class ViperKernel:
serial.puts("[main] sched started\n")
fd: t.CInt = devfs.devfs_open("/dev/serial0", 0)
fd: int = devfs.devfs_open("/dev/serial0", 0)
buf: t.CArray[t.CChar, 64]
string.memset(c.Addr(buf), 0, 64)
devfs.devfs_write(fd, "hello from devfs!", 17)
@@ -327,10 +327,10 @@ class ViperKernel:
serial.puts("[main] entering main loop\n")
# sched.sched_dump()
last_sec: t.CUInt32T = 0
loop_cnt: t.CUInt32T = 0
last_sec: uint32 = 0
loop_cnt: uint32 = 0
while True:
cur_sec: t.CUInt32T = timer.timer_get_seconds()
cur_sec: uint32 = timer.timer_get_seconds()
if cur_sec != last_sec:
last_sec = cur_sec
#if cur_sec % 5 == 0:
@@ -360,7 +360,7 @@ VKP: ViperKernel | t.CPtr
# stackrealign:_start 由 bootloader jmp 进入(rsp≡0 mod 16),llc 按 call 约定
# 假设入口 rsp≡8 → 帧偏 8 → 变参函数 movaps #GP。动态重对齐栈修复。
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16), t.attr.stackrealign)
def _start() -> t.CInt:
def _start() -> int:
global VKP, BootInfo
saved_rdi: t.CUnsignedLong
c.Asm(f"mov {c.AsmOut(saved_rdi, t.ASM_DESCR.OUTPUT_REG)}, rdi",
+179 -179
View File
@@ -15,24 +15,24 @@ BLOCK_FREE: t.CDefine = 0 # 空闲
BLOCK_USED: t.CDefine = 1 # 已使用
# 内存类型定义
MEMORY_TYPE_AVAILABLE: t.CUInt64T = 7
MEMORY_TYPE_RESERVED: t.CUInt64T = 0
MEMORY_TYPE_LOADER_CODE: t.CUInt64T = 1
MEMORY_TYPE_LOADER_DATA: t.CUInt64T = 2
MEMORY_TYPE_BOOT_SERVICES_CODE: t.CUInt64T = 3
MEMORY_TYPE_BOOT_SERVICES_DATA: t.CUInt64T = 4
MEMORY_TYPE_RUNTIME_SERVICES_CODE: t.CUInt64T = 5
MEMORY_TYPE_RUNTIME_SERVICES_DATA: t.CUInt64T = 6
MEMORY_TYPE_ACPI_RECLAIMABLE: t.CUInt64T = 9
MEMORY_TYPE_ACPI_NVS: t.CUInt64T = 10
MEMORY_TYPE_BAD_MEMORY: t.CUInt64T = 8
MEMORY_TYPE_AVAILABLE: uint64 = 7
MEMORY_TYPE_RESERVED: uint64 = 0
MEMORY_TYPE_LOADER_CODE: uint64 = 1
MEMORY_TYPE_LOADER_DATA: uint64 = 2
MEMORY_TYPE_BOOT_SERVICES_CODE: uint64 = 3
MEMORY_TYPE_BOOT_SERVICES_DATA: uint64 = 4
MEMORY_TYPE_RUNTIME_SERVICES_CODE: uint64 = 5
MEMORY_TYPE_RUNTIME_SERVICES_DATA: uint64 = 6
MEMORY_TYPE_ACPI_RECLAIMABLE: uint64 = 9
MEMORY_TYPE_ACPI_NVS: uint64 = 10
MEMORY_TYPE_BAD_MEMORY: uint64 = 8
# 内存区域结构
class memory_region(t.CStruct):
start: t.CUInt64T
end: t.CUInt64T
size: t.CUInt64T
type: t.CUInt32T
start: uint64
end: uint64
size: uint64
type: uint32
next: 'memory_region' | t.CPtr
# 全局内存区域链表
@@ -40,20 +40,20 @@ memory_regions: t.CStatic | memory_region | t.CPtr = None
# 内存块结构
class memory_block(t.CStruct):
size: t.CUInt64T # 块大小
state: t.CUInt8T # 块状态
order: t.CUInt8T # 块阶数
size: uint64 # 块大小
state: uint8 # 块状态
order: uint8 # 块阶数
next: 'memory_block' | t.CPtr # 下一个块
prev: 'memory_block' | t.CPtr # 上一个块
# 伙伴系统结构
class __buddy_system(t.CStruct):
free_lists: t.CArray[memory_block | t.CPtr, MAX_ORDER + 1]
total_memory: t.CUInt64T # 总内存大小
used_memory: t.CUInt64T # 已使用内存大小
free_memory: t.CUInt64T # 空闲内存大小
start_addr: t.CVoid | t.CPtr # 内存起始地址
end_addr: t.CVoid | t.CPtr # 内存结束地址
total_memory: uint64 # 总内存大小
used_memory: uint64 # 已使用内存大小
free_memory: uint64 # 空闲内存大小
start_addr: t.CPtr # 内存起始地址
end_addr: t.CPtr # 内存结束地址
SLAB_MAGIC: t.CDefine = 0x534C4142
@@ -61,34 +61,34 @@ SLAB_NUM_SIZES: t.CDefine = 6
SLAB_THRESHOLD: t.CDefine = 1024
class slab_page(t.CStruct):
magic: t.CUInt32T
obj_size: t.CUInt16T
free_count: t.CUInt16T
data_offset: t.CUInt16T
total_objs: t.CUInt16T
free_head: t.CVoid | t.CPtr
magic: uint32
obj_size: uint16
free_count: uint16
data_offset: uint16
total_objs: uint16
free_head: t.CPtr
block_ptr: memory_block | t.CPtr
next: 'slab_page' | t.CPtr
prev: 'slab_page' | t.CPtr
# 4K对齐函数
def align_4k(addr: t.CUInt64T) -> t.CUInt64T:
def align_4k(addr: uint64) -> uint64:
return (addr + 0xFFF) & ~0xFFF
# 计算阶数
def get_order(size: t.CUInt64T) -> t.CStatic | t.CInt:
order: t.CInt = 0
def get_order(size: uint64) -> t.CStatic | int:
order: int = 0
while size > MIN_BLOCK_SIZE:
size >>= 1
order += 1
return order
# 计算块大小
def get_block_size(order: t.CInt) -> t.CStatic | t.CUInt64T:
def get_block_size(order: int) -> t.CStatic | uint64:
# 4096 << 20 = 4GB 超出 i32 范围 → 0x0 → 伙伴初始化无限循环(bs=0x0)。
# 必须用 64 位移位(4096<<20 = 4294967296)。
return t.CUInt64T(MIN_BLOCK_SIZE) << t.CUInt64T(order)
return uint64(MIN_BLOCK_SIZE) << uint64(order)
@t.Object
@@ -96,27 +96,27 @@ class _BuddySystemObject:
# 全局伙伴系统实例
buddy: __buddy_system
# 初始化伙伴系统
def __init__(self, start_addr: t.CVoid | t.CPtr, size: t.CUInt64T):
def __init__(self, start_addr: t.CPtr, size: uint64):
for i in range(MAX_ORDER + 1):
self.buddy.free_lists[i] = None
self.buddy.total_memory = size
self.buddy.used_memory = 0
self.buddy.free_memory = size
self.buddy.start_addr = start_addr
self.buddy.end_addr = t.CVoid(t.CUInt64T(start_addr) + size, t.CPtr)
remaining: t.CUInt64T = size
cur_addr: t.CUInt64T = t.CUInt64T(start_addr)
self.buddy.end_addr = t.CVoid(uint64(start_addr) + size, t.CPtr)
remaining: uint64 = size
cur_addr: uint64 = uint64(start_addr)
# [DBG] buddy 初始化循环进度(用后移除)
import drivers.serial.uart.serial as _sdbg
_dbp: t.CArray[t.CChar, 80]
_itc: t.CInt = 0
_itc: int = 0
while remaining >= MIN_BLOCK_SIZE:
order: t.CInt = 0
tmp: t.CUInt64T = remaining
order: int = 0
tmp: uint64 = remaining
while tmp > MIN_BLOCK_SIZE:
tmp >>= 1
order += 1
block_size: t.CUInt64T = get_block_size(order)
block_size: uint64 = get_block_size(order)
while block_size > remaining and order > 0:
order -= 1
block_size = get_block_size(order)
@@ -144,23 +144,23 @@ class _BuddySystemObject:
import drivers.serial.uart.serial as serial
_dmsg: t.CArray[t.CChar, 40]
serial.puts("[mm] buddy init:")
_di: t.CInt = 0
_di: int = 0
while _di <= MAX_ORDER:
if self.buddy.free_lists[_di]:
viperlib.snprintf(c.Addr(_dmsg), 40, " [%d]=0x%lx", _di, t.CUInt64T(self.buddy.free_lists[_di]))
viperlib.snprintf(c.Addr(_dmsg), 40, " [%d]=0x%lx", _di, uint64(self.buddy.free_lists[_di]))
serial.puts(_dmsg)
_di += 1
serial.puts("\n")
# 分割内存块
def split_block(self, block: memory_block | t.CPtr, target_order: t.CInt) -> memory_block | t.CPtr:
current_order: t.CInt = block.order
def split_block(self, block: memory_block | t.CPtr, target_order: int) -> memory_block | t.CPtr:
current_order: int = block.order
# 从当前阶数向下分割,直到达到目标阶数
while current_order > target_order:
current_order -= 1
new_block_size: t.CUInt64T = get_block_size(current_order)
new_block_size: uint64 = get_block_size(current_order)
# 创建新块
new_block: memory_block | t.CPtr = t.CPtr(t.CUInt64T(block) + new_block_size)
new_block: memory_block | t.CPtr = t.CPtr(uint64(block) + new_block_size)
new_block.size = new_block_size
new_block.state = BLOCK_FREE
new_block.order = current_order
@@ -179,13 +179,13 @@ class _BuddySystemObject:
# 合并内存块
def merge_blocks(self, block: memory_block | t.CPtr) -> t.CStatic | memory_block | t.CPtr:
order: t.CInt = block.order
order: int = block.order
while order < MAX_ORDER:
block_size: t.CUInt64T = get_block_size(order)
block_addr: t.CUInt64T = t.CUInt64T(block) - t.CUInt64T(self.buddy.start_addr)
buddy_addr: t.CUInt64T = block_addr ^ block_size
block_size: uint64 = get_block_size(order)
block_addr: uint64 = uint64(block) - uint64(self.buddy.start_addr)
buddy_addr: uint64 = block_addr ^ block_size
# 计算伙伴块地址
buddy: memory_block | t.CPtr = t.CPtr(t.CUInt64T(self.buddy.start_addr) + buddy_addr)
buddy: memory_block | t.CPtr = t.CPtr(uint64(self.buddy.start_addr) + buddy_addr)
# 检查伙伴块是否存在且空闲
if buddy >= t.CType(self.buddy.end_addr, memory_block, t.CPtr):
break # 伙伴块超出内存范围
@@ -205,12 +205,12 @@ class _BuddySystemObject:
return block
# 分配内存块
def allocate_block(self, size: t.CUInt64T) -> t.CStatic | memory_block | t.CPtr:
def allocate_block(self, size: uint64) -> t.CStatic | memory_block | t.CPtr:
# 计算所需阶数
order: t.CInt = get_order(size)
order: int = get_order(size)
if order > MAX_ORDER: return None # 所需块大小超过最大限制
# 查找合适的空闲块
found_order: t.CInt = -1
found_order: int = -1
for i in range(order, MAX_ORDER + 1):
if self.buddy.free_lists[i]:
found_order = i
@@ -222,11 +222,11 @@ class _BuddySystemObject:
viperlib.snprintf(c.Addr(_dba), 120, "[mm] alloc FAIL size=%lu order=%d\n", size, order)
serial.puts(_dba)
_dbf: t.CArray[t.CChar, 200]
_fi: t.CInt = 0
_fo: t.CInt = 0
_fi: int = 0
_fo: int = 0
while _fi <= MAX_ORDER:
if self.buddy.free_lists[_fi]:
_fs: t.CInt = viperlib.snprintf(c.Addr(_dbf) + _fo, 200 - _fo, "[%d]=0x%lx ", _fi, t.CUInt64T(self.buddy.free_lists[_fi]))
_fs: int = viperlib.snprintf(c.Addr(_dbf) + _fo, 200 - _fo, "[%d]=0x%lx ", _fi, uint64(self.buddy.free_lists[_fi]))
_fo = _fo + _fs
_fi += 1
if _fo == 0:
@@ -249,7 +249,7 @@ class _BuddySystemObject:
# 更新内存统计
self.buddy.used_memory += block.size
self.buddy.free_memory -= block.size
viperlib.snprintf(c.Addr(_dba), 120, "[mm] alloc OK size=%lu order=%d found=%d block=0x%lx\n", size, order, found_order, t.CUInt64T(block))
viperlib.snprintf(c.Addr(_dba), 120, "[mm] alloc OK size=%lu order=%d found=%d block=0x%lx\n", size, order, found_order, uint64(block))
serial.puts(_dba)
return block
@@ -263,7 +263,7 @@ class _BuddySystemObject:
# 尝试合并块
block = self.merge_blocks(block)
# 将块添加到对应阶数的空闲链表
order: t.CInt = block.order
order: int = block.order
if order <= MAX_ORDER:
block.next = self.buddy.free_lists[order]
block.prev = None
@@ -273,7 +273,7 @@ class _BuddySystemObject:
BuddySystemObject: _BuddySystemObject
def _slab_obj_size(size_class: t.CInt) -> t.CUInt16T:
def _slab_obj_size(size_class: int) -> uint16:
if size_class == 0: return 32
if size_class == 1: return 64
if size_class == 2: return 128
@@ -281,7 +281,7 @@ def _slab_obj_size(size_class: t.CInt) -> t.CUInt16T:
if size_class == 4: return 512
return 1024
def _slab_size_class(size: t.CUInt64T) -> t.CInt:
def _slab_size_class(size: uint64) -> int:
if size <= 32: return 0
if size <= 64: return 1
if size <= 128: return 2
@@ -290,31 +290,31 @@ def _slab_size_class(size: t.CUInt64T) -> t.CInt:
if size <= 1024: return 5
return -1
def _slab_read_ptr(addr: t.CVoid | t.CPtr) -> t.CVoid | t.CPtr:
result: t.CVoid | t.CPtr
def _slab_read_ptr(addr: t.CPtr) -> t.CPtr:
result: t.CPtr
c.Asm(f"""mov rax, [{c.AsmInp(addr, t.ASM_DESCR.REG_ANY)}]
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
return result
def _slab_write_ptr(addr: t.CVoid | t.CPtr, val: t.CVoid | t.CPtr):
def _slab_write_ptr(addr: t.CPtr, val: t.CPtr):
c.Asm(f"""mov rax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}
mov [{c.AsmInp(addr, t.ASM_DESCR.REG_ANY)}], rax""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_MEMORY])
def _slab_find_page(ptr: t.CVoid | t.CPtr) -> slab_page | t.CPtr:
def _slab_find_page(ptr: t.CPtr) -> slab_page | t.CPtr:
if ptr is None: return None
hdr_off: t.CUInt64T = memory_block.__sizeof__()
page_addr: t.CUInt64T = t.CUInt64T(ptr) & ~t.CUInt64T(0xFFF)
hdr_off: uint64 = memory_block.__sizeof__()
page_addr: uint64 = uint64(ptr) & ~uint64(0xFFF)
page: slab_page | t.CPtr = t.CPtr(page_addr + hdr_off)
if page.magic == SLAB_MAGIC:
os: t.CUInt16T = page.obj_size
os: uint16 = page.obj_size
if os == 32 or os == 64 or os == 128 or os == 256 or os == 512 or os == 1024:
return page
page_addr2: t.CUInt64T = page_addr - 4096
page_addr2: uint64 = page_addr - 4096
page2: slab_page | t.CPtr = t.CPtr(page_addr2 + hdr_off)
if page2.magic == SLAB_MAGIC:
os2: t.CUInt16T = page2.obj_size
os2: uint16 = page2.obj_size
if os2 == 32 or os2 == 64 or os2 == 128 or os2 == 256 or os2 == 512 or os2 == 1024:
return page2
return None
@@ -327,34 +327,34 @@ class _SlabAllocator:
for i in range(SLAB_NUM_SIZES):
self.caches[i] = None
def _create_page(self, size_class: t.CInt) -> slab_page | t.CPtr:
obj_size: t.CUInt16T = _slab_obj_size(size_class)
aligned_size: t.CUInt16T = t.CUInt16T((obj_size + 15) & ~15)
def _create_page(self, size_class: int) -> slab_page | t.CPtr:
obj_size: uint16 = _slab_obj_size(size_class)
aligned_size: uint16 = uint16((obj_size + 15) & ~15)
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(4096 + memory_block.__sizeof__())
if not block: return None
hdr_off: t.CUInt64T = memory_block.__sizeof__()
page: slab_page | t.CPtr = t.CPtr(t.CUInt64T(block) + hdr_off)
hdr_off: uint64 = memory_block.__sizeof__()
page: slab_page | t.CPtr = t.CPtr(uint64(block) + hdr_off)
page.magic = SLAB_MAGIC
page.obj_size = aligned_size
d_off: t.CUInt16T = t.CUInt16T((hdr_off + slab_page.__sizeof__() + 15) & ~15)
d_off: uint16 = uint16((hdr_off + slab_page.__sizeof__() + 15) & ~15)
page.data_offset = d_off
total: t.CUInt16T = t.CUInt16T((block.size - d_off) / aligned_size)
total: uint16 = uint16((block.size - d_off) / aligned_size)
page.total_objs = total
page.free_count = total
page.block_ptr = block
page.next = None
page.prev = None
data_start: t.CUInt64T = t.CUInt64T(block) + d_off
data_start: uint64 = uint64(block) + d_off
page.free_head = t.CVoid(data_start, t.CPtr)
for i in range(1, total):
cur: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(i - 1) * aligned_size, t.CPtr)
nxt: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(i) * aligned_size, t.CPtr)
cur: t.CPtr = t.CVoid(data_start + uint64(i - 1) * aligned_size, t.CPtr)
nxt: t.CPtr = t.CVoid(data_start + uint64(i) * aligned_size, t.CPtr)
_slab_write_ptr(cur, nxt)
last: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(total - 1) * aligned_size, t.CPtr)
last: t.CPtr = t.CVoid(data_start + uint64(total - 1) * aligned_size, t.CPtr)
_slab_write_ptr(last, t.CVoid(0, t.CPtr))
return page
def alloc(self, size_class: t.CInt) -> t.CVoid | t.CPtr:
def alloc(self, size_class: int) -> t.CPtr:
page: slab_page | t.CPtr = self.caches[size_class]
while page:
if page.free_count > 0: break
@@ -366,12 +366,12 @@ class _SlabAllocator:
if self.caches[size_class]:
self.caches[size_class].prev = page
self.caches[size_class] = page
obj: t.CVoid | t.CPtr = page.free_head
obj: t.CPtr = page.free_head
page.free_head = _slab_read_ptr(obj)
page.free_count -= 1
return obj
def free_obj(self, ptr: t.CVoid | t.CPtr, page: slab_page | t.CPtr):
def free_obj(self, ptr: t.CPtr, page: slab_page | t.CPtr):
_slab_write_ptr(ptr, page.free_head)
page.free_head = ptr
page.free_count += 1
@@ -379,7 +379,7 @@ class _SlabAllocator:
if page.prev:
page.prev.next = page.next
else:
sc: t.CInt = _slab_size_class(page.obj_size)
sc: int = _slab_size_class(page.obj_size)
if sc >= 0:
self.caches[sc] = page.next
if page.next:
@@ -391,99 +391,99 @@ SlabAllocator: _SlabAllocator
# 内存分配函数
def malloc(size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
def malloc(size: uint64) -> t.CPtr | t.CExport:
if size == 0: return None
if size <= SLAB_THRESHOLD:
sc: t.CInt = _slab_size_class(size)
sc: int = _slab_size_class(size)
if sc >= 0:
result: t.CVoid | t.CPtr = SlabAllocator.alloc(sc)
result: t.CPtr = SlabAllocator.alloc(sc)
return result
hdr: t.CUInt64T = memory_block.__sizeof__()
hdr: uint64 = memory_block.__sizeof__()
if size >= 4096:
total: t.CUInt64T = size + 4096
total: uint64 = size + 4096
total = align_4k(total)
order: t.CInt = get_order(total)
order: int = get_order(total)
if order > MAX_ORDER: return None
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(total)
import drivers.serial.uart.serial as serial
_dbm: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbm), 120, "[mm] malloc buddy size=%lu block=0x%lx\n", size, t.CUInt64T(block))
viperlib.snprintf(c.Addr(_dbm), 120, "[mm] malloc buddy size=%lu block=0x%lx\n", size, uint64(block))
serial.puts(_dbm)
if not block: return None
user_ptr: t.CUInt64T = (t.CUInt64T(block) + hdr + 4095) & ~t.CUInt64T(4095)
real_hdr: t.CUInt64T = user_ptr - 8
user_ptr: uint64 = (uint64(block) + hdr + 4095) & ~uint64(4095)
real_hdr: uint64 = user_ptr - 8
c.Asm(f"""mov rax, {c.AsmInp(block, t.ASM_DESCR.REG_ANY)}
mov [{c.AsmInp(t.CVoid(real_hdr, t.CPtr), t.ASM_DESCR.REG_ANY)}], rax""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_MEMORY])
viperlib.snprintf(c.Addr(_dbm), 120, "[mm] malloc ret user_ptr=0x%lx\n", user_ptr)
serial.puts(_dbm)
return t.CVoid(user_ptr, t.CPtr)
total2: t.CUInt64T = size + hdr
total2: uint64 = size + hdr
total2 = align_4k(total2)
order2: t.CInt = get_order(total2)
order2: int = get_order(total2)
if order2 > MAX_ORDER: return None
block2: memory_block | t.CPtr = BuddySystemObject.allocate_block(total2)
if not block2: return None
return t.CVoid(t.CUInt64T(block2) + hdr, t.CPtr)
return t.CVoid(uint64(block2) + hdr, t.CPtr)
def malloc_direct(size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
def malloc_direct(size: uint64) -> t.CPtr | t.CExport:
if size == 0: return None
hdr: t.CUInt64T = memory_block.__sizeof__()
total: t.CUInt64T = size + hdr
hdr: uint64 = memory_block.__sizeof__()
total: uint64 = size + hdr
total = align_4k(total)
order: t.CInt = get_order(total)
order: int = get_order(total)
if order > MAX_ORDER: return None
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(total)
if not block: return None
return t.CVoid(t.CUInt64T(block) + hdr, t.CPtr)
return t.CVoid(uint64(block) + hdr, t.CPtr)
def free(ptr: t.CVoid | t.CPtr) -> t.CExport:
def free(ptr: t.CPtr) -> t.CExport:
if ptr is None: return
sp: slab_page | t.CPtr = _slab_find_page(ptr)
if sp:
SlabAllocator.free_obj(ptr, sp)
return
if (t.CUInt64T(ptr) & 0xFFF) == 0:
real_hdr: t.CUInt64T = t.CUInt64T(ptr) - 8
if (uint64(ptr) & 0xFFF) == 0:
real_hdr: uint64 = uint64(ptr) - 8
block: memory_block | t.CPtr
c.Asm(f"""mov rax, [{c.AsmInp(t.CVoid(real_hdr, t.CPtr), t.ASM_DESCR.REG_ANY)}]
mov {c.AsmOut(block, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
BuddySystemObject.free_block(block)
return
block2: memory_block | t.CPtr = t.CPtr(t.CUInt64T(ptr) - memory_block.__sizeof__())
block2: memory_block | t.CPtr = t.CPtr(uint64(ptr) - memory_block.__sizeof__())
BuddySystemObject.free_block(block2)
def calloc(nmemb: t.CUInt64T, size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
total_size: t.CUInt64T = nmemb * size
ptr: t.CVoid | t.CPtr = malloc(total_size)
def calloc(nmemb: uint64, size: uint64) -> t.CPtr | t.CExport:
total_size: uint64 = nmemb * size
ptr: t.CPtr = malloc(total_size)
if ptr:
string.memset(ptr, 0, total_size)
return ptr
def realloc(ptr: t.CVoid | t.CPtr, size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
def realloc(ptr: t.CPtr, size: uint64) -> t.CPtr | t.CExport:
if ptr is None: return malloc(size)
if size == 0:
free(ptr)
return None
new_ptr: t.CVoid | t.CPtr = malloc(size)
new_ptr: t.CPtr = malloc(size)
if not new_ptr: return None
sp: slab_page | t.CPtr = _slab_find_page(ptr)
if sp:
old_size: t.CUInt64T = sp.obj_size
elif (t.CUInt64T(ptr) & 0xFFF) == 0:
real_hdr_r: t.CUInt64T = t.CUInt64T(ptr) - 8
old_size: uint64 = sp.obj_size
elif (uint64(ptr) & 0xFFF) == 0:
real_hdr_r: uint64 = uint64(ptr) - 8
block_r: memory_block | t.CPtr
c.Asm(f"""mov rax, [{c.AsmInp(t.CVoid(real_hdr_r, t.CPtr), t.ASM_DESCR.REG_ANY)}]
mov {c.AsmOut(block_r, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
old_size = block_r.size - 4096
else:
block2: memory_block | t.CPtr = t.CPtr(t.CUInt64T(ptr) - memory_block.__sizeof__())
block2: memory_block | t.CPtr = t.CPtr(uint64(ptr) - memory_block.__sizeof__())
old_size = block2.size - memory_block.__sizeof__()
copy_size: t.CUInt64T = old_size if old_size < size else size
copy_size: uint64 = old_size if old_size < size else size
string.memcpy(new_ptr, ptr, copy_size)
free(ptr)
return new_ptr
@@ -500,7 +500,7 @@ def free_memory_regions() -> t.CStatic | t.CVoid:
memory_regions = None
# 初始化内存管理系统
def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt64T, FbAddr: t.CUInt64T = 0, FbSize: t.CUInt64T = 0):
def init(MemmapAddr: uint64, MemmapSize: uint64, MemmapDescSize: uint64, FbAddr: uint64 = 0, FbSize: uint64 = 0):
global BuddySystemObject
import drivers.serial.uart.serial as serial
# [DBG] 无条件打印 memmap 三参数,判定分支未走的根因(用后移除)
@@ -508,43 +508,43 @@ def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt
viperlib.snprintf(c.Addr(_dk0), 100, "[mm] raw addr=0x%lx size=%lu desc=%lu\n",
MemmapAddr, MemmapSize, MemmapDescSize)
serial.puts(c.Addr(_dk0))
start_addr: t.CVoid | t.CPtr = None
size: t.CUInt64T = 0
start_addr: t.CPtr = None
size: uint64 = 0
if MemmapAddr != 0:
if MemmapSize > 0:
if MemmapDescSize > 0:
num_entries: t.CUInt64T = MemmapSize / MemmapDescSize
num_entries: uint64 = MemmapSize / MemmapDescSize
# [DBG] 关键数值:memmap 缓冲/步长/条目数(用后移除)
_dk1: t.CArray[t.CChar, 100]
viperlib.snprintf(c.Addr(_dk1), 100, "[mm] addr=0x%lx size=%lu desc=%lu entries=%lu\n",
MemmapAddr, MemmapSize, MemmapDescSize, num_entries)
serial.puts(c.Addr(_dk1))
max_memory: t.CUInt64T = 0
best_start: t.CUInt64T = 0
best_avail_size: t.CUInt64T = 0
best_avail_start: t.CUInt64T = 0
best_bs_size: t.CUInt64T = 0
best_bs_start: t.CUInt64T = 0
best_ld_size: t.CUInt64T = 0
best_ld_start: t.CUInt64T = 0
i: t.CUInt64T
max_memory: uint64 = 0
best_start: uint64 = 0
best_avail_size: uint64 = 0
best_avail_start: uint64 = 0
best_bs_size: uint64 = 0
best_bs_start: uint64 = 0
best_ld_size: uint64 = 0
best_ld_start: uint64 = 0
i: uint64
# [DBG] 转储全部 memmap 描述符,定位 4GB 伪可用区的来源(用后移除)
for i in range(num_entries):
entry: bootinfo.memory_map_entry | t.CPtr = t.CVoid(MemmapAddr + i * MemmapDescSize, t.CPtr)
_dbgd: t.CArray[t.CChar, 100]
viperlib.snprintf(c.Addr(_dbgd), 100, "[mm] d[%lu] t=%lu start=0x%lx np=%lu\n",
i, t.CUInt64T(entry.type), entry.physical_start, entry.num_pages)
i, uint64(entry.type), entry.physical_start, entry.num_pages)
serial.puts(c.Addr(_dbgd))
for i in range(num_entries):
entry: bootinfo.memory_map_entry | t.CPtr = t.CVoid(MemmapAddr + i * MemmapDescSize, t.CPtr)
etype: t.CUInt64T = entry.type
start: t.CUInt64T = align_4k(entry.physical_start)
np: t.CUInt64T = entry.num_pages
end: t.CUInt64T = entry.physical_start + np * 4096
etype: uint64 = entry.type
start: uint64 = align_4k(entry.physical_start)
np: uint64 = entry.num_pages
end: uint64 = entry.physical_start + np * 4096
end = align_4k(end - 1)
region_size: t.CUInt64T = end - start
region_size: uint64 = end - start
if FbAddr != 0 and FbSize != 0:
fb_end: t.CUInt64T = FbAddr + FbSize
fb_end: uint64 = FbAddr + FbSize
if start < fb_end and end > FbAddr:
continue
if etype == MEMORY_TYPE_AVAILABLE:
@@ -559,7 +559,7 @@ def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt
if region_size > best_ld_size:
best_ld_size = region_size
best_ld_start = start
min_blk: t.CUInt64T = MIN_BLOCK_SIZE
min_blk: uint64 = MIN_BLOCK_SIZE
if best_avail_size >= min_blk:
best_start = best_avail_start
max_memory = best_avail_size
@@ -584,7 +584,7 @@ def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt
viperlib.snprintf(c.Addr(_dc0), 100, "[mm] fallback cmos 0x%02x 0x%02x 0x%02x 0x%02x\n",
cmos_read(0x15), cmos_read(0x16), cmos_read(0x17), cmos_read(0x18))
serial.puts(c.Addr(_dc0))
_dsz: t.CUInt64T = detect_memory_size()
_dsz: uint64 = detect_memory_size()
viperlib.snprintf(c.Addr(_dc0), 100, "[mm] fallback detect=%lu\n", _dsz)
serial.puts(c.Addr(_dc0))
size = detect_memory_size()
@@ -595,13 +595,13 @@ def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt
if size > 0x400000:
size = size - 0x400000
size = align_4k(size)
min_blk2: t.CUInt64T = MIN_BLOCK_SIZE
min_blk2: uint64 = MIN_BLOCK_SIZE
if size < min_blk2:
size = 33554432
cr2: t.CArray[t.CChar, 128]
string.memset(c.Addr(cr2), 0, 128)
viperlib.snprintf(c.Addr(cr2), 128, "mm.init: start=0x%lx size=%lu bytes\n",
t.CUInt64T(start_addr), size)
uint64(start_addr), size)
serial.puts(cr2)
BuddySystemObject.__init__(start_addr, size)
SlabAllocator.__init__()
@@ -609,10 +609,10 @@ def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt
# 虚拟内存映射结构
class vm_area(t.CStruct):
VirtAddr: t.CUInt64T
PhysAddr: t.CUInt64T
size: t.CUInt64T
flags: t.CUInt32T
VirtAddr: uint64
PhysAddr: uint64
size: uint64
flags: uint32
next: 'vm_area' | t.CPtr
# 全局虚拟内存区域链表
@@ -623,15 +623,15 @@ ALLOCATION_RETRIES: t.CDefine = 5 # 分配重试次数
FRAGMENTATION_THRESHOLD: t.CDefine = 0.7 # 碎片率阈值
# 获取内存使用统计
@c.CReturn(t.CUInt64T, t.CUInt64T, t.CUInt64T)
@c.CReturn(uint64, uint64, uint64)
def GetMemoryStats():
return (BuddySystemObject.buddy.total_memory, BuddySystemObject.buddy.used_memory, BuddySystemObject.buddy.free_memory)
# 计算内存碎片率
def calculate_fragmentation() -> t.CDouble:
# 计算空闲块的数量和总大小
free_blocks: t.CInt = 0
free_size: t.CUInt64T = 0
free_blocks: int = 0
free_size: uint64 = 0
for i in range(MAX_ORDER + 1):
block: memory_block | t.CPtr = BuddySystemObject.buddy.free_lists[i]
@@ -646,7 +646,7 @@ def calculate_fragmentation() -> t.CDouble:
# 计算碎片率
# 碎片率 = 1 - (最大空闲块大小 / 总空闲内存大小)
max_free_block: t.CUInt64T = 0
max_free_block: uint64 = 0
for i in range(MAX_ORDER, -1, -1):
if BuddySystemObject.buddy.free_lists[i]:
max_free_block = get_block_size(i)
@@ -658,8 +658,8 @@ def calculate_fragmentation() -> t.CDouble:
return 1.0 - (t.CDouble(max_free_block) / t.CDouble(free_size))
# 内存整理函数
def compact_memory() -> t.CStatic | t.CInt:
freed_pages: t.CInt = 0
def compact_memory() -> t.CStatic | int:
freed_pages: int = 0
for sc in range(SLAB_NUM_SIZES):
page: slab_page | t.CPtr = SlabAllocator.caches[sc]
while page:
@@ -678,14 +678,14 @@ def compact_memory() -> t.CStatic | t.CInt:
return freed_pages
# 虚拟内存分配函数
def vm_alloc(size: t.CUInt64T, flags: t.CUInt32T) -> t.CUInt64T:
def vm_alloc(size: uint64, flags: uint32) -> uint64:
global vm_areas
# 4K对齐
size = align_4k(size)
# 尝试分配物理内存,使用博弈机制
PhysAddr: t.CVoid | t.CPtr = None
retries: t.CInt = 0
PhysAddr: t.CPtr = None
retries: int = 0
while retries < ALLOCATION_RETRIES:
PhysAddr = malloc(size)
@@ -703,7 +703,7 @@ def vm_alloc(size: t.CUInt64T, flags: t.CUInt32T) -> t.CUInt64T:
# 分配虚拟地址
# 简单的虚拟地址分配策略:从0x100000000开始
VirtAddr: t.CUInt64T = 0x100000000
VirtAddr: uint64 = 0x100000000
current: vm_area | t.CPtr = vm_areas
# 寻找合适的虚拟地址空间
@@ -717,7 +717,7 @@ def vm_alloc(size: t.CUInt64T, flags: t.CUInt32T) -> t.CUInt64T:
area: vm_area | t.CPtr = malloc(vm_area.__sizeof__())
if area:
area.VirtAddr = VirtAddr
area.PhysAddr = t.CUInt64T(PhysAddr)
area.PhysAddr = uint64(PhysAddr)
area.size = size
area.flags = flags
area.next = vm_areas
@@ -725,18 +725,18 @@ def vm_alloc(size: t.CUInt64T, flags: t.CUInt32T) -> t.CUInt64T:
# 映射虚拟地址到物理地址
# 计算需要映射的页数
pages: t.CUInt64T = size / 4096
i: t.CUInt64T
pages: uint64 = size / 4096
i: uint64
for i in range(pages):
page_virt: t.CUInt64T = VirtAddr + (i * 4096)
page_phys: t.CUInt64T = t.CUInt64T(PhysAddr) + (i * 4096)
page_virt: uint64 = VirtAddr + (i * 4096)
page_phys: uint64 = uint64(PhysAddr) + (i * 4096)
# 调用paging模块的映射函数
paging.MapPage(page_virt, page_phys, flags)
return VirtAddr
# 虚拟内存释放函数
def vm_free(VirtAddr: t.CUInt64T):
def vm_free(VirtAddr: uint64):
global vm_areas
# 查找虚拟内存区域
current: vm_area | t.CPtr = vm_areas
@@ -745,10 +745,10 @@ def vm_free(VirtAddr: t.CUInt64T):
while current:
if current.VirtAddr == VirtAddr:
# 取消虚拟地址映射
pages: t.CUInt64T = current.size / 4096
i: t.CUInt64T
pages: uint64 = current.size / 4096
i: uint64
for i in range(pages):
page_virt: t.CUInt64T = current.VirtAddr + (i * 4096)
page_virt: uint64 = current.VirtAddr + (i * 4096)
paging.UnMapPage(page_virt)
# 释放物理内存
@@ -763,42 +763,42 @@ def vm_free(VirtAddr: t.CUInt64T):
current = current.next
# CMOS读取函数
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
def cmos_read(reg: uint8) -> uint8:
# in/out al 会改 EAX,必须 CLOBBER_RAX;显式 mov 到输出寄存器
#(与 asm.inb/inw 修复同模式,避免调用方 EAX 被静默破坏)。
c.Asm(f"""mov eax, {c.AsmInp(t.CUInt32T(reg), t.ASM_DESCR.REG_ANY)}
c.Asm(f"""mov eax, {c.AsmInp(uint32(reg), t.ASM_DESCR.REG_ANY)}
out 0x70, al""",
op=[t.ASM_DESCR.CLOBBER_RAX])
val32: t.CUInt32T
val32: uint32
c.Asm(f"""in al, 0x71
movzx eax, al
mov {c.AsmOut(val32, t.ASM_DESCR.OUTPUT_REG)}, eax""",
out=[c.AsmOut(val32, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_RAX])
return t.CUInt8T(val32)
return uint8(val32)
# 内存大小测试函数
def detect_memory_size() -> t.CUInt64T:
def detect_memory_size() -> uint64:
# 读取 1MB-16MB 扩展内存(KB 单位)
low: t.CUInt8T = cmos_read(0x15)
high: t.CUInt8T = cmos_read(0x16)
mem_kb: t.CUInt32T = (t.CUInt32T(high) << 8) | low
low: uint8 = cmos_read(0x15)
high: uint8 = cmos_read(0x16)
mem_kb: uint32 = (uint32(high) << 8) | low
# 读取 16MB 以上扩展内存(64KB 块为单位)
low2: t.CUInt8T = cmos_read(0x17)
high2: t.CUInt8T = cmos_read(0x18)
mem_above_16mb: t.CUInt32T = (t.CUInt32T(high2) << 8) | low2
low2: uint8 = cmos_read(0x17)
high2: uint8 = cmos_read(0x18)
mem_above_16mb: uint32 = (uint32(high2) << 8) | low2
# 两个寄存器都为 0 时使用默认值
if mem_kb == 0 and mem_above_16mb == 0:
return 0x10000000 # 256MB
# 计算总内存:1MB 基础 + 1MB-16MB + 16MB 以上
total_size: t.CUInt64T = 1048576 # 前 1MB
total_size: uint64 = 1048576 # 前 1MB
if mem_kb > 0:
total_size = total_size + t.CUInt64T(mem_kb) * 1024
total_size = total_size + uint64(mem_kb) * 1024
if mem_above_16mb > 0:
total_size = total_size + t.CUInt64T(mem_above_16mb) * 65536
total_size = total_size + uint64(mem_above_16mb) * 65536
total_size = align_4k(total_size)
+479 -479
View File
@@ -1,479 +1,479 @@
import drivers.serial.uart.serial as serial
import viperlib
import t, c
PTE_PRESENT: t.CDefine = (1 << 0)
PTE_WRITABLE: t.CDefine = (1 << 1)
PTE_USER: t.CDefine = (1 << 2)
PTE_PWT: t.CDefine = (1 << 3)
PTE_PCD: t.CDefine = (1 << 4)
PTE_ACCESSED: t.CDefine = (1 << 5)
PTE_DIRTY: t.CDefine = (1 << 6)
PTE_PS: t.CDefine = (1 << 7)
PTE_GLOBAL: t.CDefine = (1 << 8)
class _p:
entries: t.CArray[t.CUInt64T, 512]
PT_POOL_PAGES: t.CDefine = 512
pt_pool_raw: t.CVoid | t.CPtr = None
pt_pool_start: t.CUInt64T = 0
pt_pool_used: t.CUInt64T = 0
AllocatedPages: t.CUInt64T = 0
pml4: _p | t.CPtr = None
pdp: _p | t.CPtr
pd: _p | t.CPtr
pt: _p | t.CPtr
def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T):
global pml4
pml4 = GetCurrentPml4()
# bootloader/UEFI 的 CR0.WP 通常已是 1(原代码清 WP 正因此)。页表页
# (pml4/pdp/pd/pt,0xf8xxxx)默认只读,而内核运行时 MapPage/clone 需
# 修改页表。顺序:先清 WP(允许写只读页表页)→ MakePTWritable 放开
# 全部页表页 → 再置 WP=1(此后写只读页即 #PF 暴露越界写源)。
c.Asm(f"""
mov rax, cr0
and rax, ~0x10000
mov cr0, rax
""")
MakePTWritable()
c.Asm(f"""
mov rax, cr0
or rax, 0x10000
mov cr0, rax
""")
def init_pool(buf: t.CVoid | t.CPtr, buf_size: t.CUInt64T):
global pt_pool_raw, pt_pool_start, pt_pool_used
pt_pool_raw = buf
if buf is None: return
raw_addr: t.CUInt64T = t.CUInt64T(buf)
aligned_addr: t.CUInt64T = (raw_addr + t.CUInt64T(0xFFF)) & ~t.CUInt64T(0xFFF)
pt_pool_start = aligned_addr
pt_pool_used = 0
# [DIAG] 定位 clone 时 pt_pool_raw=0x0(init 后被覆盖?还是 init 收到 0)
_dip: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(_dip), 80, "[paging] init_pool raw=0x%lx start=0x%lx\n", t.CUInt64T(pt_pool_raw), pt_pool_start)
serial.puts(c.Addr(_dip))
def AllocPage() -> t.CVoid | t.CPtr:
global AllocatedPages, pt_pool_used, pml4, pdp, pd, pt
if pt_pool_raw is None: return None
if pt_pool_used >= t.CUInt64T(PT_POOL_PAGES): return None
page: t.CVoid | t.CPtr = t.CVoid(pt_pool_start + pt_pool_used * t.CUInt64T(4096), t.CPtr)
pt_pool_used = pt_pool_used + t.CUInt64T(1)
c.Asm(f"""mov al, 0
mov ecx, 4096
mov rdi, {c.AsmInp(page, t.ASM_DESCR.REG_ANY)}
rep stosb""",
op = [t.ASM_DESCR.CLOBBER_AL, t.ASM_DESCR.CLOBBER_ECX, t.ASM_DESCR.CLOBBER_RDI])
AllocatedPages = AllocatedPages + t.CUInt64T(1)
return page
def FreePage(page: t.CVoid | t.CPtr):
global AllocatedPages, pml4, pdp, pd, pt
if page is None: return
if AllocatedPages > 0: AllocatedPages = AllocatedPages - t.CUInt64T(1)
def MapPage(VirtAddr: t.CUInt64T, PhysAddr: t.CUInt64T, flags: t.CUInt64T):
global pml4, pdp, pd, pt
if VirtAddr == 0 or PhysAddr == 0: return
VirtAddr = VirtAddr & ~t.CUInt64T(0xFFF)
PhysAddr = PhysAddr & ~t.CUInt64T(0xFFF)
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
PtIndex: t.CUInt64T = (VirtAddr >> 12) & 0x1FF
if not pml4:
pml4 = AllocPage()
if not pml4: return
if not (pml4.entries[Pml4Index] & PTE_PRESENT):
pdp: _p | t.CPtr = AllocPage()
if not pdp: return
pml4.entries[Pml4Index] = (t.CUInt64T(pdp) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
if (flags & PTE_USER) and not (pml4.entries[Pml4Index] & PTE_USER):
pml4.entries[Pml4Index] = pml4.entries[Pml4Index] | PTE_USER
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
pd: _p | t.CPtr = AllocPage()
if not pd: return
pdp.entries[PdpIndex] = (t.CUInt64T(pd) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
if (flags & PTE_USER) and not (pdp.entries[PdpIndex] & PTE_USER):
pdp.entries[PdpIndex] = pdp.entries[PdpIndex] | PTE_USER
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if pd.entries[PdIndex] & 1:
if pd.entries[PdIndex] & 0x80:
big_phys: t.CUInt64T = pd.entries[PdIndex] & ~t.CUInt64T(0x1FFFFF)
inherit_flags: t.CUInt64T = pd.entries[PdIndex] & (PTE_PCD | PTE_PWT)
pt: _p | t.CPtr = AllocPage()
if not pt: return
split_i: t.CInt = 0
while split_i < 512:
pt.entries[split_i] = (big_phys + t.CUInt64T(split_i) * 0x1000) | PTE_PRESENT | PTE_WRITABLE | inherit_flags
split_i += 1
pd.entries[PdIndex] = (t.CUInt64T(pt) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
# PD entry exists as a regular PT (e.g. cloned identity mapping).
# Must propagate PTE_USER to the PD entry so user-mode access is
# allowed at all paging levels, otherwise #PF err=0x5.
if (flags & PTE_USER) and not (pd.entries[PdIndex] & PTE_USER):
pd.entries[PdIndex] = pd.entries[PdIndex] | PTE_USER
else:
pt: _p | t.CPtr = AllocPage()
if not pt: return
pd.entries[PdIndex] = (t.CUInt64T(pt) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt.entries[PtIndex] = PhysAddr | flags | PTE_PRESENT
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def MapLargePage(VirtAddr: t.CUInt64T, PhysAddr: t.CUInt64T, flags: t.CUInt64T) -> t.CVoid:
global pml4, pdp, pd, pt
VirtAddr = VirtAddr & ~t.CUInt64T(0x1FFFFF)
PhysAddr = PhysAddr & ~t.CUInt64T(0x1FFFFF)
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
if not pml4:
pml4 = AllocPage()
if not pml4: return
if not pml4.entries[Pml4Index] & PTE_PRESENT:
pdp: _p | t.CPtr = AllocPage()
if not pdp: return
pml4.entries[Pml4Index] = (t.CUInt64T(pdp) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
pd: _p | t.CPtr = AllocPage()
if not pd: return
pdp.entries[PdpIndex] = (t.CUInt64T(pd) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd.entries[PdIndex] = PhysAddr | flags | PTE_PRESENT | PTE_PS
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def UnMapPage(VirtAddr: t.CUInt64T):
global pml4, pdp, pd, pt
if VirtAddr == 0: return
if not pml4: return
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
PtIndex: t.CUInt64T = (VirtAddr >> 12) & 0x1FF
if not pml4.entries[Pml4Index] & PTE_PRESENT: return
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not pdp.entries[PdpIndex] & PTE_PRESENT: return
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not pd.entries[PdIndex] & PTE_PRESENT: return
if pd.entries[PdIndex] & PTE_PS:
pd.entries[PdIndex] = 0
else:
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt.entries[PtIndex] = 0
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def EnablePaging():
global pml4, pdp, pd, pt
c.Asm(f"mov cr3, {c.AsmInp(t.CUInt64T(pml4), t.ASM_DESCR.REG_ANY)}")
def _set_page_writable(phys_addr: t.CUInt64T):
"""把物理页 phys_addr(identity 映射,虚拟=物理)的 PTE 置 W 位
页表页(bootloader 建立的 pml4/pdp/pd/pt 位于 0xf8xxxx)默认只读,
而内核运行时 MapPage/clone 需修改页表 → 必须先把这些页表页自身设为可写,
否则 CR0.WP=1 下写页表触发 #PF(slog.so 映射 0x600000 新建页表项时
cr2=0xf801000 err=0x3 根因)。
"""
global pml4
if not pml4: return
va: t.CUInt64T = phys_addr & ~t.CUInt64T(0xFFF)
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): return
pdp_s: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
if not (pdp_s.entries[pdp_idx] & PTE_PRESENT): return
pd_s: _p | t.CPtr = t.CType(pdp_s.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
if not (pd_s.entries[pd_idx] & PTE_PRESENT): return
if pd_s.entries[pd_idx] & PTE_PS:
# 2MB 大页:W 位在 PD 条目自身(无下层 PT),直接置位
pd_s.entries[pd_idx] = pd_s.entries[pd_idx] | t.CUInt64T(PTE_WRITABLE)
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
return
pt_s: _p | t.CPtr = t.CType(pd_s.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
pt_s.entries[pt_idx] = pt_s.entries[pt_idx] | t.CUInt64T(PTE_WRITABLE)
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
def MakePTWritable():
"""把当前页表层次所有页表页(pml4 自身 + pdp/pd/pt)设为可写
内核运行时需修改页表(MapPage/clone_for_process),而 bootloader 建立的
页表页映射为只读——CR0.WP=1 下必须先放开页表页自身,否则写页表即 #PF。
"""
global pml4
if not pml4: return
_set_page_writable(t.CUInt64T(pml4))
pi: t.CUInt64T
for pi in range(512):
if not (pml4.entries[pi] & PTE_PRESENT): continue
pdp_m: _p | t.CPtr = t.CType(pml4.entries[pi] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
_set_page_writable(t.CUInt64T(pdp_m))
pj: t.CUInt64T
for pj in range(512):
if not (pdp_m.entries[pj] & PTE_PRESENT): continue
pd_m: _p | t.CPtr = t.CType(pdp_m.entries[pj] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
_set_page_writable(t.CUInt64T(pd_m))
pk: t.CUInt64T
for pk in range(512):
if not (pd_m.entries[pk] & PTE_PRESENT): continue
if pd_m.entries[pk] & PTE_PS: continue
pt_m: _p | t.CPtr = t.CType(pd_m.entries[pk] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
_set_page_writable(t.CUInt64T(pt_m))
def MakeRangeRO(vaddr_start: t.CUInt64T, vaddr_end: t.CUInt64T):
"""把 [vaddr_start, vaddr_end) 范围内所有页的 PTE 清 W 位(只读)
定位越界写源:内核态写只读页在 CR0.WP=1 下触发 #PF(int=14),
isrCommonhandler 打印 cr2/rip → 写源立即暴露,不再静默破坏 .rodata。
"""
global pml4
if not pml4: return
va: t.CUInt64T = vaddr_start & ~t.CUInt64T(0xFFF)
# ro_end 下取整到页:不保护含 ro_end 的未对齐尾页。链接脚本输出段未页对齐,
# .data 紧跟 .rodata(__rodata_end 未对齐时 .data 起始落在 rodata 尾页内),
# 整页置只读会把 .data 全局(如 devfs @DevFSObject=0x141630)误保护 →
# devfs_init 写全局 #PF(cr2=0x141630 rip=0x101aaa mov [r15],rax 根因)。
# 尾页含少量 rodata 尾部(对齐填充),保持可写可容忍。
ro_end_align: t.CUInt64T = vaddr_end & ~t.CUInt64T(0xFFF)
while va < ro_end_align:
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue
pdp_r: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
if not (pdp_r.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue
pd_r: _p | t.CPtr = t.CType(pdp_r.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
if not (pd_r.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue
if pd_r.entries[pd_idx] & PTE_PS:
# 2MB 大页:直接跳过会让 .rodata 保持可写——越界写被静默吞掉
# (perf 格式串 win=%lu/work=%lu 被逐步破坏的根因)。拆分为 512
# 个 4KB 页(复用 MapPage 的分裂逻辑),再走下方常规路径清 W 位。
# WP=1 后内核态写只读页即 #PF → isrCommonhandler 打印 cr2/rip 暴露写源。
big_phys: t.CUInt64T = pd_r.entries[pd_idx] & ~t.CUInt64T(0x1FFFFF)
inherit_flags: t.CUInt64T = pd_r.entries[pd_idx] & (PTE_PCD | PTE_PWT | PTE_USER | t.CUInt64T(0x8000000000000000))
pt_split: _p | t.CPtr = AllocPage()
if not pt_split:
va += 0x1000
continue
split_i: t.CInt = 0
while split_i < 512:
pt_split.entries[split_i] = (big_phys + t.CUInt64T(split_i) * t.CUInt64T(0x1000)) \
| PTE_PRESENT | PTE_WRITABLE | inherit_flags
split_i += 1
pd_r.entries[pd_idx] = (t.CUInt64T(pt_split) & ~t.CUInt64T(0xFFF)) \
| PTE_PRESENT | PTE_WRITABLE | (pd_r.entries[pd_idx] & PTE_USER)
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
# 分裂后落入下方 4KB 常规路径,继续清当前页 W 位
pt_r: _p | t.CPtr = t.CType(pd_r.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
pt_r.entries[pt_idx] = pt_r.entries[pt_idx] & ~t.CUInt64T(PTE_WRITABLE)
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
va += 0x1000
def ProtectKernelRO():
"""把内核镜像 .rodata 段(字符串常量/vtable 等)映射为只读
地址经 c.Asm 内联引用链接器符号 __rodata_start/__rodata_end
(linker.ld 定义,TPV 不声明 extern——避免生成定义与链接器符号冲突)。
"""
global pml4
if not pml4: return
# 页表页可写已在 paging.init(WP=0 阶段)由 MakePTWritable 完成,
# 此处只保护 .rodata 内容页(WP=1 后写只读页即 #PF 暴露写源)。
ro_start: t.CUInt64T = 0
ro_end: t.CUInt64T = 0
c.Asm(f"""lea rax, [rip + __rodata_start]
mov {c.AsmOut(ro_start, t.ASM_DESCR.OUTPUT_REG)}, rax
lea rax, [rip + __rodata_end]
mov {c.AsmOut(ro_end, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
MakeRangeRO(ro_start, ro_end)
# [PG] 打印 .rodata 起始页映射:确认只读真正生效。
# ps=1 说明仍在 2MB 大页(分裂失败)→ .rodata 保持可写 → 越界写继续被静默吞掉。
DumpMapping(ro_start, "ro_s")
def DumpMapping(va: t.CUInt64T, tag: t.CConst | str):
"""[PG] 打印指定 VA 的 pml4/pdp/pd/pt 条目,定位大页(PS)与权限位
内核区域若为 UEFI 2MB 大页,MakeRangeRO 无法只读 .rodata(越界写静默破坏
格式串);1GB 页同理(PS 位在 pdpe)。W=1 且 PS=1 → 该页可写且是大页。
"""
global pml4
if not pml4: return
pml4_i: t.CUInt64T = (va >> 39) & 0x1FF
pdp_i: t.CUInt64T = (va >> 30) & 0x1FF
pd_i: t.CUInt64T = (va >> 21) & 0x1FF
pt_i: t.CUInt64T = (va >> 12) & 0x1FF
pml4_e: t.CUInt64T = pml4.entries[pml4_i]
pdp_e: t.CUInt64T = 0
pd_e: t.CUInt64T = 0
pt_e: t.CUInt64T = 0
if pml4_e & PTE_PRESENT:
pdp_r: _p | t.CPtr = t.CType(pml4_e & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pdp_e = pdp_r.entries[pdp_i]
if pdp_e & PTE_PRESENT:
if pdp_e & PTE_PS:
pd_e = pdp_e
else:
pd_r: _p | t.CPtr = t.CType(pdp_e & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd_e = pd_r.entries[pd_i]
if (pd_e & PTE_PRESENT) and not (pd_e & PTE_PS):
pt_r: _p | t.CPtr = t.CType(pd_e & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt_e = pt_r.entries[pt_i]
buf_d: t.CArray[t.CChar, 200]
viperlib.snprintf(c.Addr(buf_d), 200, "[PG] %s va=0x%lx pdpe=0x%lx pde=0x%lx pte=0x%lx (ps=%d W=%d)\n",
tag, va, pdp_e, pd_e, pt_e,
1 if (pd_e & PTE_PS) else 0,
1 if (pt_e & PTE_WRITABLE) or (pd_e & PTE_WRITABLE) or (pdp_e & PTE_WRITABLE) else 0)
serial.puts(c.Addr(buf_d))
def GetCurrentPml4() -> _p | t.CPtr:
global pml4, pdp, pd, pt
cr3: t.CUInt64T
c.Asm(f"mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3")
return (_p | t.CPtr)(cr3 & ~t.CUInt64T(0xFFF))
def create_process_page_table() -> t.CUInt64T:
global pml4
if not pml4: return 0
new_pml4: _p | t.CPtr = AllocPage()
if not new_pml4: return 0
i: t.CUInt64T
for i in range(512):
entry: t.CUInt64T = pml4.entries[i]
if entry & PTE_PRESENT:
new_pml4.entries[i] = entry
return t.CUInt64T(new_pml4)
def clone_for_process(isolate_vaddr: t.CUInt64T) -> t.CUInt64T:
global pml4
_dbg: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg), 120, "[clone] pml4=0x%lx pool_used=%lu iso_va=0x%lx\n", t.CUInt64T(pml4), pt_pool_used, isolate_vaddr)
serial.puts(_dbg)
if not pml4: return 0
new_pml4_page: _p | t.CPtr = AllocPage()
if not new_pml4_page:
# [DIAG] 定位 AllocPage 失败:pool_used 打印 0 但分配失败 → BSS 全局
# (pt_pool_raw/pt_pool_used)疑似被内存越界写覆盖。
_dbgf: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbgf), 120, "[clone] AllocPage FAIL raw=0x%lx used=%lu PP=%d\n",
t.CUInt64T(pt_pool_raw), pt_pool_used, PT_POOL_PAGES)
serial.puts(c.Addr(_dbgf))
serial.puts("[clone] AllocPage pml4 failed\n")
return 0
_dbg2: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg2), 120, "[clone] new_pml4=0x%lx\n", t.CUInt64T(new_pml4_page))
serial.puts(_dbg2)
i: t.CUInt64T
for i in range(512):
new_pml4_page.entries[i] = pml4.entries[i]
pml4_idx: t.CUInt64T = (isolate_vaddr >> 39) & 0x1FF
_dbg3: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg3), 120, "[clone] pml4_idx=%lu entry0=0x%lx\n", pml4_idx, pml4.entries[pml4_idx])
serial.puts(_dbg3)
if not (pml4.entries[pml4_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
kernel_pdp: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
new_pdp_page: _p | t.CPtr = AllocPage()
if not new_pdp_page: return t.CUInt64T(new_pml4_page)
for i in range(512):
new_pdp_page.entries[i] = kernel_pdp.entries[i]
new_pml4_page.entries[pml4_idx] = (t.CUInt64T(new_pdp_page) & ~t.CUInt64T(0xFFF)) | (pml4.entries[pml4_idx] & t.CUInt64T(0xFFF))
pdp_idx: t.CUInt64T = (isolate_vaddr >> 30) & 0x1FF
if not (kernel_pdp.entries[pdp_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
kernel_pd: _p | t.CPtr = t.CType(kernel_pdp.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
new_pd_page: _p | t.CPtr = AllocPage()
if not new_pd_page: return t.CUInt64T(new_pml4_page)
for i in range(512):
new_pd_page.entries[i] = kernel_pd.entries[i]
new_pdp_page.entries[pdp_idx] = (t.CUInt64T(new_pd_page) & ~t.CUInt64T(0xFFF)) | (kernel_pdp.entries[pdp_idx] & t.CUInt64T(0xFFF))
pd_idx: t.CUInt64T = (isolate_vaddr >> 21) & 0x1FF
if not (kernel_pd.entries[pd_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
if kernel_pd.entries[pd_idx] & PTE_PS: return t.CUInt64T(new_pml4_page)
kernel_pt: _p | t.CPtr = t.CType(kernel_pd.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
new_pt_page: _p | t.CPtr = AllocPage()
if not new_pt_page: return t.CUInt64T(new_pml4_page)
for i in range(512):
new_pt_page.entries[i] = kernel_pt.entries[i]
new_pd_page.entries[pd_idx] = (t.CUInt64T(new_pt_page) & ~t.CUInt64T(0xFFF)) | (kernel_pd.entries[pd_idx] & t.CUInt64T(0xFFF))
return t.CUInt64T(new_pml4_page)
def save_pt_range(vaddr_start: t.CUInt64T, vaddr_end: t.CUInt64T, save_buf: t.CUInt64T | t.CPtr, save_count: t.CUInt32T | t.CPtr) -> t.CInt:
global pml4
if not pml4: return -1
# c.Set(a,b)=a=b(改指针变量本身);写所指地址必须 c.Set(c.Deref(a),b)
c.Set(c.Deref(save_count), t.CUInt32T(0))
va: t.CUInt64T = vaddr_start & ~t.CUInt64T(0xFFF)
while va < vaddr_end:
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
if not (pd_.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue
if pd_.entries[pd_idx] & PTE_PS: va += 0x200000; continue
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
saved: t.CUInt32T = c.DerefAs(save_count)
entry_ptr: t.CUInt64T | t.CPtr = save_buf + t.CUInt64T(saved) * 16
c.DerefAs(entry_ptr, va)
c.DerefAs(entry_ptr + 8, pt_.entries[pt_idx])
c.Set(c.Deref(save_count), t.CUInt32T(saved + 1))
va += 0x1000
return 0
def restore_pt_range(save_buf: t.CUInt64T | t.CPtr, save_count: t.CUInt32T):
global pml4
if not pml4: return
i: t.CUInt32T = 0
while i < save_count:
entry_ptr: t.CUInt64T | t.CPtr = save_buf + t.CUInt64T(i) * 16
va: t.CUInt64T = c.DerefAs(entry_ptr)
orig_pte: t.CUInt64T = c.DerefAs(entry_ptr + 8)
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): i += 1; continue
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): i += 1; continue
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
if not (pd_.entries[pd_idx] & PTE_PRESENT): i += 1; continue
if pd_.entries[pd_idx] & PTE_PS: i += 1; continue
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
pt_.entries[pt_idx] = orig_pte
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]", op=[t.ASM_DESCR.CLOBBER_MEMORY])
i += 1
def set_active_pml4(cr3_val: t.CUInt64T):
global pml4
pml4 = (_p | t.CPtr)(cr3_val & ~t.CUInt64T(0xFFF))
import drivers.serial.uart.serial as serial
import viperlib
import t, c
PTE_PRESENT: t.CDefine = (1 << 0)
PTE_WRITABLE: t.CDefine = (1 << 1)
PTE_USER: t.CDefine = (1 << 2)
PTE_PWT: t.CDefine = (1 << 3)
PTE_PCD: t.CDefine = (1 << 4)
PTE_ACCESSED: t.CDefine = (1 << 5)
PTE_DIRTY: t.CDefine = (1 << 6)
PTE_PS: t.CDefine = (1 << 7)
PTE_GLOBAL: t.CDefine = (1 << 8)
class _p:
entries: t.CArray[uint64, 512]
PT_POOL_PAGES: t.CDefine = 512
pt_pool_raw: t.CPtr = None
pt_pool_start: uint64 = 0
pt_pool_used: uint64 = 0
AllocatedPages: uint64 = 0
pml4: _p | t.CPtr = None
pdp: _p | t.CPtr
pd: _p | t.CPtr
pt: _p | t.CPtr
def init(MemmapAddr: uint64, MemmapSize: uint64):
global pml4
pml4 = GetCurrentPml4()
# bootloader/UEFI 的 CR0.WP 通常已是 1(原代码清 WP 正因此)。页表页
# (pml4/pdp/pd/pt,0xf8xxxx)默认只读,而内核运行时 MapPage/clone 需
# 修改页表。顺序:先清 WP(允许写只读页表页)→ MakePTWritable 放开
# 全部页表页 → 再置 WP=1(此后写只读页即 #PF 暴露越界写源)。
c.Asm(f"""
mov rax, cr0
and rax, ~0x10000
mov cr0, rax
""")
MakePTWritable()
c.Asm(f"""
mov rax, cr0
or rax, 0x10000
mov cr0, rax
""")
def init_pool(buf: t.CPtr, buf_size: uint64):
global pt_pool_raw, pt_pool_start, pt_pool_used
pt_pool_raw = buf
if buf is None: return
raw_addr: uint64 = uint64(buf)
aligned_addr: uint64 = (raw_addr + uint64(0xFFF)) & ~uint64(0xFFF)
pt_pool_start = aligned_addr
pt_pool_used = 0
# [DIAG] 定位 clone 时 pt_pool_raw=0x0(init 后被覆盖?还是 init 收到 0)
_dip: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(_dip), 80, "[paging] init_pool raw=0x%lx start=0x%lx\n", uint64(pt_pool_raw), pt_pool_start)
serial.puts(c.Addr(_dip))
def AllocPage() -> t.CPtr:
global AllocatedPages, pt_pool_used, pml4, pdp, pd, pt
if pt_pool_raw is None: return None
if pt_pool_used >= uint64(PT_POOL_PAGES): return None
page: t.CPtr = t.CVoid(pt_pool_start + pt_pool_used * uint64(4096), t.CPtr)
pt_pool_used = pt_pool_used + uint64(1)
c.Asm(f"""mov al, 0
mov ecx, 4096
mov rdi, {c.AsmInp(page, t.ASM_DESCR.REG_ANY)}
rep stosb""",
op = [t.ASM_DESCR.CLOBBER_AL, t.ASM_DESCR.CLOBBER_ECX, t.ASM_DESCR.CLOBBER_RDI])
AllocatedPages = AllocatedPages + uint64(1)
return page
def FreePage(page: t.CPtr):
global AllocatedPages, pml4, pdp, pd, pt
if page is None: return
if AllocatedPages > 0: AllocatedPages = AllocatedPages - uint64(1)
def MapPage(VirtAddr: uint64, PhysAddr: uint64, flags: uint64):
global pml4, pdp, pd, pt
if VirtAddr == 0 or PhysAddr == 0: return
VirtAddr = VirtAddr & ~uint64(0xFFF)
PhysAddr = PhysAddr & ~uint64(0xFFF)
Pml4Index: uint64 = (VirtAddr >> 39) & 0x1FF
PdpIndex: uint64 = (VirtAddr >> 30) & 0x1FF
PdIndex: uint64 = (VirtAddr >> 21) & 0x1FF
PtIndex: uint64 = (VirtAddr >> 12) & 0x1FF
if not pml4:
pml4 = AllocPage()
if not pml4: return
if not (pml4.entries[Pml4Index] & PTE_PRESENT):
pdp: _p | t.CPtr = AllocPage()
if not pdp: return
pml4.entries[Pml4Index] = (uint64(pdp) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
if (flags & PTE_USER) and not (pml4.entries[Pml4Index] & PTE_USER):
pml4.entries[Pml4Index] = pml4.entries[Pml4Index] | PTE_USER
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~uint64(0xFFF), _p, t.CPtr)
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
pd: _p | t.CPtr = AllocPage()
if not pd: return
pdp.entries[PdpIndex] = (uint64(pd) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
if (flags & PTE_USER) and not (pdp.entries[PdpIndex] & PTE_USER):
pdp.entries[PdpIndex] = pdp.entries[PdpIndex] | PTE_USER
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~uint64(0xFFF), _p, t.CPtr)
if pd.entries[PdIndex] & 1:
if pd.entries[PdIndex] & 0x80:
big_phys: uint64 = pd.entries[PdIndex] & ~uint64(0x1FFFFF)
inherit_flags: uint64 = pd.entries[PdIndex] & (PTE_PCD | PTE_PWT)
pt: _p | t.CPtr = AllocPage()
if not pt: return
split_i: int = 0
while split_i < 512:
pt.entries[split_i] = (big_phys + uint64(split_i) * 0x1000) | PTE_PRESENT | PTE_WRITABLE | inherit_flags
split_i += 1
pd.entries[PdIndex] = (uint64(pt) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
# PD entry exists as a regular PT (e.g. cloned identity mapping).
# Must propagate PTE_USER to the PD entry so user-mode access is
# allowed at all paging levels, otherwise #PF err=0x5.
if (flags & PTE_USER) and not (pd.entries[PdIndex] & PTE_USER):
pd.entries[PdIndex] = pd.entries[PdIndex] | PTE_USER
else:
pt: _p | t.CPtr = AllocPage()
if not pt: return
pd.entries[PdIndex] = (uint64(pt) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~uint64(0xFFF), _p, t.CPtr)
pt.entries[PtIndex] = PhysAddr | flags | PTE_PRESENT
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def MapLargePage(VirtAddr: uint64, PhysAddr: uint64, flags: uint64) -> t.CVoid:
global pml4, pdp, pd, pt
VirtAddr = VirtAddr & ~uint64(0x1FFFFF)
PhysAddr = PhysAddr & ~uint64(0x1FFFFF)
Pml4Index: uint64 = (VirtAddr >> 39) & 0x1FF
PdpIndex: uint64 = (VirtAddr >> 30) & 0x1FF
PdIndex: uint64 = (VirtAddr >> 21) & 0x1FF
if not pml4:
pml4 = AllocPage()
if not pml4: return
if not pml4.entries[Pml4Index] & PTE_PRESENT:
pdp: _p | t.CPtr = AllocPage()
if not pdp: return
pml4.entries[Pml4Index] = (uint64(pdp) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~uint64(0xFFF), _p, t.CPtr)
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
pd: _p | t.CPtr = AllocPage()
if not pd: return
pdp.entries[PdpIndex] = (uint64(pd) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~uint64(0xFFF), _p, t.CPtr)
pd.entries[PdIndex] = PhysAddr | flags | PTE_PRESENT | PTE_PS
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def UnMapPage(VirtAddr: uint64):
global pml4, pdp, pd, pt
if VirtAddr == 0: return
if not pml4: return
Pml4Index: uint64 = (VirtAddr >> 39) & 0x1FF
PdpIndex: uint64 = (VirtAddr >> 30) & 0x1FF
PdIndex: uint64 = (VirtAddr >> 21) & 0x1FF
PtIndex: uint64 = (VirtAddr >> 12) & 0x1FF
if not pml4.entries[Pml4Index] & PTE_PRESENT: return
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~uint64(0xFFF), _p, t.CPtr)
if not pdp.entries[PdpIndex] & PTE_PRESENT: return
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~uint64(0xFFF), _p, t.CPtr)
if not pd.entries[PdIndex] & PTE_PRESENT: return
if pd.entries[PdIndex] & PTE_PS:
pd.entries[PdIndex] = 0
else:
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~uint64(0xFFF), _p, t.CPtr)
pt.entries[PtIndex] = 0
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def EnablePaging():
global pml4, pdp, pd, pt
c.Asm(f"mov cr3, {c.AsmInp(uint64(pml4), t.ASM_DESCR.REG_ANY)}")
def _set_page_writable(phys_addr: uint64):
"""把物理页 phys_addr(identity 映射,虚拟=物理)的 PTE 置 W 位
页表页(bootloader 建立的 pml4/pdp/pd/pt 位于 0xf8xxxx)默认只读,
而内核运行时 MapPage/clone 需修改页表 → 必须先把这些页表页自身设为可写,
否则 CR0.WP=1 下写页表触发 #PF(slog.so 映射 0x600000 新建页表项时
cr2=0xf801000 err=0x3 根因)。
"""
global pml4
if not pml4: return
va: uint64 = phys_addr & ~uint64(0xFFF)
pml4_idx: uint64 = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): return
pdp_s: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~uint64(0xFFF), _p, t.CPtr)
pdp_idx: uint64 = (va >> 30) & 0x1FF
if not (pdp_s.entries[pdp_idx] & PTE_PRESENT): return
pd_s: _p | t.CPtr = t.CType(pdp_s.entries[pdp_idx] & ~uint64(0xFFF), _p, t.CPtr)
pd_idx: uint64 = (va >> 21) & 0x1FF
if not (pd_s.entries[pd_idx] & PTE_PRESENT): return
if pd_s.entries[pd_idx] & PTE_PS:
# 2MB 大页:W 位在 PD 条目自身(无下层 PT),直接置位
pd_s.entries[pd_idx] = pd_s.entries[pd_idx] | uint64(PTE_WRITABLE)
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
return
pt_s: _p | t.CPtr = t.CType(pd_s.entries[pd_idx] & ~uint64(0xFFF), _p, t.CPtr)
pt_idx: uint64 = (va >> 12) & 0x1FF
pt_s.entries[pt_idx] = pt_s.entries[pt_idx] | uint64(PTE_WRITABLE)
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
def MakePTWritable():
"""把当前页表层次所有页表页(pml4 自身 + pdp/pd/pt)设为可写
内核运行时需修改页表(MapPage/clone_for_process),而 bootloader 建立的
页表页映射为只读——CR0.WP=1 下必须先放开页表页自身,否则写页表即 #PF。
"""
global pml4
if not pml4: return
_set_page_writable(uint64(pml4))
pi: uint64
for pi in range(512):
if not (pml4.entries[pi] & PTE_PRESENT): continue
pdp_m: _p | t.CPtr = t.CType(pml4.entries[pi] & ~uint64(0xFFF), _p, t.CPtr)
_set_page_writable(uint64(pdp_m))
pj: uint64
for pj in range(512):
if not (pdp_m.entries[pj] & PTE_PRESENT): continue
pd_m: _p | t.CPtr = t.CType(pdp_m.entries[pj] & ~uint64(0xFFF), _p, t.CPtr)
_set_page_writable(uint64(pd_m))
pk: uint64
for pk in range(512):
if not (pd_m.entries[pk] & PTE_PRESENT): continue
if pd_m.entries[pk] & PTE_PS: continue
pt_m: _p | t.CPtr = t.CType(pd_m.entries[pk] & ~uint64(0xFFF), _p, t.CPtr)
_set_page_writable(uint64(pt_m))
def MakeRangeRO(vaddr_start: uint64, vaddr_end: uint64):
"""把 [vaddr_start, vaddr_end) 范围内所有页的 PTE 清 W 位(只读)
定位越界写源:内核态写只读页在 CR0.WP=1 下触发 #PF(int=14),
isrCommonhandler 打印 cr2/rip → 写源立即暴露,不再静默破坏 .rodata。
"""
global pml4
if not pml4: return
va: uint64 = vaddr_start & ~uint64(0xFFF)
# ro_end 下取整到页:不保护含 ro_end 的未对齐尾页。链接脚本输出段未页对齐,
# .data 紧跟 .rodata(__rodata_end 未对齐时 .data 起始落在 rodata 尾页内),
# 整页置只读会把 .data 全局(如 devfs @DevFSObject=0x141630)误保护 →
# devfs_init 写全局 #PF(cr2=0x141630 rip=0x101aaa mov [r15],rax 根因)。
# 尾页含少量 rodata 尾部(对齐填充),保持可写可容忍。
ro_end_align: uint64 = vaddr_end & ~uint64(0xFFF)
while va < ro_end_align:
pml4_idx: uint64 = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue
pdp_r: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~uint64(0xFFF), _p, t.CPtr)
pdp_idx: uint64 = (va >> 30) & 0x1FF
if not (pdp_r.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue
pd_r: _p | t.CPtr = t.CType(pdp_r.entries[pdp_idx] & ~uint64(0xFFF), _p, t.CPtr)
pd_idx: uint64 = (va >> 21) & 0x1FF
if not (pd_r.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue
if pd_r.entries[pd_idx] & PTE_PS:
# 2MB 大页:直接跳过会让 .rodata 保持可写——越界写被静默吞掉
# (perf 格式串 win=%lu/work=%lu 被逐步破坏的根因)。拆分为 512
# 个 4KB 页(复用 MapPage 的分裂逻辑),再走下方常规路径清 W 位。
# WP=1 后内核态写只读页即 #PF → isrCommonhandler 打印 cr2/rip 暴露写源。
big_phys: uint64 = pd_r.entries[pd_idx] & ~uint64(0x1FFFFF)
inherit_flags: uint64 = pd_r.entries[pd_idx] & (PTE_PCD | PTE_PWT | PTE_USER | uint64(0x8000000000000000))
pt_split: _p | t.CPtr = AllocPage()
if not pt_split:
va += 0x1000
continue
split_i: int = 0
while split_i < 512:
pt_split.entries[split_i] = (big_phys + uint64(split_i) * uint64(0x1000)) \
| PTE_PRESENT | PTE_WRITABLE | inherit_flags
split_i += 1
pd_r.entries[pd_idx] = (uint64(pt_split) & ~uint64(0xFFF)) \
| PTE_PRESENT | PTE_WRITABLE | (pd_r.entries[pd_idx] & PTE_USER)
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
# 分裂后落入下方 4KB 常规路径,继续清当前页 W 位
pt_r: _p | t.CPtr = t.CType(pd_r.entries[pd_idx] & ~uint64(0xFFF), _p, t.CPtr)
pt_idx: uint64 = (va >> 12) & 0x1FF
pt_r.entries[pt_idx] = pt_r.entries[pt_idx] & ~uint64(PTE_WRITABLE)
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
va += 0x1000
def ProtectKernelRO():
"""把内核镜像 .rodata 段(字符串常量/vtable 等)映射为只读
地址经 c.Asm 内联引用链接器符号 __rodata_start/__rodata_end
(linker.ld 定义,TPV 不声明 extern——避免生成定义与链接器符号冲突)。
"""
global pml4
if not pml4: return
# 页表页可写已在 paging.init(WP=0 阶段)由 MakePTWritable 完成,
# 此处只保护 .rodata 内容页(WP=1 后写只读页即 #PF 暴露写源)。
ro_start: uint64 = 0
ro_end: uint64 = 0
c.Asm(f"""lea rax, [rip + __rodata_start]
mov {c.AsmOut(ro_start, t.ASM_DESCR.OUTPUT_REG)}, rax
lea rax, [rip + __rodata_end]
mov {c.AsmOut(ro_end, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
MakeRangeRO(ro_start, ro_end)
# [PG] 打印 .rodata 起始页映射:确认只读真正生效。
# ps=1 说明仍在 2MB 大页(分裂失败)→ .rodata 保持可写 → 越界写继续被静默吞掉。
DumpMapping(ro_start, "ro_s")
def DumpMapping(va: uint64, tag: t.CConst | str):
"""[PG] 打印指定 VA 的 pml4/pdp/pd/pt 条目,定位大页(PS)与权限位
内核区域若为 UEFI 2MB 大页,MakeRangeRO 无法只读 .rodata(越界写静默破坏
格式串);1GB 页同理(PS 位在 pdpe)。W=1 且 PS=1 → 该页可写且是大页。
"""
global pml4
if not pml4: return
pml4_i: uint64 = (va >> 39) & 0x1FF
pdp_i: uint64 = (va >> 30) & 0x1FF
pd_i: uint64 = (va >> 21) & 0x1FF
pt_i: uint64 = (va >> 12) & 0x1FF
pml4_e: uint64 = pml4.entries[pml4_i]
pdp_e: uint64 = 0
pd_e: uint64 = 0
pt_e: uint64 = 0
if pml4_e & PTE_PRESENT:
pdp_r: _p | t.CPtr = t.CType(pml4_e & ~uint64(0xFFF), _p, t.CPtr)
pdp_e = pdp_r.entries[pdp_i]
if pdp_e & PTE_PRESENT:
if pdp_e & PTE_PS:
pd_e = pdp_e
else:
pd_r: _p | t.CPtr = t.CType(pdp_e & ~uint64(0xFFF), _p, t.CPtr)
pd_e = pd_r.entries[pd_i]
if (pd_e & PTE_PRESENT) and not (pd_e & PTE_PS):
pt_r: _p | t.CPtr = t.CType(pd_e & ~uint64(0xFFF), _p, t.CPtr)
pt_e = pt_r.entries[pt_i]
buf_d: t.CArray[t.CChar, 200]
viperlib.snprintf(c.Addr(buf_d), 200, "[PG] %s va=0x%lx pdpe=0x%lx pde=0x%lx pte=0x%lx (ps=%d W=%d)\n",
tag, va, pdp_e, pd_e, pt_e,
1 if (pd_e & PTE_PS) else 0,
1 if (pt_e & PTE_WRITABLE) or (pd_e & PTE_WRITABLE) or (pdp_e & PTE_WRITABLE) else 0)
serial.puts(c.Addr(buf_d))
def GetCurrentPml4() -> _p | t.CPtr:
global pml4, pdp, pd, pt
cr3: uint64
c.Asm(f"mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3")
return (_p | t.CPtr)(cr3 & ~uint64(0xFFF))
def create_process_page_table() -> uint64:
global pml4
if not pml4: return 0
new_pml4: _p | t.CPtr = AllocPage()
if not new_pml4: return 0
i: uint64
for i in range(512):
entry: uint64 = pml4.entries[i]
if entry & PTE_PRESENT:
new_pml4.entries[i] = entry
return uint64(new_pml4)
def clone_for_process(isolate_vaddr: uint64) -> uint64:
global pml4
_dbg: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg), 120, "[clone] pml4=0x%lx pool_used=%lu iso_va=0x%lx\n", uint64(pml4), pt_pool_used, isolate_vaddr)
serial.puts(_dbg)
if not pml4: return 0
new_pml4_page: _p | t.CPtr = AllocPage()
if not new_pml4_page:
# [DIAG] 定位 AllocPage 失败:pool_used 打印 0 但分配失败 → BSS 全局
# (pt_pool_raw/pt_pool_used)疑似被内存越界写覆盖。
_dbgf: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbgf), 120, "[clone] AllocPage FAIL raw=0x%lx used=%lu PP=%d\n",
uint64(pt_pool_raw), pt_pool_used, PT_POOL_PAGES)
serial.puts(c.Addr(_dbgf))
serial.puts("[clone] AllocPage pml4 failed\n")
return 0
_dbg2: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg2), 120, "[clone] new_pml4=0x%lx\n", uint64(new_pml4_page))
serial.puts(_dbg2)
i: uint64
for i in range(512):
new_pml4_page.entries[i] = pml4.entries[i]
pml4_idx: uint64 = (isolate_vaddr >> 39) & 0x1FF
_dbg3: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg3), 120, "[clone] pml4_idx=%lu entry0=0x%lx\n", pml4_idx, pml4.entries[pml4_idx])
serial.puts(_dbg3)
if not (pml4.entries[pml4_idx] & PTE_PRESENT): return uint64(new_pml4_page)
kernel_pdp: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~uint64(0xFFF), _p, t.CPtr)
new_pdp_page: _p | t.CPtr = AllocPage()
if not new_pdp_page: return uint64(new_pml4_page)
for i in range(512):
new_pdp_page.entries[i] = kernel_pdp.entries[i]
new_pml4_page.entries[pml4_idx] = (uint64(new_pdp_page) & ~uint64(0xFFF)) | (pml4.entries[pml4_idx] & uint64(0xFFF))
pdp_idx: uint64 = (isolate_vaddr >> 30) & 0x1FF
if not (kernel_pdp.entries[pdp_idx] & PTE_PRESENT): return uint64(new_pml4_page)
kernel_pd: _p | t.CPtr = t.CType(kernel_pdp.entries[pdp_idx] & ~uint64(0xFFF), _p, t.CPtr)
new_pd_page: _p | t.CPtr = AllocPage()
if not new_pd_page: return uint64(new_pml4_page)
for i in range(512):
new_pd_page.entries[i] = kernel_pd.entries[i]
new_pdp_page.entries[pdp_idx] = (uint64(new_pd_page) & ~uint64(0xFFF)) | (kernel_pdp.entries[pdp_idx] & uint64(0xFFF))
pd_idx: uint64 = (isolate_vaddr >> 21) & 0x1FF
if not (kernel_pd.entries[pd_idx] & PTE_PRESENT): return uint64(new_pml4_page)
if kernel_pd.entries[pd_idx] & PTE_PS: return uint64(new_pml4_page)
kernel_pt: _p | t.CPtr = t.CType(kernel_pd.entries[pd_idx] & ~uint64(0xFFF), _p, t.CPtr)
new_pt_page: _p | t.CPtr = AllocPage()
if not new_pt_page: return uint64(new_pml4_page)
for i in range(512):
new_pt_page.entries[i] = kernel_pt.entries[i]
new_pd_page.entries[pd_idx] = (uint64(new_pt_page) & ~uint64(0xFFF)) | (kernel_pd.entries[pd_idx] & uint64(0xFFF))
return uint64(new_pml4_page)
def save_pt_range(vaddr_start: uint64, vaddr_end: uint64, save_buf: uint64 | t.CPtr, save_count: uint32 | t.CPtr) -> int:
global pml4
if not pml4: return -1
# c.Set(a,b)=a=b(改指针变量本身);写所指地址必须 c.Set(c.Deref(a),b)
c.Set(c.Deref(save_count), uint32(0))
va: uint64 = vaddr_start & ~uint64(0xFFF)
while va < vaddr_end:
pml4_idx: uint64 = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~uint64(0xFFF), _p, t.CPtr)
pdp_idx: uint64 = (va >> 30) & 0x1FF
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~uint64(0xFFF), _p, t.CPtr)
pd_idx: uint64 = (va >> 21) & 0x1FF
if not (pd_.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue
if pd_.entries[pd_idx] & PTE_PS: va += 0x200000; continue
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~uint64(0xFFF), _p, t.CPtr)
pt_idx: uint64 = (va >> 12) & 0x1FF
saved: uint32 = c.DerefAs(save_count)
entry_ptr: uint64 | t.CPtr = save_buf + uint64(saved) * 16
c.DerefAs(entry_ptr, va)
c.DerefAs(entry_ptr + 8, pt_.entries[pt_idx])
c.Set(c.Deref(save_count), uint32(saved + 1))
va += 0x1000
return 0
def restore_pt_range(save_buf: uint64 | t.CPtr, save_count: uint32):
global pml4
if not pml4: return
i: uint32 = 0
while i < save_count:
entry_ptr: uint64 | t.CPtr = save_buf + uint64(i) * 16
va: uint64 = c.DerefAs(entry_ptr)
orig_pte: uint64 = c.DerefAs(entry_ptr + 8)
pml4_idx: uint64 = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): i += 1; continue
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~uint64(0xFFF), _p, t.CPtr)
pdp_idx: uint64 = (va >> 30) & 0x1FF
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): i += 1; continue
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~uint64(0xFFF), _p, t.CPtr)
pd_idx: uint64 = (va >> 21) & 0x1FF
if not (pd_.entries[pd_idx] & PTE_PRESENT): i += 1; continue
if pd_.entries[pd_idx] & PTE_PS: i += 1; continue
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~uint64(0xFFF), _p, t.CPtr)
pt_idx: uint64 = (va >> 12) & 0x1FF
pt_.entries[pt_idx] = orig_pte
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]", op=[t.ASM_DESCR.CLOBBER_MEMORY])
i += 1
def set_active_pml4(cr3_val: uint64):
global pml4
pml4 = (_p | t.CPtr)(cr3_val & ~uint64(0xFFF))
+120 -120
View File
@@ -1,120 +1,120 @@
import asm
import t, c
# PIC端口定义
PIC1_COMMAND: t.CDefine = 0x20
PIC1_DATA: t.CDefine = 0x21
PIC2_COMMAND: t.CDefine = 0xA0
PIC2_DATA: t.CDefine = 0xA1
# ICW1 - 初始化命令字1
ICW1_ICW4: t.CDefine = 0x01 # 需要ICW4
ICW1_SINGLE: t.CDefine = 0x02 # 单级模式
ICW1_INTERVAL4: t.CDefine = 0x04 # 间隔4字节
ICW1_LEVEL: t.CDefine = 0x08 # 电平触发模式
ICW1_INIT: t.CDefine = 0x10 # 初始化
# ICW4 - 初始化命令字4
ICW4_8086: t.CDefine = 0x01 # 8086/88模式
ICW4_AUTO: t.CDefine = 0x02 # 自动EOI
ICW4_BUF_SLAVE: t.CDefine = 0x08 # 缓冲模式(从片)
ICW4_BUF_MASTER: t.CDefine = 0x0C # 缓冲模式(主片)
ICW4_SFNM: t.CDefine = 0x10 # 特殊全嵌套模式
# OCW2 - 操作命令字2
OCW2_EOI: t.CDefine = 0x20 # 结束中断
# OCW3 - 操作命令字3
OCW3_READ_ISR: t.CDefine = 0x0B # 读取中断服务寄存器(ISR)
# 初始化PIC
def init():
# 发送ICW1:开始初始化,需要ICW4
asm.outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4)
asm.io_wait()
asm.outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4)
asm.io_wait()
# 发送ICW2:中断向量偏移
asm.outb(PIC1_DATA, 0x20) # IRQ0-7映射到0x20-0x27
asm.io_wait()
asm.outb(PIC2_DATA, 0x28) # IRQ8-15映射到0x28-0x2F
asm.io_wait()
# 发送ICW3:级联信息
asm.outb(PIC1_DATA, 0x04) # 主PIC的IRQ2连接从PIC
asm.io_wait()
asm.outb(PIC2_DATA, 0x02) # 从PIC连接到主PIC的IRQ2
asm.io_wait()
# 发送ICW4:8086模式
asm.outb(PIC1_DATA, ICW4_8086)
asm.io_wait()
asm.outb(PIC2_DATA, ICW4_8086)
asm.io_wait()
# 设置初始屏蔽字:只启用IRQ0(定时器)、IRQ1(键盘)、IRQ2(级联)
# 主PIC: 屏蔽所有除了IRQ0, IRQ1, IRQ2 (0xF8 = 11111000)
# 从PIC: 屏蔽所有 (0xFF = 11111111),鼠标中断由驱动程序自己启用
asm.outb(PIC1_DATA, 0xF8) # 启用IRQ0, IRQ1, IRQ2
asm.io_wait()
asm.outb(PIC2_DATA, 0xFF) # 屏蔽所有从PIC中断
asm.io_wait()
# 发送EOI信号
def eoi(irq: t.CUInt8T):
if irq >= 8: asm.outb(PIC2_COMMAND, OCW2_EOI)
asm.outb(PIC1_COMMAND, OCW2_EOI)
# 检查是否是虚假中断(spurious interrupt)
# 返回 1 表示是虚假中断,0 表示是真实中断
def isSpurious(irq: t.CInt) -> t.CInt:
# 边界检查
if irq < 0 or irq > 15: return 0
isr: t.CUInt8T
if irq < 8:
# 发送OCW3,读取ISR(Interrupt Service Register)
asm.outb(PIC1_COMMAND, OCW3_READ_ISR)
asm.io_wait()
isr = asm.inb(PIC1_COMMAND)
# 如果ISR中对应位为0,说明是虚假中断
return not (isr & (1 << irq))
else:
# 发送OCW3,读取从PIC的ISR
asm.outb(PIC2_COMMAND, OCW3_READ_ISR)
asm.io_wait()
isr = asm.inb(PIC2_COMMAND)
# 如果ISR中对应位为0,说明是虚假中断
return not (isr & (1 << (irq - 8)))
# 设置IRQ屏蔽
def setMask(irq: t.CUInt8T):
# 边界检查
if irq > 15: return
port: t.CUInt16T
value: t.CUInt8T
if irq < 8:
port = PIC1_DATA
else:
port = PIC2_DATA
irq -= 8
value = asm.inb(port) | (1 << irq)
asm.outb(port, value)
asm.io_wait() # 确保命令生效
# 清除IRQ屏蔽
def clearMask(irq: t.CUInt8T):
# 边界检查
if irq > 15: return
port: t.CUInt16T
value: t.CUInt8T
if irq < 8:
port = PIC1_DATA
else:
port = PIC2_DATA
irq -= 8
value = asm.inb(port) & ~(1 << irq)
asm.outb(port, value)
asm.io_wait() # 确保命令生效
import asm
import t, c
# PIC端口定义
PIC1_COMMAND: t.CDefine = 0x20
PIC1_DATA: t.CDefine = 0x21
PIC2_COMMAND: t.CDefine = 0xA0
PIC2_DATA: t.CDefine = 0xA1
# ICW1 - 初始化命令字1
ICW1_ICW4: t.CDefine = 0x01 # 需要ICW4
ICW1_SINGLE: t.CDefine = 0x02 # 单级模式
ICW1_INTERVAL4: t.CDefine = 0x04 # 间隔4字节
ICW1_LEVEL: t.CDefine = 0x08 # 电平触发模式
ICW1_INIT: t.CDefine = 0x10 # 初始化
# ICW4 - 初始化命令字4
ICW4_8086: t.CDefine = 0x01 # 8086/88模式
ICW4_AUTO: t.CDefine = 0x02 # 自动EOI
ICW4_BUF_SLAVE: t.CDefine = 0x08 # 缓冲模式(从片)
ICW4_BUF_MASTER: t.CDefine = 0x0C # 缓冲模式(主片)
ICW4_SFNM: t.CDefine = 0x10 # 特殊全嵌套模式
# OCW2 - 操作命令字2
OCW2_EOI: t.CDefine = 0x20 # 结束中断
# OCW3 - 操作命令字3
OCW3_READ_ISR: t.CDefine = 0x0B # 读取中断服务寄存器(ISR)
# 初始化PIC
def init():
# 发送ICW1:开始初始化,需要ICW4
asm.outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4)
asm.io_wait()
asm.outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4)
asm.io_wait()
# 发送ICW2:中断向量偏移
asm.outb(PIC1_DATA, 0x20) # IRQ0-7映射到0x20-0x27
asm.io_wait()
asm.outb(PIC2_DATA, 0x28) # IRQ8-15映射到0x28-0x2F
asm.io_wait()
# 发送ICW3:级联信息
asm.outb(PIC1_DATA, 0x04) # 主PIC的IRQ2连接从PIC
asm.io_wait()
asm.outb(PIC2_DATA, 0x02) # 从PIC连接到主PIC的IRQ2
asm.io_wait()
# 发送ICW4:8086模式
asm.outb(PIC1_DATA, ICW4_8086)
asm.io_wait()
asm.outb(PIC2_DATA, ICW4_8086)
asm.io_wait()
# 设置初始屏蔽字:只启用IRQ0(定时器)、IRQ1(键盘)、IRQ2(级联)
# 主PIC: 屏蔽所有除了IRQ0, IRQ1, IRQ2 (0xF8 = 11111000)
# 从PIC: 屏蔽所有 (0xFF = 11111111),鼠标中断由驱动程序自己启用
asm.outb(PIC1_DATA, 0xF8) # 启用IRQ0, IRQ1, IRQ2
asm.io_wait()
asm.outb(PIC2_DATA, 0xFF) # 屏蔽所有从PIC中断
asm.io_wait()
# 发送EOI信号
def eoi(irq: uint8):
if irq >= 8: asm.outb(PIC2_COMMAND, OCW2_EOI)
asm.outb(PIC1_COMMAND, OCW2_EOI)
# 检查是否是虚假中断(spurious interrupt)
# 返回 1 表示是虚假中断,0 表示是真实中断
def isSpurious(irq: int) -> int:
# 边界检查
if irq < 0 or irq > 15: return 0
isr: uint8
if irq < 8:
# 发送OCW3,读取ISR(Interrupt Service Register)
asm.outb(PIC1_COMMAND, OCW3_READ_ISR)
asm.io_wait()
isr = asm.inb(PIC1_COMMAND)
# 如果ISR中对应位为0,说明是虚假中断
return not (isr & (1 << irq))
else:
# 发送OCW3,读取从PIC的ISR
asm.outb(PIC2_COMMAND, OCW3_READ_ISR)
asm.io_wait()
isr = asm.inb(PIC2_COMMAND)
# 如果ISR中对应位为0,说明是虚假中断
return not (isr & (1 << (irq - 8)))
# 设置IRQ屏蔽
def setMask(irq: uint8):
# 边界检查
if irq > 15: return
port: uint16
value: uint8
if irq < 8:
port = PIC1_DATA
else:
port = PIC2_DATA
irq -= 8
value = asm.inb(port) | (1 << irq)
asm.outb(port, value)
asm.io_wait() # 确保命令生效
# 清除IRQ屏蔽
def clearMask(irq: uint8):
# 边界检查
if irq > 15: return
port: uint16
value: uint8
if irq < 8:
port = PIC1_DATA
else:
port = PIC2_DATA
irq -= 8
value = asm.inb(port) & ~(1 << irq)
asm.outb(port, value)
asm.io_wait() # 确保命令生效
+26 -26
View File
@@ -1,26 +1,26 @@
import asm
import t, c
PIT_CHANNEL0: t.CDefine = 0x40
PIT_CHANNEL1: t.CDefine = 0x41
PIT_CHANNEL2: t.CDefine = 0x42
PIT_COMMAND: t.CDefine = 0x43
def pit_init(frequency: t.CInt):
# 参数验证:确保频率为正数
if frequency <= 0: return
# 计算除数,使用16位无符号整数
divisor: t.CUInt32T = 1193180 / frequency
# 发送命令字:通道0,先低后高,模式3(方波),二进制计数
asm.outb(PIT_COMMAND, 0x36)
asm.io_wait()
# 写入低字节
asm.outb(PIT_CHANNEL0, divisor & 0xFF)
asm.io_wait()
# 写入高字节
asm.outb(PIT_CHANNEL0, (divisor >> 8) & 0xFF)
asm.io_wait()
import asm
import t, c
PIT_CHANNEL0: t.CDefine = 0x40
PIT_CHANNEL1: t.CDefine = 0x41
PIT_CHANNEL2: t.CDefine = 0x42
PIT_COMMAND: t.CDefine = 0x43
def pit_init(frequency: int):
# 参数验证:确保频率为正数
if frequency <= 0: return
# 计算除数,使用16位无符号整数
divisor: uint32 = 1193180 / frequency
# 发送命令字:通道0,先低后高,模式3(方波),二进制计数
asm.outb(PIT_COMMAND, 0x36)
asm.io_wait()
# 写入低字节
asm.outb(PIT_CHANNEL0, divisor & 0xFF)
asm.io_wait()
# 写入高字节
asm.outb(PIT_CHANNEL0, (divisor >> 8) & 0xFF)
asm.io_wait()
+97 -97
View File
@@ -1,97 +1,97 @@
from stdint import *
import t, c
import asm
RTC_CMOS_ADDR: t.CUInt16T = 0x70
RTC_CMOS_DATA: t.CUInt16T = 0x71
RTC_REG_SECONDS: t.CDefine = 0x00
RTC_REG_MINUTES: t.CDefine = 0x02
RTC_REG_HOURS: t.CDefine = 0x04
RTC_REG_DAY: t.CDefine = 0x07
RTC_REG_MONTH: t.CDefine = 0x08
RTC_REG_YEAR: t.CDefine = 0x09
RTC_REG_STATUS_A: t.CDefine = 0x0A
RTC_REG_STATUS_B: t.CDefine = 0x0B
RTC_TZ_OFFSET: t.CDefine = 8
rtc_seconds: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_minutes: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_hours: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_day: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_month: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_year: t.CStatic | t.CVolatile | t.CUInt16T = 0
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
asm.outb(RTC_CMOS_ADDR, reg)
return asm.inb(RTC_CMOS_DATA)
def bcd_to_bin(bcd: t.CUInt8T) -> t.CUInt8T:
return (bcd >> 4) * 10 + (bcd & 0x0F)
def rtc_read_time():
while cmos_read(RTC_REG_STATUS_A) & 0x80: pass
sec: t.CUInt8T = cmos_read(RTC_REG_SECONDS)
min_: t.CUInt8T = cmos_read(RTC_REG_MINUTES)
hour: t.CUInt8T = cmos_read(RTC_REG_HOURS)
day: t.CUInt8T = cmos_read(RTC_REG_DAY)
mon: t.CUInt8T = cmos_read(RTC_REG_MONTH)
year: t.CUInt8T = cmos_read(RTC_REG_YEAR)
reg_b: t.CUInt8T = cmos_read(RTC_REG_STATUS_B)
if not (reg_b & 0x04):
sec = bcd_to_bin(sec)
min_ = bcd_to_bin(min_)
hour = bcd_to_bin(hour)
day = bcd_to_bin(day)
mon = bcd_to_bin(mon)
year = bcd_to_bin(year)
if not (reg_b & 0x02) and (hour & 0x80):
hour = ((hour & 0x7F) + 12) % 24
hour = hour + RTC_TZ_OFFSET
if hour >= 24:
hour = hour - 24
day = day + 1
max_day: t.CUInt8T = 31
if mon == 4 or mon == 6 or mon == 9 or mon == 11:
max_day = 30
elif mon == 2:
max_day = 28
y4: t.CUInt16T = t.CUInt16T(year) + 2000
if (y4 % 4 == 0 and y4 % 100 != 0) or (y4 % 400 == 0):
max_day = 29
if day > max_day:
day = 1
mon = mon + 1
if mon > 12:
mon = 1
year = year + 1
global rtc_seconds, rtc_minutes, rtc_hours, rtc_day, rtc_month, rtc_year
rtc_seconds = sec
rtc_minutes = min_
rtc_hours = hour
rtc_day = day
rtc_month = mon
rtc_year = t.CUInt16T(year) + 2000
def rtc_init():
rtc_read_time()
def rtc_get_hours() -> t.CUInt8T:
return rtc_hours
def rtc_get_minutes() -> t.CUInt8T:
return rtc_minutes
def rtc_get_seconds() -> t.CUInt8T:
return rtc_seconds
def rtc_get_day() -> t.CUInt8T:
return rtc_day
def rtc_get_month() -> t.CUInt8T:
return rtc_month
def rtc_get_year() -> t.CUInt16T:
return rtc_year
from stdint import *
import t, c
import asm
RTC_CMOS_ADDR: uint16 = 0x70
RTC_CMOS_DATA: uint16 = 0x71
RTC_REG_SECONDS: t.CDefine = 0x00
RTC_REG_MINUTES: t.CDefine = 0x02
RTC_REG_HOURS: t.CDefine = 0x04
RTC_REG_DAY: t.CDefine = 0x07
RTC_REG_MONTH: t.CDefine = 0x08
RTC_REG_YEAR: t.CDefine = 0x09
RTC_REG_STATUS_A: t.CDefine = 0x0A
RTC_REG_STATUS_B: t.CDefine = 0x0B
RTC_TZ_OFFSET: t.CDefine = 8
rtc_seconds: t.CStatic | t.CVolatile | uint8 = 0
rtc_minutes: t.CStatic | t.CVolatile | uint8 = 0
rtc_hours: t.CStatic | t.CVolatile | uint8 = 0
rtc_day: t.CStatic | t.CVolatile | uint8 = 0
rtc_month: t.CStatic | t.CVolatile | uint8 = 0
rtc_year: t.CStatic | t.CVolatile | uint16 = 0
def cmos_read(reg: uint8) -> uint8:
asm.outb(RTC_CMOS_ADDR, reg)
return asm.inb(RTC_CMOS_DATA)
def bcd_to_bin(bcd: uint8) -> uint8:
return (bcd >> 4) * 10 + (bcd & 0x0F)
def rtc_read_time():
while cmos_read(RTC_REG_STATUS_A) & 0x80: pass
sec: uint8 = cmos_read(RTC_REG_SECONDS)
min_: uint8 = cmos_read(RTC_REG_MINUTES)
hour: uint8 = cmos_read(RTC_REG_HOURS)
day: uint8 = cmos_read(RTC_REG_DAY)
mon: uint8 = cmos_read(RTC_REG_MONTH)
year: uint8 = cmos_read(RTC_REG_YEAR)
reg_b: uint8 = cmos_read(RTC_REG_STATUS_B)
if not (reg_b & 0x04):
sec = bcd_to_bin(sec)
min_ = bcd_to_bin(min_)
hour = bcd_to_bin(hour)
day = bcd_to_bin(day)
mon = bcd_to_bin(mon)
year = bcd_to_bin(year)
if not (reg_b & 0x02) and (hour & 0x80):
hour = ((hour & 0x7F) + 12) % 24
hour = hour + RTC_TZ_OFFSET
if hour >= 24:
hour = hour - 24
day = day + 1
max_day: uint8 = 31
if mon == 4 or mon == 6 or mon == 9 or mon == 11:
max_day = 30
elif mon == 2:
max_day = 28
y4: uint16 = uint16(year) + 2000
if (y4 % 4 == 0 and y4 % 100 != 0) or (y4 % 400 == 0):
max_day = 29
if day > max_day:
day = 1
mon = mon + 1
if mon > 12:
mon = 1
year = year + 1
global rtc_seconds, rtc_minutes, rtc_hours, rtc_day, rtc_month, rtc_year
rtc_seconds = sec
rtc_minutes = min_
rtc_hours = hour
rtc_day = day
rtc_month = mon
rtc_year = uint16(year) + 2000
def rtc_init():
rtc_read_time()
def rtc_get_hours() -> uint8:
return rtc_hours
def rtc_get_minutes() -> uint8:
return rtc_minutes
def rtc_get_seconds() -> uint8:
return rtc_seconds
def rtc_get_day() -> uint8:
return rtc_day
def rtc_get_month() -> uint8:
return rtc_month
def rtc_get_year() -> uint16:
return rtc_year
+129 -129
View File
@@ -1,129 +1,129 @@
import platform.pch.pic as pic
import platform.pch.pit as pit
import sched.sched as sched
import drivers.core.cpu.apic as apic
import drivers.serial.uart.serial as serial
import viperlib
import asm
import t, c
TIMER_FREQUENCY: t.CDefine = 1000
TICKS_PER_SECOND: t.CDefine = TIMER_FREQUENCY
MILLISECONDS_PER_TICK: t.CDefine = (1000 / TIMER_FREQUENCY)
ticks: t.CStatic | t.CVolatile | t.CUInt64T = 0
seconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
milliseconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
timer_running: t.CStatic | t.CVolatile | bool = False
_dbg_once: t.CInt = 0
def timer_init():
global ticks, seconds, milliseconds, timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = 0
seconds = 0
milliseconds = 0
timer_running = True
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
pit.pit_init(TIMER_FREQUENCY)
# [DBG] 读 PIT 计数器验证是否在走(用后移除)
asm.outb(0x43, 0x00) # latch channel 0
_lo: t.CUInt8T = asm.inb(0x40)
_hi: t.CUInt8T = asm.inb(0x40)
_cnt: t.CInt = t.CInt(_lo) | (t.CInt(_hi) << 8)
_cb: t.CArray[t.CChar, 40]
viperlib.snprintf(c.Addr(_cb), 40, "[PIT] cnt=%d\n", _cnt)
serial.puts(c.Addr(_cb))
def timer_handler():
global ticks, seconds, milliseconds, timer_running, _dbg_once
# [DBG] 一次性打印:'H' 出现说明定时 ISR 被调用(用后移除)
if _dbg_once == 0:
_dbg_once = 1
serial.puts("H")
if not timer_running:
pic.eoi(0)
apic.eoi()
return
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = ticks + 1
milliseconds = milliseconds + MILLISECONDS_PER_TICK
if milliseconds >= 1000:
seconds = seconds + 1
milliseconds = milliseconds - 1000
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
sched.Scheduler.sched_tick()
pic.eoi(0)
# LAPIC EOI:APIC 启用后中断经 LINT0(EXTINT) 送达会置 LAPIC ISR,
# 只发 PIC EOI 不清 LAPIC ISR → 首个定时中断后后续中断被屏蔽 →
# ticks 不推进 → msleep 永久挂起(QEMU/OVMF 下 APIC 必启用)。
apic.eoi()
def timer_start():
global timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
timer_running = True
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_stop():
global timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
timer_running = False
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_reset():
global ticks, seconds, milliseconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = 0
seconds = 0
milliseconds = 0
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_get_ticks() -> t.CUInt64T:
current_ticks: t.CUInt64T
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_ticks = ticks
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_ticks
def timer_get_seconds() -> t.CUInt32T:
current_seconds: t.CUInt32T
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_seconds = seconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_seconds
def timer_get_milliseconds() -> t.CUInt32T:
current_milliseconds: t.CUInt32T
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_milliseconds = milliseconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_milliseconds
def timer_get_time(out_seconds: t.CUInt32T | t.CPtr, out_milliseconds: t.CUInt32T | t.CPtr):
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
if out_seconds:
c.Set(c.Deref(out_seconds), seconds)
if out_milliseconds:
c.Set(c.Deref(out_milliseconds), milliseconds)
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_msleep(ms: t.CUInt32T):
target: t.CUInt64T = ticks + (ms + MILLISECONDS_PER_TICK - 1) / MILLISECONDS_PER_TICK
_spin: t.CUInt64T = 0
while ticks < target:
# [DBG] 自旋计数:每 1M 次迭代打印 s——hlt 能唤醒说明中断触发
# (用后移除)
_spin += 1
if (_spin & 0xFFFFF) == 0:
serial.puts("s")
asm.sti()
asm.hlt()
sched.Scheduler._yield()
def timer_sleep(sec: t.CUInt32T):
target: t.CUInt64T = ticks + sec * TICKS_PER_SECOND
while ticks < target:
asm.sti()
asm.hlt()
sched.Scheduler._yield()
import platform.pch.pic as pic
import platform.pch.pit as pit
import sched.sched as sched
import drivers.core.cpu.apic as apic
import drivers.serial.uart.serial as serial
import viperlib
import asm
import t, c
TIMER_FREQUENCY: t.CDefine = 1000
TICKS_PER_SECOND: t.CDefine = TIMER_FREQUENCY
MILLISECONDS_PER_TICK: t.CDefine = (1000 / TIMER_FREQUENCY)
ticks: t.CStatic | t.CVolatile | uint64 = 0
seconds: t.CStatic | t.CVolatile | uint32 = 0
milliseconds: t.CStatic | t.CVolatile | uint32 = 0
timer_running: t.CStatic | t.CVolatile | bool = False
_dbg_once: int = 0
def timer_init():
global ticks, seconds, milliseconds, timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = 0
seconds = 0
milliseconds = 0
timer_running = True
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
pit.pit_init(TIMER_FREQUENCY)
# [DBG] 读 PIT 计数器验证是否在走(用后移除)
asm.outb(0x43, 0x00) # latch channel 0
_lo: uint8 = asm.inb(0x40)
_hi: uint8 = asm.inb(0x40)
_cnt: int = int(_lo) | (int(_hi) << 8)
_cb: t.CArray[t.CChar, 40]
viperlib.snprintf(c.Addr(_cb), 40, "[PIT] cnt=%d\n", _cnt)
serial.puts(c.Addr(_cb))
def timer_handler():
global ticks, seconds, milliseconds, timer_running, _dbg_once
# [DBG] 一次性打印:'H' 出现说明定时 ISR 被调用(用后移除)
if _dbg_once == 0:
_dbg_once = 1
serial.puts("H")
if not timer_running:
pic.eoi(0)
apic.eoi()
return
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = ticks + 1
milliseconds = milliseconds + MILLISECONDS_PER_TICK
if milliseconds >= 1000:
seconds = seconds + 1
milliseconds = milliseconds - 1000
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
sched.Scheduler.sched_tick()
pic.eoi(0)
# LAPIC EOI:APIC 启用后中断经 LINT0(EXTINT) 送达会置 LAPIC ISR,
# 只发 PIC EOI 不清 LAPIC ISR → 首个定时中断后后续中断被屏蔽 →
# ticks 不推进 → msleep 永久挂起(QEMU/OVMF 下 APIC 必启用)。
apic.eoi()
def timer_start():
global timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
timer_running = True
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_stop():
global timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
timer_running = False
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_reset():
global ticks, seconds, milliseconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = 0
seconds = 0
milliseconds = 0
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_get_ticks() -> uint64:
current_ticks: uint64
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_ticks = ticks
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_ticks
def timer_get_seconds() -> uint32:
current_seconds: uint32
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_seconds = seconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_seconds
def timer_get_milliseconds() -> uint32:
current_milliseconds: uint32
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_milliseconds = milliseconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_milliseconds
def timer_get_time(out_seconds: uint32 | t.CPtr, out_milliseconds: uint32 | t.CPtr):
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
if out_seconds:
c.Set(c.Deref(out_seconds), seconds)
if out_milliseconds:
c.Set(c.Deref(out_milliseconds), milliseconds)
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_msleep(ms: uint32):
target: uint64 = ticks + (ms + MILLISECONDS_PER_TICK - 1) / MILLISECONDS_PER_TICK
_spin: uint64 = 0
while ticks < target:
# [DBG] 自旋计数:每 1M 次迭代打印 s——hlt 能唤醒说明中断触发
# (用后移除)
_spin += 1
if (_spin & 0xFFFFF) == 0:
serial.puts("s")
asm.sti()
asm.hlt()
sched.Scheduler._yield()
def timer_sleep(sec: uint32):
target: uint64 = ticks + sec * TICKS_PER_SECOND
while ticks < target:
asm.sti()
asm.hlt()
sched.Scheduler._yield()
+43 -38
View File
@@ -13,27 +13,27 @@ CORO_STACK_SIZE: t.CDefine = 8192
@t.Object
class Coroutine:
rsp: t.CUInt64T
stack: t.CVoid | t.CPtr
stack_size: t.CUInt64T
func: t.CVoid | t.CPtr
arg: t.CVoid | t.CPtr
state: t.CInt
cid: t.CInt
caller_rsp: t.CUInt64T
ret_val: t.CInt
rsp: uint64
stack: t.CPtr
stack_size: uint64
func: t.CPtr
arg: t.CPtr
state: int
cid: int
caller_rsp: uint64
ret_val: int
def resume(self) -> t.CInt:
def resume(self) -> int:
global _coro_old_rsp, _coro_new_rsp
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if self.state == CORO_DONE: return self.ret_val
if self.state != CORO_READY and self.state != CORO_YIELDED: return -1
prev_cid: t.CInt = m.current_cid
prev_cid: int = m.current_cid
m.current_cid = self.cid
self.state = CORO_RUNNING
_coro_old_rsp = c.Addr(m.coroutines[prev_cid].rsp)
_coro_new_rsp = c.Addr(self.rsp)
self.caller_rsp = t.CUInt64T(_coro_old_rsp)
self.caller_rsp = uint64(_coro_old_rsp)
_coro_switch()
if self.state == CORO_DONE:
return self.ret_val
@@ -43,11 +43,11 @@ class Coroutine:
def _yield():
global _coro_old_rsp, _coro_new_rsp
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
cid: t.CInt = m.current_cid
cid: int = m.current_cid
if cid < 0: return
m.coroutines[cid].state = CORO_YIELDED
prev_cid: t.CInt = -1
i: t.CInt
prev_cid: int = -1
i: int
for i in range(m.count):
if m.coroutines[i].state == CORO_RUNNING and m.coroutines[i].caller_rsp != 0:
prev_cid = i
@@ -59,27 +59,27 @@ class Coroutine:
_coro_switch()
@property
def is_done(self) -> t.CInt:
def is_done(self) -> int:
if self.state == CORO_DONE:
return 1
return 0
@property
def is_yielded(self) -> t.CInt:
def is_yielded(self) -> int:
if self.state == CORO_YIELDED:
return 1
return 0
@property
def retval(self) -> t.CInt:
def retval(self) -> int:
return self.ret_val
@t.Object
class CoroutineManager:
coroutines: t.CArray[Coroutine, MAX_COROUTINES]
current_cid: t.CInt
count: t.CInt
current_cid: int
count: int
def __init__(self):
global _coro_mgr_ptr
@@ -96,7 +96,7 @@ class CoroutineManager:
m.coroutines[0].stack_size = 0
m.coroutines[0].func = None
m.coroutines[0].arg = None
main_rsp_ptr: t.CVoid | t.CPtr = c.Addr(m.coroutines[0].rsp)
main_rsp_ptr: t.CPtr = c.Addr(m.coroutines[0].rsp)
c.Asm(f"""mov qword ptr [{c.AsmInp(main_rsp_ptr, t.ASM_DESCR.REG_ANY)}], rsp""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@@ -106,16 +106,16 @@ class CoroutineManager:
return c.Addr(m.coroutines[m.current_cid])
@staticmethod
def get_coroutine(cid: t.CInt) -> Coroutine | t.CPtr:
def get_coroutine(cid: int) -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if cid < 0 or cid >= m.count: return None
return c.Addr(m.coroutines[cid])
@staticmethod
def create(func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr) -> Coroutine | t.CPtr:
def create(func: t.CPtr, arg: t.CPtr) -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if m.count >= MAX_COROUTINES: return None
cid: t.CInt = m.count
cid: int = m.count
m.count += 1
co: Coroutine | t.CPtr = c.Addr(m.coroutines[cid])
co.state = CORO_READY
@@ -124,13 +124,13 @@ class CoroutineManager:
co.arg = arg
co.caller_rsp = 0
co.ret_val = 0
stack_ptr: t.CVoid | t.CPtr = mm.malloc(CORO_STACK_SIZE)
stack_ptr: t.CPtr = mm.malloc(CORO_STACK_SIZE)
if not stack_ptr: return None
co.stack = stack_ptr
co.stack_size = CORO_STACK_SIZE
stack_top: t.CUInt64T = t.CUInt64T(stack_ptr) + CORO_STACK_SIZE - 16
stack_top = stack_top & ~t.CUInt64T(0xF)
entry_addr: t.CUInt64T = t.CUInt64T(c.Addr(_coro_entry))
stack_top: uint64 = uint64(stack_ptr) + CORO_STACK_SIZE - 16
stack_top = stack_top & ~uint64(0xF)
entry_addr: uint64 = uint64(c.Addr(_coro_entry))
sp: t.CPtr = t.CPtr(stack_top)
c.Asm(f"""mov rax, {c.AsmInp(sp, t.ASM_DESCR.REG_ANY)}
mov qword ptr [rax - 56], 0
@@ -149,8 +149,8 @@ class CoroutineManager:
_coro_mgr: CoroutineManager = CoroutineManager()
_coro_mgr_ptr: CoroutineManager | t.CPtr | t.CExport = c.Addr(_coro_mgr)
_coro_old_rsp: t.CVoid | t.CPtr | t.CExport
_coro_new_rsp: t.CVoid | t.CPtr | t.CExport
_coro_old_rsp: t.CPtr | t.CExport
_coro_new_rsp: t.CPtr | t.CExport
@c.Attribute(t.attr.naked)
def _coro_switch():
@@ -177,20 +177,25 @@ def _coro_switch():
@c.Attribute(t.attr.naked)
def _coro_entry():
# 结构体布局(以 stub.ll 为权威):
# Coroutine = {rsp@0, stack@8, stack_size@16, func@24, arg@32,
# state@40, cid@44, caller_rsp@48, ret_val@56}, sizeof=64
# CoroutineManager= {coroutines[32]@0 (32*64=2048), current_cid@2048, count@2052}
# 取 func/arg 入口,写 state=CORO_DONE(3)、ret_val。
c.Asm(f"""sub rsp, 8
mov rax, qword ptr [rip + _coro_mgr_ptr]
mov ecx, dword ptr [rax + 1056]
mov ecx, dword ptr [rax + 2048]
movsxd rcx, ecx
shl rcx, 5
mov rdi, qword ptr [rax + rcx + 24]
mov rax, qword ptr [rax + rcx + 16]
shl rcx, 6
mov rdi, qword ptr [rax + rcx + 32]
mov rax, qword ptr [rax + rcx + 24]
call rax
mov rax, qword ptr [rip + _coro_mgr_ptr]
mov ecx, dword ptr [rax + 1056]
mov ecx, dword ptr [rax + 2048]
movsxd rcx, ecx
shl rcx, 5
mov dword ptr [rax + rcx + 32], 3
mov dword ptr [rax + rcx + 48], eax
shl rcx, 6
mov dword ptr [rax + rcx + 40], 3
mov dword ptr [rax + rcx + 56], eax
add rsp, 8""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
+48 -48
View File
@@ -23,25 +23,25 @@ USER_STACK_SIZE: t.CDefine = 65536
@t.Object
class Process:
pid: t.CInt
pml4_root: t.CUInt64T
threads: t.CArray[t.CInt, 8]
thread_count: t.CInt
state: t.CInt
entry: t.CVoid | t.CPtr
elf_base: t.CUInt64T
heap_start: t.CUInt64T
heap_size: t.CUInt64T
pid: int
pml4_root: uint64
threads: t.CArray[int, 8]
thread_count: int
state: int
entry: t.CPtr
elf_base: uint64
heap_start: uint64
heap_size: uint64
name: t.CArray[t.CChar, 32]
fd_table: t.CArray[t.CVoid | t.CPtr, PROC_MAX_FDS]
fd_used: t.CArray[t.CUInt8T, PROC_MAX_FDS]
dir_table: t.CArray[t.CVoid | t.CPtr, PROC_MAX_DIRS]
dir_used: t.CArray[t.CUInt8T, PROC_MAX_DIRS]
fd_table: t.CArray[t.CPtr, PROC_MAX_FDS]
fd_used: t.CArray[uint8, PROC_MAX_FDS]
dir_table: t.CArray[t.CPtr, PROC_MAX_DIRS]
dir_used: t.CArray[uint8, PROC_MAX_DIRS]
dir_pool: t.CArray[fat32_types.dirobj, PROC_MAX_DIRS]
kern_stack: t.CUInt64T
user_stack: t.CUInt64T
kern_stack: uint64
user_stack: uint64
def addThread(self, tid: t.CInt) -> t.CInt:
def addThread(self, tid: int) -> int:
if self.thread_count >= MAX_PROC_THREADS: return -1
self.threads[self.thread_count] = tid
self.thread_count += 1
@@ -51,14 +51,14 @@ class Process:
self.state = PROC_DONE
for i in range(PROC_MAX_FDS):
if self.fd_used[i]:
fp: t.CVoid | t.CPtr = self.fd_table[i]
fp: t.CPtr = self.fd_table[i]
if fp:
fat32.close(fp)
self.fd_used[i] = 0
self.fd_table[i] = t.CVoid(0, t.CPtr)
for i in range(PROC_MAX_DIRS):
if self.dir_used[i]:
dp: t.CVoid | t.CPtr = self.dir_table[i]
dp: t.CPtr = self.dir_table[i]
if dp:
fat32.closedir(dp)
self.dir_used[i] = 0
@@ -68,20 +68,20 @@ class Process:
m.current_pid = 0
m.processes[0].state = PROC_RUNNING
if self.pml4_root != 0:
kernel_cr3: t.CUInt64T = m.processes[0].pml4_root
kernel_cr3: uint64 = m.processes[0].pml4_root
if kernel_cr3 != 0:
c.Asm(f"mov cr3, {c.AsmInp(kernel_cr3, t.ASM_DESCR.REG_ANY)}",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(kernel_cr3)
@property
def is_running(self) -> t.CInt:
def is_running(self) -> int:
if self.state == PROC_RUNNING:
return 1
return 0
@property
def is_done(self) -> t.CInt:
def is_done(self) -> int:
if self.state == PROC_DONE:
return 1
return 0
@@ -90,8 +90,8 @@ class Process:
@t.Object
class ProcessManager:
processes: t.CArray[Process, MAX_PROCESSES]
current_pid: t.CInt
count: t.CInt
current_pid: int
count: int
def __init__(self):
global _proc_mgr_ptr
@@ -109,13 +109,13 @@ class ProcessManager:
p.heap_start = 0
p.heap_size = 0
name_str: str = "kernel"
i: t.CInt = 0
i: int = 0
for ch in name_str:
if i >= 31: break
p.name[i] = ch
i += 1
p.name[i] = 0
j: t.CInt
j: int
for j in range(MAX_PROC_THREADS):
p.threads[j] = -1
for j in range(PROC_MAX_FDS):
@@ -128,13 +128,13 @@ class ProcessManager:
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@staticmethod
def _switch(pid: t.CInt) -> t.CInt:
def _switch(pid: int) -> int:
global _saved_cr3
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if pid < 0 or pid >= m.count: return -1
p: Process | t.CPtr = c.Addr(m.processes[pid])
if p.state == PROC_DONE: return -1
old_pid: t.CInt = m.current_pid
old_pid: int = m.current_pid
if old_pid == pid: return 0
if old_pid >= 0 and old_pid < m.count:
m.processes[old_pid].state = PROC_READY
@@ -152,19 +152,19 @@ class ProcessManager:
return c.Addr(m.processes[m.current_pid])
@staticmethod
def get_process(pid: t.CInt) -> Process | t.CPtr:
def get_process(pid: int) -> Process | t.CPtr:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if pid < 0 or pid >= m.count: return None
return c.Addr(m.processes[pid])
@staticmethod
def create_process(name: str, entry: t.CVoid | t.CPtr) -> Process | t.CPtr:
def create_process(name: str, entry: t.CPtr) -> Process | t.CPtr:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
_dbp: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(_dbp), 80, "[process] create_process count=%d MAX=%d\n", m.count, MAX_PROCESSES)
serial.puts(_dbp)
if m.count >= MAX_PROCESSES: return None
pid: t.CInt = m.count
pid: int = m.count
m.count += 1
p: Process | t.CPtr = c.Addr(m.processes[pid])
p.pid = pid
@@ -175,13 +175,13 @@ class ProcessManager:
p.heap_start = 0
p.heap_size = 0
string.memset(c.Addr(p.name), 0, 32)
i: t.CInt = 0
i: int = 0
for ch in name:
if i >= 31: break
p.name[i] = ch
i += 1
p.name[i] = 0
j: t.CInt
j: int
for j in range(MAX_PROC_THREADS):
p.threads[j] = -1
for j in range(PROC_MAX_FDS):
@@ -190,29 +190,29 @@ class ProcessManager:
for j in range(PROC_MAX_DIRS):
p.dir_used[j] = 0
p.dir_table[j] = t.CVoid(0, t.CPtr)
ks: t.CVoid | t.CPtr = mm_mm.malloc(KERN_STACK_SIZE)
ks: t.CPtr = mm_mm.malloc(KERN_STACK_SIZE)
# [DIAG] 定位跨模块 malloc 返回值(mm 成功但调用方收到 None)
_dbg_ks: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(_dbg_ks), 64, "[proc] ks=0x%lx\n", t.CUInt64T(ks))
viperlib.snprintf(c.Addr(_dbg_ks), 64, "[proc] ks=0x%lx\n", uint64(ks))
serial.puts(c.Addr(_dbg_ks))
if ks is None:
serial.puts("[process] kernel stack alloc failed\n")
m.count = m.count - 1
return None
ks_size: t.CUInt64T = KERN_STACK_SIZE
p.kern_stack = t.CUInt64T(ks) + ks_size
us: t.CVoid | t.CPtr = mm_mm.malloc(USER_STACK_SIZE)
ks_size: uint64 = KERN_STACK_SIZE
p.kern_stack = uint64(ks) + ks_size
us: t.CPtr = mm_mm.malloc(USER_STACK_SIZE)
# [DIAG] 定位 user_stack 收到 None(mm 内部打印成功但此处收 0x0)
_dbg_us: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(_dbg_us), 64, "[proc] us=0x%lx\n", t.CUInt64T(us))
viperlib.snprintf(c.Addr(_dbg_us), 64, "[proc] us=0x%lx\n", uint64(us))
serial.puts(c.Addr(_dbg_us))
if us is None:
serial.puts("[process] user stack alloc failed\n")
mm_mm.free(ks)
m.count = m.count - 1
return None
us_size: t.CUInt64T = USER_STACK_SIZE
p.user_stack = t.CUInt64T(us) + us_size
us_size: uint64 = USER_STACK_SIZE
p.user_stack = uint64(us) + us_size
c.Asm(f"""mov {c.AsmOut(p.pml4_root, t.ASM_DESCR.OUTPUT_REG)}, cr3""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
return p
@@ -220,13 +220,13 @@ class ProcessManager:
_proc_mgr: ProcessManager = ProcessManager()
_proc_mgr_ptr: ProcessManager | t.CPtr = c.Addr(_proc_mgr)
_saved_cr3: t.CUInt64T | t.CExport
_saved_cr3: uint64 | t.CExport
def current() -> t.CInt:
def current() -> int:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
return m.current_pid
def switch_pid(new_pid: t.CInt):
def switch_pid(new_pid: int):
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if m.current_pid == new_pid: return
if m.current_pid >= 0 and m.current_pid < m.count:
@@ -236,7 +236,7 @@ def switch_pid(new_pid: t.CInt):
if new_pid >= 0 and new_pid < m.count:
new_p: Process | t.CPtr = c.Addr(m.processes[new_pid])
new_p.state = PROC_RUNNING
new_cr3: t.CUInt64T = new_p.pml4_root
new_cr3: uint64 = new_p.pml4_root
if new_cr3 != 0:
c.Asm(f"mov cr3, {c.AsmInp(new_cr3, t.ASM_DESCR.REG_ANY)}",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@@ -248,18 +248,18 @@ def switch_pid(new_pid: t.CInt):
cpu.set_kernel_rsp0(new_p.kern_stack)
m.current_pid = new_pid
def get_pid(tid: t.CInt) -> t.CInt:
def get_pid(tid: int) -> int:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
i: t.CInt
i: int
for i in range(m.count):
p: Process | t.CPtr = c.Addr(m.processes[i])
j: t.CInt
j: int
for j in range(p.thread_count):
if p.threads[j] == tid:
return p.pid
return -1
def drop_to_user_mode(entry: t.CVoid | t.CPtr, user_rsp: t.CUInt64T, kern_rsp: t.CUInt64T):
def drop_to_user_mode(entry: t.CPtr, user_rsp: uint64, kern_rsp: uint64):
# NOTE: Do NOT swapgs here. This OS uses reverse GS convention:
# GS_BASE = 0 (kernel & user), KERNEL_GS_BASE = &_per_cpu
# syscall/ISR entry does swapgs to get GS_BASE = &_per_cpu
+37 -37
View File
@@ -14,20 +14,20 @@ MAX_THREADS: t.CDefine = 16
THREAD_STACK_SIZE: t.CDefine = 65536
SCHED_QUANTUM: t.CDefine = 10
_yield_cnt: t.CUInt32T = 0
_yield_lock: t.CInt = 0
_yield_cnt: uint32 = 0
_yield_lock: int = 0
@t.Object
class Thread:
rsp: t.CUInt64T
stack: t.CVoid | t.CPtr
stack_size: t.CUInt64T
func: t.CVoid | t.CPtr
arg: t.CVoid | t.CPtr
state: t.CInt
rsp: uint64
stack: t.CPtr
stack_size: uint64
func: t.CPtr
arg: t.CPtr
state: int
tid: int
pid: t.CInt
pid: int
def block(self):
self.state = THREAD_BLOCKED
@@ -38,19 +38,19 @@ class Thread:
self.state = THREAD_READY
@property
def is_running(self) -> t.CInt:
def is_running(self) -> int:
if self.state == THREAD_RUNNING:
return 1
return 0
@property
def is_blocked(self) -> t.CInt:
def is_blocked(self) -> int:
if self.state == THREAD_BLOCKED:
return 1
return 0
@property
def is_done(self) -> t.CInt:
def is_done(self) -> int:
if self.state == THREAD_DONE:
return 1
return 0
@@ -59,11 +59,11 @@ class Thread:
@t.Object
class Scheduler:
threads: t.CArray[Thread, MAX_THREADS]
current_tid: t.CInt
thread_count: t.CInt
enabled: t.CInt
needs_reschedule: t.CInt
tick_count: t.CInt
current_tid: int
thread_count: int
enabled: int
needs_reschedule: int
tick_count: int
def __init__(self):
global _sched_ptr
@@ -87,14 +87,14 @@ class Scheduler:
s.enabled = 1
s.threads[0].state = THREAD_RUNNING
s.threads[0].tid = 0
main_rsp_ptr: t.CVoid | t.CPtr = c.Addr(s.threads[0].rsp)
main_rsp_ptr: t.CPtr = c.Addr(s.threads[0].rsp)
c.Asm(f"""mov qword ptr [{c.AsmInp(main_rsp_ptr, t.ASM_DESCR.REG_ANY)}], rsp""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@staticmethod
def _yield():
global _switch_old_rsp, _switch_new_rsp, _yield_cnt, _yield_lock
_if_saved: t.CInt = 0
_if_saved: int = 0
c.Asm(f"""pushfq
pop rax
shr rax, 9
@@ -110,14 +110,14 @@ class Scheduler:
s: Scheduler | t.CPtr = _sched_ptr
s.needs_reschedule = 0
s.tick_count = 0
old_tid: t.CInt = s.current_tid
next_tid: t.CInt = old_tid + 1
old_tid: int = s.current_tid
next_tid: int = old_tid + 1
if next_tid >= s.thread_count:
next_tid = 0
found: t.CInt = 0
count: t.CInt = 0
found: int = 0
count: int = 0
while count < s.thread_count:
st: t.CInt = s.threads[next_tid].state
st: int = s.threads[next_tid].state
if st == THREAD_READY or st == THREAD_RUNNING:
found = 1
break
@@ -141,7 +141,7 @@ class Scheduler:
_switch_old_rsp = c.Addr(s.threads[old_tid].rsp)
_switch_new_rsp = c.Addr(s.threads[next_tid].rsp)
s.current_tid = next_tid
next_pid: t.CInt = s.threads[next_tid].pid
next_pid: int = s.threads[next_tid].pid
_yield_cnt += 1
proc.switch_pid(next_pid)
_yield_lock = 0
@@ -182,13 +182,13 @@ class Scheduler:
return c.Addr(s.threads[s.current_tid])
@staticmethod
def get_thread(tid: t.CInt) -> Thread | t.CPtr:
def get_thread(tid: int) -> Thread | t.CPtr:
s: Scheduler | t.CPtr = _sched_ptr
if tid < 0 or tid >= s.thread_count: return None
return c.Addr(s.threads[tid])
@staticmethod
def create_thread(func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr, thread_pid: t.CInt = 0) -> Thread | t.CPtr:
def create_thread(func: t.CPtr, arg: t.CPtr, thread_pid: int = 0) -> Thread | t.CPtr:
s: Scheduler | t.CPtr = _sched_ptr
if s.thread_count >= MAX_THREADS: return None
tid: int = s.thread_count
@@ -199,11 +199,11 @@ class Scheduler:
th.pid = thread_pid
th.func = func
th.arg = arg
stack_size: t.CUInt64T = THREAD_STACK_SIZE
stack_ptr: t.CVoid | t.CPtr = mm.malloc(stack_size)
stack_size: uint64 = THREAD_STACK_SIZE
stack_ptr: t.CPtr = mm.malloc(stack_size)
_dbg_ct: t.CArray[t.CChar, 96]
viperlib.snprintf(c.Addr(_dbg_ct), 96, "[sched] ct t%d func=0x%lx stack=0x%lx\n",
tid, t.CUInt64T(th.func), t.CUInt64T(stack_ptr))
tid, uint64(th.func), uint64(stack_ptr))
serial.puts(c.Addr(_dbg_ct))
if not stack_ptr:
# B4:栈分配失败回退槽位计数(对齐 process.vp create_process 失败路径),
@@ -212,9 +212,9 @@ class Scheduler:
return None
th.stack = stack_ptr
th.stack_size = stack_size
stack_top: t.CUInt64T = t.CUInt64T(stack_ptr) + stack_size - 16
stack_top = stack_top & ~t.CUInt64T(0xF)
entry_addr: t.CUInt64T = t.CUInt64T(c.Addr(_thread_entry))
stack_top: uint64 = uint64(stack_ptr) + stack_size - 16
stack_top = stack_top & ~uint64(0xF)
entry_addr: uint64 = uint64(c.Addr(_thread_entry))
sp: t.CPtr = t.CPtr(stack_top)
c.Asm(f"""mov rax, {c.AsmInp(sp, t.ASM_DESCR.REG_ANY)}
mov qword ptr [rax - 64], 0x202
@@ -234,8 +234,8 @@ class Scheduler:
_sched_storage: Scheduler = Scheduler()
_sched_ptr: Scheduler | t.CPtr | t.CExport = c.Addr(_sched_storage)
_switch_old_rsp: t.CVoid | t.CPtr | t.CExport
_switch_new_rsp: t.CVoid | t.CPtr | t.CExport
_switch_old_rsp: t.CPtr | t.CExport
_switch_new_rsp: t.CPtr | t.CExport
@c.Attribute(t.attr.naked)
def _do_switch():
@@ -288,11 +288,11 @@ def _thread_entry():
asm.hlt()
Scheduler._yield()
def thread_current() -> t.CInt:
def thread_current() -> int:
s: Scheduler | t.CPtr = _sched_ptr
return s.current_tid
def needs_reschedule() -> t.CInt:
def needs_reschedule() -> int:
s: Scheduler | t.CPtr = _sched_ptr
return s.needs_reschedule
File diff suppressed because it is too large. Load diff
+5 -5
View File
@@ -10,7 +10,7 @@ SERVICE_KEYBOARD: t.CDefine = 1
@t.Object
class KeyboardService:
th: sched.Thread | t.CPtr
running: t.CInt
running: int
usb_kbd_th: sched.Thread | t.CPtr
def __init__(self):
@@ -21,16 +21,16 @@ class KeyboardService:
kbd_svc: KeyboardService
def kbd_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
def kbd_thread(arg: t.CPtr) -> int:
serial.puts("[kbd_svc] started\n")
while True:
if keyboard.has_data():
sc: t.CUInt8T = keyboard.read_scancode()
sc: uint8 = keyboard.read_scancode()
else:
sched.Scheduler._yield()
return 0
def usb_kbd_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
def usb_kbd_thread(arg: t.CPtr) -> int:
serial.puts("[usb_kbd_svc] started\n")
evt: usb_kbd.usb_kbd_event
while True:
@@ -40,7 +40,7 @@ def usb_kbd_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
sched.Scheduler._yield()
return 0
def start() -> t.CInt:
def start() -> int:
global kbd_svc
kbd_svc = KeyboardService()
keyboard.init()
+13 -13
View File
@@ -1,13 +1,13 @@
import t, c
import drivers.input.mouse.mouse as mouse
import drivers.usb.hid.usb_mouse as usb_mouse
import drivers.serial.uart.serial as serial
import sched.sched as sched
SERVICE_MOUSE: t.CDefine = 2
def start() -> t.CInt:
serial.puts("[mse_svc] mouse initialized\n")
if usb_mouse.init() == 0:
serial.puts("[mse_svc] usb mouse initialized\n")
return 0
import t, c
import drivers.input.mouse.mouse as mouse
import drivers.usb.hid.usb_mouse as usb_mouse
import drivers.serial.uart.serial as serial
import sched.sched as sched
SERVICE_MOUSE: t.CDefine = 2
def start() -> int:
serial.puts("[mse_svc] mouse initialized\n")
if usb_mouse.init() == 0:
serial.puts("[mse_svc] usb mouse initialized\n")
return 0
+8 -8
View File
@@ -1,8 +1,8 @@
import t, c
from . import syscall as syscall
def load_so(path: t.CConst | t.CChar | t.CPtr) -> t.CUInt64T:
return syscall._syscall1(t.CUInt64T(syscall.LOAD_SO), t.CUInt64T(path))
def so_call1(sym_name: t.CConst | t.CChar | t.CPtr, arg1: t.CVoid | t.CPtr) -> t.CInt:
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.SO_CALL1), t.CUInt64T(sym_name), t.CUInt64T(arg1)))
import t, c
from . import syscall as syscall
def load_so(path: t.CConst | t.CChar | t.CPtr) -> uint64:
return syscall._syscall1(uint64(syscall.LOAD_SO), uint64(path))
def so_call1(sym_name: t.CConst | t.CChar | t.CPtr, arg1: t.CPtr) -> int:
return int(syscall._syscall2(uint64(syscall.SO_CALL1), uint64(sym_name), uint64(arg1)))
+53 -53
View File
@@ -16,126 +16,126 @@ DT_UNKNOWN: t.CDefine = 0
DT_FILE: t.CDefine = 1
DT_DIR: t.CDefine = 2
def open(path: t.CConst | t.CChar | t.CPtr, flags: t.CUInt32T) -> t.CInt:
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.OPEN), t.CUInt64T(path), t.CUInt64T(flags), 0))
def open(path: t.CConst | t.CChar | t.CPtr, flags: uint32) -> int:
return int(syscall._syscall3(uint64(syscall.OPEN), uint64(path), uint64(flags), 0))
def close(fd: t.CInt) -> t.CInt:
return t.CInt(syscall._syscall1(t.CUInt64T(syscall.CLOSE), t.CUInt64T(fd)))
def close(fd: int) -> int:
return int(syscall._syscall1(uint64(syscall.CLOSE), uint64(fd)))
def read(fd: t.CInt, buf: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.READ), t.CUInt64T(fd), t.CUInt64T(buf), t.CUInt64T(count)))
def read(fd: int, buf: t.CPtr, count: uint32) -> int:
return int(syscall._syscall3(uint64(syscall.READ), uint64(fd), uint64(buf), uint64(count)))
def write(fd: t.CInt, buf: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.WRITE), t.CUInt64T(fd), t.CUInt64T(buf), t.CUInt64T(count)))
def write(fd: int, buf: t.CPtr, count: uint32) -> int:
return int(syscall._syscall3(uint64(syscall.WRITE), uint64(fd), uint64(buf), uint64(count)))
def seek(fd: t.CInt, offset: t.CUInt32T) -> t.CInt:
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.SEEK), t.CUInt64T(fd), t.CUInt64T(offset), 0))
def seek(fd: int, offset: uint32) -> int:
return int(syscall._syscall3(uint64(syscall.SEEK), uint64(fd), uint64(offset), 0))
def tell(fd: t.CInt) -> t.CUInt32T:
return t.CUInt32T(syscall._syscall1(t.CUInt64T(syscall.TELL), t.CUInt64T(fd)))
def tell(fd: int) -> uint32:
return uint32(syscall._syscall1(uint64(syscall.TELL), uint64(fd)))
def fsize(fd: t.CInt) -> t.CUInt32T:
return t.CUInt32T(syscall._syscall1(t.CUInt64T(syscall.SIZE), t.CUInt64T(fd)))
def fsize(fd: int) -> uint32:
return uint32(syscall._syscall1(uint64(syscall.SIZE), uint64(fd)))
def mkdir(path: t.CConst | t.CChar | t.CPtr) -> t.CInt:
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.MKDIR), t.CUInt64T(path), 0, 0))
def mkdir(path: t.CConst | t.CChar | t.CPtr) -> int:
return int(syscall._syscall3(uint64(syscall.MKDIR), uint64(path), 0, 0))
def remove(path: t.CConst | t.CChar | t.CPtr) -> t.CInt:
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.REMOVE), t.CUInt64T(path), 0, 0))
def remove(path: t.CConst | t.CChar | t.CPtr) -> int:
return int(syscall._syscall3(uint64(syscall.REMOVE), uint64(path), 0, 0))
def opendir(path: t.CConst | t.CChar | t.CPtr) -> t.CInt:
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.OPENDIR), t.CUInt64T(path), 0, 0))
def opendir(path: t.CConst | t.CChar | t.CPtr) -> int:
return int(syscall._syscall3(uint64(syscall.OPENDIR), uint64(path), 0, 0))
def readdir(dd: t.CInt, info: t.CVoid | t.CPtr) -> t.CInt:
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.READDIR), t.CUInt64T(dd), t.CUInt64T(info), 0))
def readdir(dd: int, info: t.CPtr) -> int:
return int(syscall._syscall3(uint64(syscall.READDIR), uint64(dd), uint64(info), 0))
def closedir(dd: t.CInt) -> t.CInt:
return t.CInt(syscall._syscall1(t.CUInt64T(syscall.CLOSEDIR), t.CUInt64T(dd)))
def closedir(dd: int) -> int:
return int(syscall._syscall1(uint64(syscall.CLOSEDIR), uint64(dd)))
def stat(path: t.CConst | t.CChar | t.CPtr, info: t.CVoid | t.CPtr) -> t.CInt:
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.STAT), t.CUInt64T(path), t.CUInt64T(info), 0))
def stat(path: t.CConst | t.CChar | t.CPtr, info: t.CPtr) -> int:
return int(syscall._syscall3(uint64(syscall.STAT), uint64(path), uint64(info), 0))
@t.Object
class FileIO:
_fd: t.CInt
_pos: t.CUInt32T
_size: t.CUInt32T
_flags: t.CUInt32T
_closed: t.CInt
_fd: int
_pos: uint32
_size: uint32
_flags: uint32
_closed: int
def __init__(self, fd: t.CInt, flags: t.CUInt32T):
def __init__(self, fd: int, flags: uint32):
self._fd = fd
self._flags = flags
self._pos = 0
self._size = fsize(fd)
self._closed = 0
def read(self, buf: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
def read(self, buf: t.CPtr, count: uint32) -> int:
if self._closed: return -1
n: t.CInt = read(self._fd, buf, count)
n: int = read(self._fd, buf, count)
if n > 0:
self._pos = self._pos + t.CUInt32T(n)
self._pos = self._pos + uint32(n)
return n
def write(self, buf: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
def write(self, buf: t.CPtr, count: uint32) -> int:
if self._closed: return -1
n: t.CInt = write(self._fd, buf, count)
n: int = write(self._fd, buf, count)
if n > 0:
self._pos = self._pos + t.CUInt32T(n)
self._pos = self._pos + uint32(n)
if self._pos > self._size:
self._size = self._pos
return n
def seek(self, offset: t.CUInt32T) -> t.CInt:
def seek(self, offset: uint32) -> int:
if self._closed: return -1
res: t.CInt = seek(self._fd, offset)
res: int = seek(self._fd, offset)
if res == 0:
self._pos = offset
return res
def tell(self) -> t.CUInt32T:
def tell(self) -> uint32:
return self._pos
def size(self) -> t.CUInt32T:
def size(self) -> uint32:
return self._size
def close(self) -> t.CInt:
def close(self) -> int:
if self._closed: return 0
self._closed = 1
return close(self._fd)
def is_closed(self) -> t.CInt:
def is_closed(self) -> int:
return self._closed
@t.Object
class DirIO:
_dd: t.CInt
_closed: t.CInt
_dd: int
_closed: int
def __init__(self, dd: t.CInt):
def __init__(self, dd: int):
self._dd = dd
self._closed = 0
def read(self, info: t.CVoid | t.CPtr) -> t.CInt:
def read(self, info: t.CPtr) -> int:
if self._closed: return -1
return readdir(self._dd, info)
def close(self) -> t.CInt:
def close(self) -> int:
if self._closed: return 0
self._closed = 1
return closedir(self._dd)
def is_closed(self) -> t.CInt:
def is_closed(self) -> int:
return self._closed
def open_file(path: t.CConst | t.CChar | t.CPtr, flags: t.CUInt32T) -> FileIO | t.CPtr:
fd: t.CInt = open(path, flags)
def open_file(path: t.CConst | t.CChar | t.CPtr, flags: uint32) -> FileIO | t.CPtr:
fd: int = open(path, flags)
if fd < 0:
return None
return FileIO(fd, flags)
def open_dir(path: t.CConst | t.CChar | t.CPtr) -> DirIO | t.CPtr:
dd: t.CInt = opendir(path)
dd: int = opendir(path)
if dd < 0:
return None
return DirIO(dd)
+65 -65
View File
@@ -1,65 +1,65 @@
import t, c
from . import syscall as syscall
def exit(code: t.CInt) -> t.CVoid:
syscall._syscall1(t.CUInt64T(syscall.EXIT), t.CUInt64T(code))
def yield_cpu() -> t.CVoid:
syscall._syscall2(t.CUInt64T(syscall.WAIT_WINDOW), t.CUInt64T(0), t.CUInt64T(2))
def spawn(path: t.CConst | t.CChar | t.CPtr, blocking: t.CInt = 0) -> t.CInt:
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.SPAWN), t.CUInt64T(path), t.CUInt64T(blocking)))
def thread_create(func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr = None) -> t.CInt:
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.THREAD_CREATE), t.CUInt64T(func), t.CUInt64T(arg)))
@t.Object
class Thread:
_tid: t.CInt
_func: t.CVoid | t.CPtr
_arg: t.CVoid | t.CPtr
_running: t.CInt
def __init__(self, func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr = None):
self._func = func
self._arg = arg
self._tid = -1
self._running = 0
def start(self) -> t.CInt:
if self._running: return -1
self._tid = thread_create(self._func, self._arg)
if self._tid < 0: return -1
self._running = 1
return 0
def is_alive(self) -> t.CInt:
return self._running
def get_tid(self) -> t.CInt:
return self._tid
@t.Object
class Process:
_pid: t.CInt
_path: t.CArray[t.CChar, 128]
def __init__(self, path: t.CConst | t.CChar | t.CPtr):
self._pid = -1
i: t.CInt = 0
for ch in path:
if i >= 127: break
self._path[i] = ch
i += 1
self._path[i] = 0
def start(self) -> t.CInt:
self._pid = spawn(c.Addr(self._path[0]), 0)
return self._pid
def start_blocking(self) -> t.CInt:
self._pid = spawn(c.Addr(self._path[0]), 1)
return self._pid
def get_pid(self) -> t.CInt:
return self._pid
import t, c
from . import syscall as syscall
def exit(code: int) -> t.CVoid:
syscall._syscall1(uint64(syscall.EXIT), uint64(code))
def yield_cpu() -> t.CVoid:
syscall._syscall2(uint64(syscall.WAIT_WINDOW), uint64(0), uint64(2))
def spawn(path: t.CConst | t.CChar | t.CPtr, blocking: int = 0) -> int:
return int(syscall._syscall2(uint64(syscall.SPAWN), uint64(path), uint64(blocking)))
def thread_create(func: t.CPtr, arg: t.CPtr = None) -> int:
return int(syscall._syscall2(uint64(syscall.THREAD_CREATE), uint64(func), uint64(arg)))
@t.Object
class Thread:
_tid: int
_func: t.CPtr
_arg: t.CPtr
_running: int
def __init__(self, func: t.CPtr, arg: t.CPtr = None):
self._func = func
self._arg = arg
self._tid = -1
self._running = 0
def start(self) -> int:
if self._running: return -1
self._tid = thread_create(self._func, self._arg)
if self._tid < 0: return -1
self._running = 1
return 0
def is_alive(self) -> int:
return self._running
def get_tid(self) -> int:
return self._tid
@t.Object
class Process:
_pid: int
_path: t.CArray[t.CChar, 128]
def __init__(self, path: t.CConst | t.CChar | t.CPtr):
self._pid = -1
i: int = 0
for ch in path:
if i >= 127: break
self._path[i] = ch
i += 1
self._path[i] = 0
def start(self) -> int:
self._pid = spawn(c.Addr(self._path[0]), 0)
return self._pid
def start_blocking(self) -> int:
self._pid = spawn(c.Addr(self._path[0]), 1)
return self._pid
def get_pid(self) -> int:
return self._pid
+33 -33
View File
@@ -1,33 +1,33 @@
import vpsdk.syscall as _syscall
import t, c
import viperlib
# ============================================================
# vpsdk.stdio - 用户态 printf/exit(CExport 裸名,供内核侧代码
# 如 includes/memhub.vp 跨模块引用解析)
#
# 裸机 App 无 libc:printf 走 viperlib.vsnprintf 格式化 + SERIAL_PUTS
# syscall 输出到串口;exit 走 EXIT syscall 通知内核销毁本进程窗口。
# ============================================================
def printf(fmt: t.CConst | str, *args) -> t.CInt | t.CExport:
"""格式化输出到串口(SERIAL_PUTS syscall),返回输出字节数"""
if fmt is None:
return 0
buf: t.CArray[t.CChar, 1024]
n: t.CInt = viperlib.vsnprintf(c.Addr(buf), 1024, fmt, args)
_syscall._syscall1(t.CUInt64T(_syscall.SERIAL_PUTS), t.CUInt64T(c.Addr(buf)))
return n
def exit(status: t.CInt) -> t.CVoid | t.CExport:
"""终止当前进程(EXIT syscall:销毁本进程窗口)"""
_syscall._syscall1(t.CUInt64T(_syscall.EXIT), t.CUInt64T(status))
def fflush(stream: t.CConst | t.CVoid | t.CPtr) -> t.CInt | t.CExport:
"""刷新输出流:串口/控制台输出都是直写,无缓冲可刷,空操作返回 0
覆盖 libc fflush 的裸机缺失(includes/memhub.vp 的诊断/终止路径 call @fflush);
与 printf/exit 同为 CExport 裸名,供内核侧 includes 跨模块引用解析。
"""
return 0
import vpsdk.syscall as _syscall
import t, c
import viperlib
# ============================================================
# vpsdk.stdio - 用户态 printf/exit(CExport 裸名,供内核侧代码
# 如 includes/memhub.vp 跨模块引用解析)
#
# 裸机 App 无 libc:printf 走 viperlib.vsnprintf 格式化 + SERIAL_PUTS
# syscall 输出到串口;exit 走 EXIT syscall 通知内核销毁本进程窗口。
# ============================================================
def printf(fmt: t.CConst | str, *args) -> int | t.CExport:
"""格式化输出到串口(SERIAL_PUTS syscall),返回输出字节数"""
if fmt is None:
return 0
buf: t.CArray[t.CChar, 1024]
n: int = viperlib.vsnprintf(c.Addr(buf), 1024, fmt, args)
_syscall._syscall1(uint64(_syscall.SERIAL_PUTS), uint64(c.Addr(buf)))
return n
def exit(status: int) -> t.CVoid | t.CExport:
"""终止当前进程(EXIT syscall:销毁本进程窗口)"""
_syscall._syscall1(uint64(_syscall.EXIT), uint64(status))
def fflush(stream: t.CConst | t.CPtr) -> int | t.CExport:
"""刷新输出流:串口/控制台输出都是直写,无缓冲可刷,空操作返回 0
覆盖 libc fflush 的裸机缺失(includes/memhub.vp 的诊断/终止路径 call @fflush);
与 printf/exit 同为 CExport 裸名,供内核侧 includes 跨模块引用解析。
"""
return 0
+59 -59
View File
@@ -1,59 +1,59 @@
import vpsdk.syscall as _sc
import string
import t, c
HEAP_BLOCK_MAGIC: t.CDefine = 0x48454150
@t.Object
class _heap_hdr:
magic: t.CUInt32T
size: t.CUInt32T
_heap_inited: t.CInt = 0
def _heap_init():
global _heap_inited
_heap_inited = 1
def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport:
global _heap_inited
if size == 0: return None
if _heap_inited == 0:
_heap_init()
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
total: t.CSizeT = hdr_size + size
ptr: t.CUInt64T = _sc._syscall1(t.CUInt64T(_sc.SYSCALL_MMAP), t.CUInt64T(total))
if ptr == 0: return None
hdr: _heap_hdr | t.CPtr = t.CVoid(ptr, t.CPtr)
hdr.magic = HEAP_BLOCK_MAGIC
hdr.size = t.CUInt32T(size)
return t.CVoid(ptr + hdr_size, t.CPtr)
def free(ptr: t.CVoid | t.CPtr) -> t.CExport:
if ptr is None: return
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
hdr: _heap_hdr | t.CPtr = t.CVoid(t.CUInt64T(ptr) - hdr_size, t.CPtr)
if hdr.magic != HEAP_BLOCK_MAGIC: return
def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport:
total: t.CSizeT = nmemb * size
p: t.CVoid | t.CPtr = malloc(total)
if p:
string.memset(p, 0, total)
return p
def realloc(ptr: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport:
if ptr is None: return malloc(size)
if size == 0:
free(ptr)
return None
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
hdr: _heap_hdr | t.CPtr = t.CVoid(t.CUInt64T(ptr) - hdr_size, t.CPtr)
if hdr.magic != HEAP_BLOCK_MAGIC: return None
old_size: t.CSizeT = hdr.size
new_ptr: t.CVoid | t.CPtr = malloc(size)
if new_ptr is None: return None
copy_size: t.CSizeT = old_size if old_size < size else size
string.memcpy(new_ptr, ptr, copy_size)
free(ptr)
return new_ptr
import vpsdk.syscall as _sc
import string
import t, c
HEAP_BLOCK_MAGIC: t.CDefine = 0x48454150
@t.Object
class _heap_hdr:
magic: uint32
size: uint32
_heap_inited: int = 0
def _heap_init():
global _heap_inited
_heap_inited = 1
def malloc(size: t.CSizeT) -> t.CPtr | t.CExport:
global _heap_inited
if size == 0: return None
if _heap_inited == 0:
_heap_init()
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
total: t.CSizeT = hdr_size + size
ptr: uint64 = _sc._syscall1(uint64(_sc.SYSCALL_MMAP), uint64(total))
if ptr == 0: return None
hdr: _heap_hdr | t.CPtr = t.CVoid(ptr, t.CPtr)
hdr.magic = HEAP_BLOCK_MAGIC
hdr.size = uint32(size)
return t.CVoid(ptr + hdr_size, t.CPtr)
def free(ptr: t.CPtr) -> t.CExport:
if ptr is None: return
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
hdr: _heap_hdr | t.CPtr = t.CVoid(uint64(ptr) - hdr_size, t.CPtr)
if hdr.magic != HEAP_BLOCK_MAGIC: return
def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CPtr | t.CExport:
total: t.CSizeT = nmemb * size
p: t.CPtr = malloc(total)
if p:
string.memset(p, 0, total)
return p
def realloc(ptr: t.CPtr, size: t.CSizeT) -> t.CPtr | t.CExport:
if ptr is None: return malloc(size)
if size == 0:
free(ptr)
return None
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
hdr: _heap_hdr | t.CPtr = t.CVoid(uint64(ptr) - hdr_size, t.CPtr)
if hdr.magic != HEAP_BLOCK_MAGIC: return None
old_size: t.CSizeT = hdr.size
new_ptr: t.CPtr = malloc(size)
if new_ptr is None: return None
copy_size: t.CSizeT = old_size if old_size < size else size
string.memcpy(new_ptr, ptr, copy_size)
free(ptr)
return new_ptr
+117 -117
View File
@@ -1,117 +1,117 @@
import t, c
CREATE_WINDOW: t.CDefine = 1
DRAW_TEXT: t.CDefine = 2
EXIT: t.CDefine = 3
OPEN: t.CDefine = 4
CLOSE: t.CDefine = 5
READ: t.CDefine = 6
WRITE: t.CDefine = 7
SEEK: t.CDefine = 8
TELL: t.CDefine = 9
SIZE: t.CDefine = 10
MKDIR: t.CDefine = 11
REMOVE: t.CDefine = 12
OPENDIR: t.CDefine = 13
READDIR: t.CDefine = 14
CLOSEDIR: t.CDefine = 15
STAT: t.CDefine = 16
WAIT_WINDOW: t.CDefine = 17
SERIAL_PUTS: t.CDefine = 18
LOAD_SO: t.CDefine = 19
SO_CALL1: t.CDefine = 20
GET_WINBUF: t.CDefine = 21
WIN_FLUSH: t.CDefine = 22
POLL_EVENT: t.CDefine = 23
SET_CURSOR: t.CDefine = 24
YIELD: t.CDefine = 25
SET_TITLE: t.CDefine = 26
SET_GEOMETRY: t.CDefine = 27
SPAWN: t.CDefine = 28
MMAP: t.CDefine = 29
MUNMAP: t.CDefine = 30
SET_RESIZABLE: t.CDefine = 31
GET_WIN_SIZE: t.CDefine = 32
THREAD_CREATE: t.CDefine = 33
# SYSCALL_* 别名(vpsdk.stdlib 等模块引用;数值与内核 VKernel/intr/syscall.vp 一致)
SYSCALL_MMAP: t.CDefine = 29
def _syscall0(num: t.CUInt64T) -> t.CUInt64T:
ret: t.CUInt64T
c.Asm(f"""mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11])
return ret
def _syscall1(num: t.CUInt64T, a1: t.CUInt64T) -> t.CUInt64T:
ret: t.CUInt64T
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI])
return ret
def _syscall2(num: t.CUInt64T, a1: t.CUInt64T, a2: t.CUInt64T) -> t.CUInt64T:
ret: t.CUInt64T
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI])
return ret
def _syscall3(num: t.CUInt64T, a1: t.CUInt64T, a2: t.CUInt64T, a3: t.CUInt64T) -> t.CUInt64T:
ret: t.CUInt64T
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX])
return ret
def _syscall5(num: t.CUInt64T, a1: t.CUInt64T, a2: t.CUInt64T, a3: t.CUInt64T, a4: t.CUInt64T, a5: t.CUInt64T) -> t.CUInt64T:
ret: t.CUInt64T
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
mov r10, {c.AsmInp(a4, t.ASM_DESCR.REG_ANY)}
mov r8, {c.AsmInp(a5, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R8])
return ret
def _syscall6(num: t.CUInt64T, a1: t.CUInt64T, a2: t.CUInt64T, a3: t.CUInt64T, a4: t.CUInt64T, a5: t.CUInt64T, a6: t.CUInt64T) -> t.CUInt64T:
ret: t.CUInt64T
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
mov r10, {c.AsmInp(a4, t.ASM_DESCR.REG_ANY)}
mov r8, {c.AsmInp(a5, t.ASM_DESCR.REG_ANY)}
mov r9, {c.AsmInp(a6, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R8,
t.ASM_DESCR.CLOBBER_R9])
return ret
import t, c
CREATE_WINDOW: t.CDefine = 1
DRAW_TEXT: t.CDefine = 2
EXIT: t.CDefine = 3
OPEN: t.CDefine = 4
CLOSE: t.CDefine = 5
READ: t.CDefine = 6
WRITE: t.CDefine = 7
SEEK: t.CDefine = 8
TELL: t.CDefine = 9
SIZE: t.CDefine = 10
MKDIR: t.CDefine = 11
REMOVE: t.CDefine = 12
OPENDIR: t.CDefine = 13
READDIR: t.CDefine = 14
CLOSEDIR: t.CDefine = 15
STAT: t.CDefine = 16
WAIT_WINDOW: t.CDefine = 17
SERIAL_PUTS: t.CDefine = 18
LOAD_SO: t.CDefine = 19
SO_CALL1: t.CDefine = 20
GET_WINBUF: t.CDefine = 21
WIN_FLUSH: t.CDefine = 22
POLL_EVENT: t.CDefine = 23
SET_CURSOR: t.CDefine = 24
YIELD: t.CDefine = 25
SET_TITLE: t.CDefine = 26
SET_GEOMETRY: t.CDefine = 27
SPAWN: t.CDefine = 28
MMAP: t.CDefine = 29
MUNMAP: t.CDefine = 30
SET_RESIZABLE: t.CDefine = 31
GET_WIN_SIZE: t.CDefine = 32
THREAD_CREATE: t.CDefine = 33
# SYSCALL_* 别名(vpsdk.stdlib 等模块引用;数值与内核 VKernel/intr/syscall.vp 一致)
SYSCALL_MMAP: t.CDefine = 29
def _syscall0(num: uint64) -> uint64:
ret: uint64
c.Asm(f"""mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11])
return ret
def _syscall1(num: uint64, a1: uint64) -> uint64:
ret: uint64
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI])
return ret
def _syscall2(num: uint64, a1: uint64, a2: uint64) -> uint64:
ret: uint64
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI])
return ret
def _syscall3(num: uint64, a1: uint64, a2: uint64, a3: uint64) -> uint64:
ret: uint64
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX])
return ret
def _syscall5(num: uint64, a1: uint64, a2: uint64, a3: uint64, a4: uint64, a5: uint64) -> uint64:
ret: uint64
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
mov r10, {c.AsmInp(a4, t.ASM_DESCR.REG_ANY)}
mov r8, {c.AsmInp(a5, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R8])
return ret
def _syscall6(num: uint64, a1: uint64, a2: uint64, a3: uint64, a4: uint64, a5: uint64, a6: uint64) -> uint64:
ret: uint64
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
mov r10, {c.AsmInp(a4, t.ASM_DESCR.REG_ANY)}
mov r8, {c.AsmInp(a5, t.ASM_DESCR.REG_ANY)}
mov r9, {c.AsmInp(a6, t.ASM_DESCR.REG_ANY)}
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
syscall""",
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R8,
t.ASM_DESCR.CLOBBER_R9])
return ret
+1557 -1557
View File
File diff suppressed because it is too large. Load diff
+93 -93
View File
@@ -1,93 +1,93 @@
import t, c
from . import syscall as syscall
from stdint import *
STYLE_CLASSIC: t.CDefine = 0
STYLE_WIN10: t.CDefine = 1
STYLE_WIN11: t.CDefine = 2
STYLE_WIN7: t.CDefine = 3
STYLE_WINXP: t.CDefine = 4
EVENT_TYPE_NONE: t.CDefine = 0
EVENT_TYPE_CLICK: t.CDefine = 1
EVENT_TYPE_HOVER: t.CDefine = 2
EVENT_TYPE_RELEASE: t.CDefine = 3
EVENT_TYPE_HOVER_LEAVE: t.CDefine = 4
EVENT_TYPE_KEY: t.CDefine = 5
EVENT_TYPE_KEY_RELEASE: t.CDefine = 6
EVENT_TYPE_PING: t.CDefine = 7
EVENT_TYPE_RESIZE: t.CDefine = 8
KEY_STATE_PRESS: t.CDefine = 1
KEY_STATE_RELEASE: t.CDefine = 2
KEY_STATE_REPEAT: t.CDefine = 3
CURSOR_DEFAULT: t.CDefine = 0
CURSOR_IBEAM: t.CDefine = 1
CURSOR_RESIZE_EW: t.CDefine = 2
CURSOR_RESIZE_NS: t.CDefine = 3
CURSOR_RESIZE_NWSE: t.CDefine = 4
VK_LEFT: t.CDefine = -1
VK_RIGHT: t.CDefine = -2
VK_UP: t.CDefine = -3
VK_DOWN: t.CDefine = -4
VK_HOME: t.CDefine = -5
VK_END: t.CDefine = -6
VK_DELETE: t.CDefine = -7
VK_PRIOR: t.CDefine = -8
VK_NEXT: t.CDefine = -9
@c.Attribute(t.attr.packed)
@t.Object
class InputEvent:
type: t.CUInt32T
win_id: t.CInt
x: t.CInt
y: t.CInt
button: t.CUInt8T
_pad0: t.CUInt8T
_pad1: t.CUInt8T
_pad2: t.CUInt8T
def create_window(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | t.CChar | t.CPtr, style: t.CInt) -> t.CInt:
return t.CInt(syscall._syscall6(t.CUInt64T(syscall.CREATE_WINDOW), t.CUInt64T(x), t.CUInt64T(y), t.CUInt64T(w), t.CUInt64T(h), t.CUInt64T(title), t.CUInt64T(style)))
def draw_text(win_id: t.CInt, x: t.CInt, y: t.CInt, text: t.CConst | t.CChar | t.CPtr, color: t.CUInt32T) -> t.CInt:
return t.CInt(syscall._syscall5(t.CUInt64T(syscall.DRAW_TEXT), t.CUInt64T(win_id), t.CUInt64T(x), t.CUInt64T(y), t.CUInt64T(text), t.CUInt64T(color)))
def get_winbuf(win_id: t.CInt) -> UINT32PTR:
return t.CVoid(syscall._syscall2(t.CUInt64T(syscall.GET_WINBUF), t.CUInt64T(win_id), 0), t.CPtr)
def get_win_size(win_id: t.CInt) -> t.CInt:
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.GET_WIN_SIZE), t.CUInt64T(win_id), 0))
def flush(win_id: t.CInt) -> t.CVoid:
syscall._syscall2(t.CUInt64T(syscall.WIN_FLUSH), t.CUInt64T(win_id), 0)
def mainloop(win_id: t.CInt) -> t.CVoid:
syscall._syscall1(t.CUInt64T(syscall.WAIT_WINDOW), t.CUInt64T(win_id))
def poll_event(evt: InputEvent | t.CPtr) -> t.CInt:
return t.CInt(syscall._syscall1(t.CUInt64T(syscall.POLL_EVENT), t.CUInt64T(evt)))
def is_active(win_id: t.CInt) -> t.CInt:
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.WAIT_WINDOW), t.CUInt64T(win_id), 1))
def set_cursor_type(win_id: t.CInt, cursor_t: t.CInt) -> t.CVoid:
syscall._syscall2(t.CUInt64T(syscall.SET_CURSOR), t.CUInt64T(win_id), t.CUInt64T(cursor_t))
def set_title(win_id: t.CInt, title: t.CConst | t.CChar | t.CPtr) -> t.CInt:
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.SET_TITLE), t.CUInt64T(win_id), t.CUInt64T(title)))
def set_geometry(win_id: t.CInt, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.CInt:
return t.CInt(syscall._syscall5(t.CUInt64T(syscall.SET_GEOMETRY), t.CUInt64T(win_id), t.CUInt64T(x), t.CUInt64T(y), t.CUInt64T(w), t.CUInt64T(h)))
def set_resizable(win_id: t.CInt, rw: t.CInt, rh: t.CInt) -> t.CInt:
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.SET_RESIZABLE), t.CUInt64T(win_id), t.CUInt64T(rw), t.CUInt64T(rh)))
#class Window:
# HWND: t.CInt
# def __init__(self):
# self.HWND = create_window(100, 100, 100, 100)
import t, c
from . import syscall as syscall
from stdint import *
STYLE_CLASSIC: t.CDefine = 0
STYLE_WIN10: t.CDefine = 1
STYLE_WIN11: t.CDefine = 2
STYLE_WIN7: t.CDefine = 3
STYLE_WINXP: t.CDefine = 4
EVENT_TYPE_NONE: t.CDefine = 0
EVENT_TYPE_CLICK: t.CDefine = 1
EVENT_TYPE_HOVER: t.CDefine = 2
EVENT_TYPE_RELEASE: t.CDefine = 3
EVENT_TYPE_HOVER_LEAVE: t.CDefine = 4
EVENT_TYPE_KEY: t.CDefine = 5
EVENT_TYPE_KEY_RELEASE: t.CDefine = 6
EVENT_TYPE_PING: t.CDefine = 7
EVENT_TYPE_RESIZE: t.CDefine = 8
KEY_STATE_PRESS: t.CDefine = 1
KEY_STATE_RELEASE: t.CDefine = 2
KEY_STATE_REPEAT: t.CDefine = 3
CURSOR_DEFAULT: t.CDefine = 0
CURSOR_IBEAM: t.CDefine = 1
CURSOR_RESIZE_EW: t.CDefine = 2
CURSOR_RESIZE_NS: t.CDefine = 3
CURSOR_RESIZE_NWSE: t.CDefine = 4
VK_LEFT: t.CDefine = -1
VK_RIGHT: t.CDefine = -2
VK_UP: t.CDefine = -3
VK_DOWN: t.CDefine = -4
VK_HOME: t.CDefine = -5
VK_END: t.CDefine = -6
VK_DELETE: t.CDefine = -7
VK_PRIOR: t.CDefine = -8
VK_NEXT: t.CDefine = -9
@c.Attribute(t.attr.packed)
@t.Object
class InputEvent:
type: uint32
win_id: int
x: int
y: int
button: uint8
_pad0: uint8
_pad1: uint8
_pad2: uint8
def create_window(x: int, y: int, w: int, h: int, title: t.CConst | t.CChar | t.CPtr, style: int) -> int:
return int(syscall._syscall6(uint64(syscall.CREATE_WINDOW), uint64(x), uint64(y), uint64(w), uint64(h), uint64(title), uint64(style)))
def draw_text(win_id: int, x: int, y: int, text: t.CConst | t.CChar | t.CPtr, color: uint32) -> int:
return int(syscall._syscall5(uint64(syscall.DRAW_TEXT), uint64(win_id), uint64(x), uint64(y), uint64(text), uint64(color)))
def get_winbuf(win_id: int) -> UINT32PTR:
return t.CVoid(syscall._syscall2(uint64(syscall.GET_WINBUF), uint64(win_id), 0), t.CPtr)
def get_win_size(win_id: int) -> int:
return int(syscall._syscall2(uint64(syscall.GET_WIN_SIZE), uint64(win_id), 0))
def flush(win_id: int) -> t.CVoid:
syscall._syscall2(uint64(syscall.WIN_FLUSH), uint64(win_id), 0)
def mainloop(win_id: int) -> t.CVoid:
syscall._syscall1(uint64(syscall.WAIT_WINDOW), uint64(win_id))
def poll_event(evt: InputEvent | t.CPtr) -> int:
return int(syscall._syscall1(uint64(syscall.POLL_EVENT), uint64(evt)))
def is_active(win_id: int) -> int:
return int(syscall._syscall2(uint64(syscall.WAIT_WINDOW), uint64(win_id), 1))
def set_cursor_type(win_id: int, cursor_t: int) -> t.CVoid:
syscall._syscall2(uint64(syscall.SET_CURSOR), uint64(win_id), uint64(cursor_t))
def set_title(win_id: int, title: t.CConst | t.CChar | t.CPtr) -> int:
return int(syscall._syscall2(uint64(syscall.SET_TITLE), uint64(win_id), uint64(title)))
def set_geometry(win_id: int, x: int, y: int, w: int, h: int) -> int:
return int(syscall._syscall5(uint64(syscall.SET_GEOMETRY), uint64(win_id), uint64(x), uint64(y), uint64(w), uint64(h)))
def set_resizable(win_id: int, rw: int, rh: int) -> int:
return int(syscall._syscall3(uint64(syscall.SET_RESIZABLE), uint64(win_id), uint64(rw), uint64(rh)))
#class Window:
# HWND: int
# def __init__(self):
# self.HWND = create_window(100, 100, 100, 100)