feat: WiFi驱动(ath9k) + TTF字体 + shell命令行 + FirstInit WiFi跳过

新增: ath9k PCIe WiFi驱动(被动扫描/beacon解析), shell命令行(help/clear/echo/version/date/reboot/halt), Consolas 18px TTF字体, render_ascii.py

修改: dkm_net_api扩展scan接口, FirstInit无WiFi设备时跳过, DSK加载shell.elf, 非首次启动直接进shell
This commit is contained in:
xyou
2026-07-03 12:59:59 +08:00
parent 129175a5d8
commit 3662345434
31 changed files with 4437 additions and 240 deletions
+325 -162
View File
@@ -99,106 +99,26 @@ static u32 blend(u32 c1, u32 c2, u32 a) {
return 0xFF000000|(b<<16)|(g<<8)|r;
}
/* 8x8 font for ASCII */
static const u8 font[95][8] = {
{0,0,0,0,0,0,0,0},{0x18,0x3c,0x3c,0x18,0x18,0,0x18,0}, /* ! */
{0x6c,0x6c,0,0,0,0,0,0},{0x6c,0x6c,0xfe,0x6c,0xfe,0x6c,0x6c,0}, /* # */
{0x18,0x7e,0xc0,0x7c,0x6,0xfc,0x18,0},{0,0xc6,0xcc,0x18,0x30,0x66,0xc6,0}, /* $ % */
{0x38,0x6c,0x38,0x76,0xdc,0xcc,0x76,0},{0x18,0x18,0x30,0,0,0,0,0}, /* & ' */
{0xc,0x18,0x30,0x30,0x30,0x18,0xc,0},{0x30,0x18,0xc,0xc,0xc,0x18,0x30,0}, /* ( ) */
{0,0x66,0x3c,0xff,0x3c,0x66,0,0},{0,0x18,0x18,0x7e,0x18,0x18,0,0}, /* * + */
{0,0,0,0,0,0x18,0x18,0x30},{0,0,0,0x7e,0,0,0,0},{0,0,0,0,0,0x18,0x18,0}, /* , - . */
{0x6,0xc,0x18,0x30,0x60,0xc0,0x80,0}, /* / */
{0x7c,0xc6,0xce,0xde,0xf6,0xe6,0x7c,0},{0x18,0x38,0x18,0x18,0x18,0x18,0x7e,0}, /* 0 1 */
{0x7c,0xc6,0x6,0xc,0x30,0x60,0xfe,0},{0x7c,0xc6,0x6,0x3c,0x6,0xc6,0x7c,0}, /* 2 3 */
{0x1c,0x3c,0x6c,0xcc,0xfe,0xc,0x1e,0},{0xfe,0xc0,0xfc,0x6,0x6,0xc6,0x7c,0}, /* 4 5 */
{0x38,0x60,0xc0,0xfc,0xc6,0xc6,0x7c,0},{0xfe,0xc6,0xc,0x18,0x30,0x30,0x30,0}, /* 6 7 */
{0x7c,0xc6,0xc6,0x7c,0xc6,0xc6,0x7c,0},{0x7c,0xc6,0xc6,0x7e,0x6,0xc,0x78,0}, /* 8 9 */
{0,0x18,0x18,0,0,0x18,0x18,0},{0,0x18,0x18,0,0,0x18,0x18,0x30}, /* : ; */
{0x6,0xc,0x18,0x30,0x18,0xc,0x6,0},{0,0,0x7e,0,0,0x7e,0,0}, /* < = */
{0x60,0x30,0x18,0xc,0x18,0x30,0x60,0},{0x7c,0xc6,0xc,0x18,0x18,0,0x18,0}, /* > ? */
{0x7c,0xc6,0xde,0xde,0xde,0xc0,0x78,0}, /* @ */
{0x38,0x6c,0xc6,0xfe,0xc6,0xc6,0xc6,0},{0xfc,0x66,0x66,0x7c,0x66,0x66,0xfc,0}, /* A B */
{0x3c,0x66,0xc0,0xc0,0xc0,0x66,0x3c,0},{0xf8,0x6c,0x66,0x66,0x66,0x6c,0xf8,0}, /* C D */
{0xfe,0x62,0x68,0x78,0x68,0x62,0xfe,0},{0xfe,0x62,0x68,0x78,0x68,0x60,0xf0,0}, /* E F */
{0x3c,0x66,0xc0,0xc0,0xce,0x66,0x3e,0},{0xc6,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0}, /* G H */
{0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0},{0x1e,0xc,0xc,0xc,0xcc,0xcc,0x78,0}, /* I J */
{0xe6,0x66,0x6c,0x78,0x6c,0x66,0xe6,0},{0xf0,0x60,0x60,0x60,0x62,0x66,0xfe,0}, /* K L */
{0xc6,0xee,0xfe,0xfe,0xd6,0xc6,0xc6,0},{0xc6,0xe6,0xf6,0xde,0xce,0xc6,0xc6,0}, /* M N */
{0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0},{0xfc,0x66,0x66,0x7c,0x60,0x60,0xf0,0}, /* O P */
{0x7c,0xc6,0xc6,0xc6,0xc6,0xce,0x7c,0xe},{0xfc,0x66,0x66,0x7c,0x6c,0x66,0xe6,0}, /* Q R */
{0x7c,0xc6,0xe0,0x78,0xe,0xc6,0x7c,0},{0x7e,0x7e,0x5a,0x18,0x18,0x18,0x3c,0}, /* S T */
{0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0},{0xc6,0xc6,0xc6,0xc6,0xc6,0x6c,0x38,0}, /* U V */
{0xc6,0xc6,0xc6,0xd6,0xd6,0xfe,0x6c,0},{0xc6,0xc6,0x6c,0x38,0x38,0x6c,0xc6,0}, /* W X */
{0x66,0x66,0x66,0x3c,0x18,0x18,0x3c,0},{0xfe,0xc6,0x8c,0x18,0x32,0x66,0xfe,0}, /* Y Z */
{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}, /* ] ^ */
{0x18,0x18,0x18,0x18,0x18,0x18,0x18,0}, /* _ */
{0,0,0,0,0,0,0,0}, /* ` */
/* a-z lowercase — full-height (no top blank rows) so they scale like uppercase */
{0x7c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0}, /* a */
{0xc6,0xc6,0xc6,0xfc,0xc6,0xc6,0xfc,0}, /* b */
{0x7c,0xc6,0xc0,0xc0,0xc0,0xc6,0x7c,0}, /* c */
{0x06,0x06,0x06,0xfc,0xc6,0xc6,0xfc,0}, /* d */
{0x7c,0xc6,0xfe,0xc0,0xfc,0xc0,0xc0,0}, /* e */
{0x7c,0xc6,0xc0,0xf8,0xc0,0xc0,0xc0,0}, /* f */
{0x7c,0xc6,0xc0,0xde,0xc6,0xc6,0x7c,0}, /* g */
{0xc6,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0}, /* h */
{0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0}, /* i */
{0x06,0x06,0x06,0xc6,0xc6,0xc6,0x7c,0}, /* j */
{0xc6,0xcc,0xd8,0xf0,0xd8,0xcc,0xc6,0}, /* k */
{0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xfe,0}, /* l */
{0xc6,0xee,0xfe,0xfe,0xc6,0xc6,0xc6,0}, /* m */
{0xc6,0xe6,0xf6,0xde,0xce,0xc6,0xc6,0}, /* n */
{0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0}, /* o */
{0xc6,0xc6,0xc6,0xfc,0xc0,0xc0,0xc0,0}, /* p */
{0x7c,0xc6,0xc6,0xce,0x7c,0x06,0x06,0}, /* q */
{0xc6,0xc6,0xcc,0xf8,0xcc,0xc6,0xc6,0}, /* r */
{0x7c,0xc0,0x7c,0x06,0xc6,0xc6,0x7c,0}, /* s */
{0x18,0x18,0x7e,0x18,0x18,0x18,0x18,0}, /* t */
{0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0}, /* u */
{0xc6,0xc6,0xc6,0xc6,0xc6,0x6c,0x38,0}, /* v */
{0xc6,0xc6,0xd6,0xfe,0xee,0xc6,0xc6,0}, /* w */
{0xc6,0xc6,0x6c,0x38,0x6c,0xc6,0xc6,0}, /* x */
{0xc6,0xc6,0xc6,0x7c,0x06,0x06,0x7c,0}, /* y */
{0xfe,0x0c,0x18,0x30,0x60,0xc0,0xfe,0}, /* z */
};
/* ASCII text — thin 8x8 → 10x16, preserves case, draws foreground only (no bg fill) */
#define ASCII_W 10
#define ASCII_H 16
#define ASCII_STEP 12
/* ASCII font — Consolas 18px grayscale, pre-rendered from C:\Windows\Fonts\consola.ttf */
#include "ascii_bitmaps.c"
/* ASCII text — Consolas 18px grayscale, alpha-blend rendered (skips transparent pixels) */
#define ASCII_W 11
#define ASCII_H 18
#define ASCII_STEP 11
static void fb_char(u32 *fb, u32 ch, i64 x, i64 y, u32 fg, u32 bg) {
u32 idx = ch >= ' ' && ch <= 'z' ? (u32)(ch-' ') : 0;
const u8 *g = font[idx];
u8 pat[8][8];
for (i64 r=0; r<8; r++) {
u8 row = g[r];
for (i64 c=0; c<8; c++) {
pat[r][c] = (row & (0x80>>c)) ? 1 : 0;
}
}
for (i64 sy=0; sy<ASCII_H; sy++) {
i64 yy = y + sy;
if (ch < ' ' || ch > '~') ch = ' ';
u32 idx = (u32)(ch - ' ');
const u8 *g = g_ascii[idx];
for (i64 r=0; r<ASCII_H; r++) {
i64 yy = y + r;
if (yy < 0 || (u64)yy >= fb_h) continue;
u32 *line = (u32 *)((u8 *)fb + (u64)yy * fb_p);
i64 src_y = sy * 7 / (ASCII_H - 1);
if (src_y > 7) src_y = 7;
for (i64 sx=0; sx<ASCII_W; sx++) {
i64 src_x = sx * 7 / (ASCII_W - 1);
if (src_x > 7) src_x = 7;
int on = pat[src_y][src_x];
int edge = 0;
if (!on) {
if (src_x > 0 && pat[src_y][src_x-1]) edge = 1;
if (src_x < 7 && pat[src_y][src_x+1]) edge = 1;
if (src_y > 0 && pat[src_y-1][src_x]) edge = 1;
if (src_y < 7 && pat[src_y+1][src_x]) edge = 1;
if (!edge) continue;
}
i64 xx = x + sx;
for (i64 c=0; c<ASCII_W; c++) {
u32 a = g[r * ASCII_W + c];
if (a == 0) continue;
i64 xx = x + c;
if (xx < 0 || (u64)xx >= fb_w) continue;
line[(u64)xx] = on ? fg : blend(bg, fg, 72);
line[(u64)xx] = (a == 255) ? fg : blend(bg, fg, a);
}
}
}
@@ -352,7 +272,7 @@ static void draw_rounded_input(u32 *fb, i64 x, i64 y, i64 w, i64 h, const char *
char out[64]; int i=0;
while(value[i] && i<60) { out[i] = mask ? '*' : value[i]; i++; }
out[i]=0;
if (out[0]) fb_text(fb, out, x+14, y+(h-16)/2, fg, fill);
if (out[0]) fb_text(fb, out, x+14, y+(h-ASCII_H)/2, fg, fill);
if (active) {
i64 cx2 = x + 14 + i * ASCII_STEP;
fill_rect(fb, cx2, y+10, 2, h-20, fg);
@@ -704,43 +624,202 @@ static void read_prefs_page(u32 *fb, i64 card_x, i64 card_y, setup_prefs *prefs,
}
typedef struct {
int mode;
int device;
int ip;
int dns;
int selected;
int connected;
char ssid[32];
char password[64];
} setup_net;
static const char *net_value(int row, int val) {
if (row == 0) return val == 0 ? "Disabled" : (val == 1 ? "DHCP" : "Manual");
if (row == 1) return val == 0 ? "Auto" : (val == 1 ? "e1000" : "virtio-net");
if (row == 2) return val ? "Manual" : "Auto DHCP";
if (row == 3) return val ? "Manual DNS" : "Auto DNS";
return "";
/* UI 显示行数(固定 4 行布局);真实扫描结果数由 g_wifi_scan_count 决定。 */
#define WIFI_SCAN_COUNT 4
#define WIFI_MAX_RESULTS 8
/* 真实 WiFi 扫描结果(来自 ath9k 驱动通过 kernel_api.net.scan_* 查询)。 */
static char g_wifi_ssids[WIFI_MAX_RESULTS][34];
static char g_wifi_meta[WIFI_MAX_RESULTS][20];
static int g_wifi_scan_count;
static int g_wifi_scan_tried; /* 是否已尝试查询扫描结果 */
static int g_no_wireless_device; /* 检测到无无线设备时跳过 WiFi 页面 */
/* dkm_net_api 函数指针类型(通过偏移访问 kernel_api.net)。 */
typedef u32 (*net_device_count_fn)(void);
typedef int (*net_device_info_fn)(u32 index, void *out);
typedef int (*net_scan_start_fn)(u32 index);
typedef int (*net_scan_count_fn)(u32 index);
typedef int (*net_scan_result_fn)(u32 index, u32 n, void *out);
typedef int (*net_is_wireless_fn)(u32 index);
/* dkm_net_scan_result 布局(须与 UTSM/include/utsm/net.h 一致)。 */
typedef struct {
char ssid[33];
u8 bssid[6];
u8 channel;
i8 rssi;
u8 security;
} net_scan_result;
#define DKM_NET_SEC_OPEN 0
#define DKM_NET_SEC_WEP 1
#define DKM_NET_SEC_WPA 2
#define DKM_NET_SEC_WPA2 3
#define DKM_NET_SEC_WPA3 4
/* 把加密类型 + RSSI 转为 "WPA2 strong" 这种简短描述。 */
static void wifi_meta_str(char *out, u32 cap, u8 security, i8 rssi) {
if (!cap) return;
const char *sec;
switch (security) {
case DKM_NET_SEC_WPA2: sec = "WPA2"; break;
case DKM_NET_SEC_WPA: sec = "WPA "; break;
case DKM_NET_SEC_WPA3: sec = "WPA3"; break;
case DKM_NET_SEC_WEP: sec = "WEP "; break;
default: sec = "Open"; break;
}
/* RSSI 分级:>=-50 strong, -51..-65 good, -66..-75 weak, else very weak */
const char *q;
i8 r = rssi;
if (r >= -50) q = "strong";
else if (r >= -65) q = "good";
else if (r >= -75) q = "weak";
else q = "very weak";
/* 手动拼接 "SEC quality" */
u32 i = 0;
while (sec[i] && i + 1 < cap) { out[i] = sec[i]; i++; }
while (i < 5 && i + 1 < cap) { out[i++] = ' '; }
u32 j = 0;
while (q[j] && i + 1 < cap) { out[i++] = q[j++]; }
out[i] = 0;
}
static int net_get(const setup_net *n, int row) {
if (row == 0) return n->mode;
if (row == 1) return n->device;
if (row == 2) return n->ip;
if (row == 3) return n->dns;
return 0;
/* 通过 kernel_api 查询无线设备并读取扫描结果。
* kernel_api 偏移布局:
* +0x48 net_api 指针
* net_api 偏移布局(追加 scan 接口后):
* +0 register_device, +8 device_count, +16 device_info,
* +24 tx, +32 rx_poll, +40 scan_start, +48 scan_count,
* +56 scan_result, +64 is_wireless
*/
static void wifi_query_scan(u64 kernel_api) {
g_wifi_scan_tried = 1;
g_wifi_scan_count = 0;
if (!kernel_api) { logl("[FirstInit] no kernel_api, wifi scan skipped"); return; }
u64 net_api = *(u64 *)(kernel_api + 0x48);
if (!net_api) { logl("[FirstInit] no net_api, wifi scan skipped"); return; }
net_device_count_fn dcount = (net_device_count_fn)*(u64 *)(net_api + 8);
net_scan_start_fn sstart = (net_scan_start_fn)*(u64 *)(net_api + 40);
net_scan_count_fn scount = (net_scan_count_fn)*(u64 *)(net_api + 48);
net_scan_result_fn sresult = (net_scan_result_fn)*(u64 *)(net_api + 56);
net_is_wireless_fn iswl = (net_is_wireless_fn)*(u64 *)(net_api + 64);
if (!dcount || !iswl || !scount || !sresult) {
logl("[FirstInit] net scan api incomplete");
return;
}
u32 ndev = dcount();
/* 串口日志:设备数 */
{
char b[24]; int p=0;
const char *s="[FirstInit] net devices=";
while(s[p]) b[p]=s[p], p++;
b[p++]='0'+(ndev/10); b[p++]='0'+(ndev%10); b[p]=0;
logl(b);
}
/* 找第一个无线设备 */
int wifi_idx = -1;
for (u32 i = 0; i < ndev; i++) {
int rc = iswl(i);
if (rc == 1) { wifi_idx = (int)i; break; }
}
if (wifi_idx < 0) {
logl("[FirstInit] no wireless device found");
g_no_wireless_device = 1;
return;
}
/* ath9k 驱动在 driver_init 时已同步扫描,但保险起见若 count=0 再触发一次 */
int count = scount((u32)wifi_idx);
if (count <= 0 && sstart) {
logl("[FirstInit] triggering wifi scan...");
int rc = sstart((u32)wifi_idx);
{
char b[32]; int p=0;
const char *s="[FirstInit] scan_start rc=";
while(s[p]) b[p]=s[p], p++;
if (rc < 0) { b[p++]='-'; b[p++]='0'+(-rc); } else { b[p++]='0'+rc; }
b[p]=0; logl(b);
}
count = scount((u32)wifi_idx);
}
if (count <= 0) {
logl("[FirstInit] wifi scan: no results");
return;
}
if (count > WIFI_MAX_RESULTS) count = WIFI_MAX_RESULTS;
/* 读取每个扫描结果 */
for (int i = 0; i < count; i++) {
net_scan_result r;
for (u32 k = 0; k < sizeof(r); k++) ((u8 *)&r)[k] = 0;
int rc = sresult((u32)wifi_idx, (u32)i, &r);
if (rc != 0) continue;
/* 拷贝 SSID */
u32 j = 0;
while (r.ssid[j] && j + 1 < sizeof(g_wifi_ssids[i])) {
g_wifi_ssids[i][j] = r.ssid[j]; j++;
}
g_wifi_ssids[i][j] = 0;
/* 生成 meta 字符串 */
wifi_meta_str(g_wifi_meta[i], sizeof(g_wifi_meta[i]), r.security, r.rssi);
g_wifi_scan_count++;
}
{
char b[32]; int p=0;
const char *s="[FirstInit] wifi scan results=";
while(s[p]) b[p]=s[p], p++;
b[p++]='0'+(g_wifi_scan_count/10); b[p++]='0'+(g_wifi_scan_count%10); b[p]=0;
logl(b);
}
}
static void net_toggle(setup_net *n, int row) {
if (row == 0) n->mode = (n->mode + 1) % 3;
else if (row == 1) n->device = (n->device + 1) % 3;
else if (row == 2) n->ip ^= 1;
else if (row == 3) n->dns ^= 1;
static void net_copy(char *dst, u32 cap, const char *src) {
if (!cap) return;
u32 i = 0;
while (src[i] && i + 1 < cap) {
dst[i] = src[i];
i++;
}
dst[i] = 0;
}
static void draw_network_row(u32 *fb, i64 card_x, i64 card_y, setup_net *net, int row, int active, u32 fg) {
static void net_select(setup_net *net, int idx) {
if (idx < 0) idx = 0;
if (idx >= WIFI_SCAN_COUNT) idx = WIFI_SCAN_COUNT - 1;
if (net->selected != idx) {
net->password[0] = 0;
net->connected = 0;
}
net->selected = idx;
if (idx < g_wifi_scan_count) {
net_copy(net->ssid, sizeof(net->ssid), g_wifi_ssids[idx]);
} else {
net->ssid[0] = 0;
}
}
static void draw_wifi_row(u32 *fb, i64 card_x, i64 card_y, setup_net *net, int row, int active, u32 fg) {
u32 card = CARD_BG;
i64 ry = card_y + 150 + (i64)row * 88;
const u8 *label = g_txt_net_mode; i64 lw = g_txt_net_mode_w, lh = g_txt_net_mode_h;
if (row == 1) { label = g_txt_net_device; lw = g_txt_net_device_w; lh = g_txt_net_device_h; }
else if (row == 2) { label = g_txt_net_ip; lw = g_txt_net_ip_w; lh = g_txt_net_ip_h; }
else if (row == 3) { label = g_txt_net_dns; lw = g_txt_net_dns_w; lh = g_txt_net_dns_h; }
draw_option_row(fb, card_x+40, ry, 820, 42, label, lw, lh, net_value(row, net_get(net, row)), active==row, fg, card);
i64 x = card_x + 40;
i64 y = card_y + 132 + (i64)row * 64;
u32 fill = active == row ? 0xFFFFFFFF : (net->selected == row ? 0xFFDCECF8 : INPUT_BG);
fill_rounded_rect(fb, x, y, 390, 50, 9, fill);
stroke_rounded_rect(fb, x, y, 390, 50, 9, 1, active == row ? 0xFF7FA7C8 : card);
fb_text(fb, net->selected == row ? ">" : " ", x + 12, y + 16, fg, fill);
if (row < g_wifi_scan_count) {
fb_text(fb, g_wifi_ssids[row], x + 42, y + 8, fg, fill);
fb_text(fb, g_wifi_meta[row], x + 42, y + 28, 0xFF7F97AC, fill);
} else {
/* 无扫描结果时的占位行 */
const char *placeholder = (g_wifi_scan_tried && g_wifi_scan_count == 0)
? "No networks found" : "(empty)";
fb_text(fb, placeholder, x + 42, y + 16, 0xFF9AACC0, fill);
}
}
static void redraw_network_card(u32 *fb, i64 card_x, i64 card_y, setup_net *net, int active, i64 mx, i64 my, u32 bg, u32 fg) {
@@ -749,23 +828,42 @@ static void redraw_network_card(u32 *fb, i64 card_x, i64 card_y, setup_net *net,
fill_gradient_rect(fb, card_x - 24, card_y - 24, 948, 648);
draw_card(fb, card_x, card_y, 900, 600, card, bg);
fb_bitmap_alpha(fb, g_txt_network_title, g_txt_network_title_w, g_txt_network_title_h, card_x+40, card_y+40, fg, card, 255);
for (int r=0; r<4; r++) draw_network_row(fb, card_x, card_y, net, r, active, fg);
fb_bitmap_alpha(fb, g_txt_net_hint, g_txt_net_hint_w, g_txt_net_hint_h, card_x+40, card_y+555, 0xFF7F97AC, card, 255);
cursor_draw(fb, mx, my);
}
fb_text(fb, "Choose a network", card_x + 40, card_y + 88, 0xFF7F97AC, card);
for (int r=0; r<WIFI_SCAN_COUNT; r++) draw_wifi_row(fb, card_x, card_y, net, r, active, fg);
static void redraw_network_row(u32 *fb, i64 card_x, i64 card_y, setup_net *net, int row, int active, i64 mx, i64 my, u32 fg) {
u32 card = CARD_BG;
i64 ry = card_y + 150 + (i64)row * 88;
cursor_erase(fb);
fill_rect(fb, card_x + 36, ry - 8, 832, 58, card);
draw_network_row(fb, card_x, card_y, net, row, active, fg);
fill_rounded_rect(fb, card_x + 470, card_y + 120, 390, 260, 12, INPUT_BG);
stroke_rounded_rect(fb, card_x + 470, card_y + 120, 390, 260, 12, 1, 0xFFD2E3F0);
fb_text(fb, "Highlighted network", card_x + 494, card_y + 148, 0xFF7F97AC, INPUT_BG);
int preview = active < WIFI_SCAN_COUNT ? active : net->selected;
if (preview < g_wifi_scan_count) {
fb_text(fb, g_wifi_ssids[preview], card_x + 494, card_y + 182, fg, INPUT_BG);
fb_text(fb, g_wifi_meta[preview], card_x + 494, card_y + 210, 0xFF7F97AC, INPUT_BG);
} else {
fb_text(fb, g_wifi_scan_tried ? "No networks found" : "WiFi not initialized",
card_x + 494, card_y + 182, 0xFF9AACC0, INPUT_BG);
fb_text(fb, g_wifi_scan_tried ? "Check ath9k driver" : "Run ath9k driver first",
card_x + 494, card_y + 210, 0xFF9AACC0, INPUT_BG);
}
fb_text(fb, "Use Up/Down or click menu", card_x + 494, card_y + 260, 0xFF7F97AC, INPUT_BG);
fb_text(fb, "Enter selects highlighted item", card_x + 494, card_y + 288, 0xFF7F97AC, INPUT_BG);
fb_text(fb, "Password", card_x + 470, card_y + 400, fg, card);
draw_rounded_input(fb, card_x + 470, card_y + 430, 390, 44, net->password, 1, fg, card, active == WIFI_SCAN_COUNT);
u32 btn = active == WIFI_SCAN_COUNT + 1 ? 0xFFFFFFFF : 0xFFDCECF8;
fill_rounded_rect(fb, card_x + 620, card_y + 500, 240, 48, 10, btn);
stroke_rounded_rect(fb, card_x + 620, card_y + 500, 240, 48, 10, 1, active == WIFI_SCAN_COUNT + 1 ? 0xFFB6C9DD : card);
fb_text(fb, "Connect", card_x + 690, card_y + 516, fg, btn);
if (net->connected) fb_text(fb, "Connection profile saved", card_x + 40, card_y + 515, 0xFF4F8A5F, card);
else fb_text(fb, "Select SSID, enter password, then Connect", card_x + 40, card_y + 555, 0xFF7F97AC, card);
cursor_draw(fb, mx, my);
}
static void read_network_page(u32 *fb, i64 card_x, i64 card_y, setup_net *net, i64 *mx, i64 *my, u32 bg, u32 fg) {
int active = 0, mcnt = 0, e0 = 0;
int active = 0, mcnt = 0, e0 = 0, shift = 0;
u8 mpkt[3]; u8 prev_btns = 0;
int len = 0;
while (net->password[len]) len++;
net_select(net, net->selected);
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
for (;;) {
u8 st = inb(0x64);
@@ -787,28 +885,79 @@ static void read_network_page(u32 *fb, i64 card_x, i64 card_y, setup_net *net, i
cursor_draw(fb, *mx, *my);
}
if ((btns & 1) && !(prev_btns & 1)) {
for (int r=0; r<4; r++) {
i64 ry = card_y + 150 + (i64)r * 88;
if (*mx >= card_x + 260 && *mx < card_x + 860 && *my >= ry && *my < ry + 42) {
int old = active; active = r; net_toggle(net, active);
if (old != active) redraw_network_row(fb, card_x, card_y, net, old, active, *mx, *my, fg);
redraw_network_row(fb, card_x, card_y, net, active, active, *mx, *my, fg);
for (int r=0; r<WIFI_SCAN_COUNT; r++) {
i64 ry = card_y + 132 + (i64)r * 64;
if (*mx >= card_x + 40 && *mx < card_x + 430 && *my >= ry && *my < ry + 50) {
active = r;
net_select(net, r);
len = 0;
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
}
}
if (*mx >= card_x + 470 && *mx < card_x + 860 && *my >= card_y + 430 && *my < card_y + 474) {
active = WIFI_SCAN_COUNT;
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
}
if (*mx >= card_x + 620 && *mx < card_x + 860 && *my >= card_y + 500 && *my < card_y + 548) {
net->connected = 1;
logl("[FirstInit] wireless profile selected");
redraw_network_card(fb, card_x, card_y, net, WIFI_SCAN_COUNT + 1, *mx, *my, bg, fg);
for (int i=0;i<30;i++) delay_frame();
return;
}
}
prev_btns = btns;
continue;
}
u8 sc = data;
if (sc == 0xE0) { e0 = 1; continue; }
if (sc == 0x2A || sc == 0x36) { shift = 1; continue; }
if (sc == 0xAA || sc == 0xB6) { shift = 0; continue; }
if (sc & 0x80) { e0 = 0; continue; }
if (e0 && sc == 0x48) { if (active > 0) { int old=active; active--; redraw_network_row(fb, card_x, card_y, net, old, active, *mx, *my, fg); redraw_network_row(fb, card_x, card_y, net, active, active, *mx, *my, fg); } e0=0; continue; }
if (e0 && sc == 0x50) { if (active < 3) { int old=active; active++; redraw_network_row(fb, card_x, card_y, net, old, active, *mx, *my, fg); redraw_network_row(fb, card_x, card_y, net, active, active, *mx, *my, fg); } e0=0; continue; }
if (e0 && sc == 0x48) {
if (active > 0) active--;
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
e0=0; continue;
}
if (e0 && sc == 0x50) {
if (active < WIFI_SCAN_COUNT + 1) active++;
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
e0=0; continue;
}
e0 = 0;
if (sc == 0x39 || sc == 0x4D || sc == 0x4B) { net_toggle(net, active); redraw_network_row(fb, card_x, card_y, net, active, active, *mx, *my, fg); continue; }
if (sc == 0x1C) {
if (active < 3) { int old=active; active++; redraw_network_row(fb, card_x, card_y, net, old, active, *mx, *my, fg); redraw_network_row(fb, card_x, card_y, net, active, active, *mx, *my, fg); }
else return;
char c = scan_to_ascii(sc, shift);
if (!c) continue;
if (c == '\n') {
if (active < WIFI_SCAN_COUNT) {
net_select(net, active);
len = 0;
active = WIFI_SCAN_COUNT;
} else if (active == WIFI_SCAN_COUNT) {
active = WIFI_SCAN_COUNT + 1;
} else {
net->connected = 1;
logl("[FirstInit] wireless profile selected");
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
for (int i=0;i<30;i++) delay_frame();
return;
}
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
continue;
}
if (c == '\t') {
active = (active + 1) % (WIFI_SCAN_COUNT + 2);
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
continue;
}
if (active == WIFI_SCAN_COUNT) {
if (c == 8) {
if (len > 0) net->password[--len] = 0;
} else if (len < 63 && c >= 32 && c <= 126) {
net->password[len++] = c;
net->password[len] = 0;
}
net->connected = 0;
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
}
}
}
@@ -854,20 +1003,20 @@ static void build_user_conf(const char *pc, const char *user, const char *pass,
const char *th0="\ntheme="; for(int i=0;th0[i];i++) conf[p++]=th0[i];
const char *v4 = prefs->theme ? "dark" : "light"; for(int i=0;v4[i];i++) conf[p++]=v4[i];
const char *nm="\nnetwork.mode="; for(int i=0;nm[i];i++) conf[p++]=nm[i];
const char *nv0 = net->mode == 0 ? "disabled" : (net->mode == 1 ? "dhcp" : "manual"); for(int i=0;nv0[i];i++) conf[p++]=nv0[i];
const char *nd="\nnetwork.device="; for(int i=0;nd[i];i++) conf[p++]=nd[i];
const char *nv1 = net->device == 0 ? "auto" : (net->device == 1 ? "e1000" : "virtio-net"); for(int i=0;nv1[i];i++) conf[p++]=nv1[i];
const char *ni="\nnetwork.ip="; for(int i=0;ni[i];i++) conf[p++]=ni[i];
const char *nv2 = net->ip ? "manual" : "dhcp"; for(int i=0;nv2[i];i++) conf[p++]=nv2[i];
const char *dns="\nnetwork.dns="; for(int i=0;dns[i];i++) conf[p++]=dns[i];
const char *nv3 = net->dns ? "manual" : "auto"; for(int i=0;nv3[i];i++) conf[p++]=nv3[i];
const char *nv0 = net->connected ? "wifi" : "disabled"; for(int i=0;nv0[i];i++) conf[p++]=nv0[i];
const char *ns="\nnetwork.ssid="; for(int i=0;ns[i];i++) conf[p++]=ns[i];
for(int i=0;net->ssid[i]&&p<740;i++) conf[p++]=net->ssid[i];
const char *np="\nnetwork.password="; for(int i=0;np[i];i++) conf[p++]=np[i];
for(int i=0;net->password[i]&&p<740;i++) conf[p++]=net->password[i];
const char *ni="\nnetwork.ip=dhcp"; for(int i=0;ni[i];i++) conf[p++]=ni[i];
const char *dns="\nnetwork.dns=auto"; for(int i=0;dns[i];i++) conf[p++]=dns[i];
conf[p++]='\n';
/* XOR encrypt buffer with hash-derived stream; real disk write waits for FAT32 write support. */
for(int i=0;i<p;i++) conf[i]^=hash[i&31];
logl("[FirstInit] user.conf encrypted in memory (disk write pending)");
}
__attribute__((visibility("default"), noreturn))
__attribute__((visibility("default")))
void dsk_entry(const dsk_boot_context *ctx) {
__asm__ volatile("cli"); /* prevent IRQ1 (ps2kbd) from racing with our polling */
logl("[FirstInit] boot");
@@ -965,12 +1114,25 @@ void dsk_entry(const dsk_boot_context *ctx) {
prefs.keyboard = 0; /* US-QWERTY */
prefs.theme = 0; /* Light */
read_prefs_page(fb, card_x, card_y, &prefs, &mx, &my, bg, fg);
/* 查询真实 WiFi 扫描结果(来自 ath9k 驱动通过 kernel_api.net.scan_*) */
wifi_query_scan(ctx->dkm_kernel_api);
setup_net net;
net.mode = 0; /* Disabled */
net.device = 0; /* Auto */
net.ip = 0; /* Auto DHCP */
net.dns = 0; /* Auto DNS */
read_network_page(fb, card_x, card_y, &net, &mx, &my, bg, fg);
net.selected = 0;
net.connected = 0;
net.ssid[0] = 0;
net.password[0] = 0;
if (g_no_wireless_device) {
/* QEMU 或无无线网卡场景:跳过 WiFi 设置页面,network.mode=disabled */
logl("[FirstInit] no wireless device, skipping WiFi setup page");
net.connected = 0;
} else {
cursor_bg_valid = 0;
cursor_cur_x = -100;
cursor_cur_y = -100;
logl("[FirstInit] entering wireless setup page");
read_network_page(fb, card_x, card_y, &net, &mx, &my, bg, fg);
logl("[FirstInit] wireless setup page returned");
}
build_user_conf(pc, user, pass, &prefs, &net);
cursor_erase(fb);
@@ -978,5 +1140,6 @@ void dsk_entry(const dsk_boot_context *ctx) {
fb_bitmap_alpha(fb, g_txt_done, g_txt_done_w, g_txt_done_h, cx - g_txt_done_w/2, cy - 20, fg, bg_at_y(cy), 255);
logl("[FirstInit] user setup finished");
for(;;) __asm__("hlt");
/* 短暂停留后返回,由 DSK 接管加载 shell */
for (int i = 0; i < 60; i++) delay_frame();
}