added upload uboot

This commit is contained in:
wt
2026-03-14 06:38:19 +07:00
parent febecf4dd9
commit 844f839c51
5 changed files with 215 additions and 27 deletions
+6 -1
View File
@@ -8,10 +8,14 @@
- **Обновление ядра**: Загрузка `Image.gz` в boot раздел
- **Обновление Device-Tree**: Загрузка `sun50i-h618-orangepi-zero2w.dtb`
- **U-Boot Environment**: Загрузка `uboot.env`
- **U-Boot Binary**: Загрузка `u-boot-sunxi-with-spl.bin` с записью в:
- `/media/u-boot-sunxi-with-spl.bin` (файл)
- `/dev/mtd0` (SPI NOR flash)
- `/dev/mmcblk1` со смещением 8KB (SD карта, аналог `dd seek=8`)
- **Редактор extlinux.conf**: Просмотр и редактирование конфигурации загрузчика
- **Индикатор прогресса**: Отображение прогресса загрузки в реальном времени
- **Авто-монтирование**: Автоматически монтирует `/dev/mmcblk1p1` в `/media`
- **Поддержка больших файлов**: Загрузка файлов до 200 MB
- **Поддержка больших файлов**: Загрузка файлов до 200 MB (до 1 MB для U-Boot Binary)
- **Перезагрузка системы**: Кнопка безопасной перезагрузки с корректным отмонтированием
- **Мониторинг температуры**: Отображение температуры CPU с цветовой индикацией
@@ -103,6 +107,7 @@ sudo ./up
| Ядро | `/media/Image.gz` |
| Device-Tree | `/media/sun50i-h618-orangepi-zero2w.dtb` |
| U-Boot Env | `/media/uboot.env` |
| U-Boot Binary | `/media/u-boot-sunxi-with-spl.bin` + `/dev/mtd0` + `/dev/mmcblk1` (+8KB offset) |
| Extlinux | `/media/extlinux/extlinux.conf` |
## Конфигурация
+178 -26
View File
@@ -4,6 +4,8 @@
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
@@ -18,9 +20,11 @@
#define KERNEL_FILE "Image.gz"
#define DTB_FILE "sun50i-h618-orangepi-zero2w.dtb"
#define UBOOT_FILE "uboot.env"
#define UBOOT_BIN_FILE "u-boot-sunxi-with-spl.bin"
#define EXTLINUX_FILE "extlinux/extlinux.conf"
#define MAX_FILE_SIZE (200 * 1024 * 1024) // 200 MB
#define UBOOT_MAX_SIZE (1 * 1024 * 1024) // 1 MB for U-Boot
static const char *s_http_port = "http://0.0.0.0:43243";
static struct mg_mgr mgr;
@@ -100,9 +104,135 @@ static const char* get_target_filename(const char *type) {
if (strcmp(type, "kernel") == 0) return KERNEL_FILE;
if (strcmp(type, "dtb") == 0) return DTB_FILE;
if (strcmp(type, "uboot") == 0) return UBOOT_FILE;
if (strcmp(type, "uboot_bin") == 0) return UBOOT_BIN_FILE;
return NULL;
}
// Write U-Boot to SPI NOR (mtd0) and MMC (mmcblk1)
static int write_uboot_to_devices(const char *data, size_t len, const char *filepath) {
int success = 0;
size_t chunk_size = 4096;
// Allwinner H618 boot offset: 8KB (same as "bs=1024 seek=8" in dd)
#define MMC_BOOT_OFFSET 8192
printf("Writing U-Boot to devices (%zu bytes)...\n", len);
// Check size limit for SPI NOR (safe limit to avoid overwriting partitions)
if (len > UBOOT_MAX_SIZE) {
printf("U-Boot image too large for SPI NOR (%zu > %d bytes)\n", len, UBOOT_MAX_SIZE);
return -1;
}
// First, save to file in /media
FILE *f = fopen(filepath, "wb");
if (!f) {
perror("fopen uboot file");
return -1;
}
size_t written = 0;
while (written < len) {
size_t to_write = (len - written < chunk_size) ? (len - written) : chunk_size;
if (fwrite(data + written, 1, to_write, f) != to_write) {
fclose(f);
return -1;
}
written += to_write;
g_upload.progress = (int)(written * 30 / len); // First 30% for file write
}
fclose(f);
sync();
// Write to /dev/mtd0 (SPI NOR flash)
printf("Writing to /dev/mtd0 (SPI NOR)...\n");
int mtd_fd = open("/dev/mtd0", O_RDWR | O_SYNC);
if (mtd_fd >= 0) {
// Get erase block size for SPI NOR
struct mtd_info_user mtd_info;
memset(&mtd_info, 0, sizeof(mtd_info));
if (ioctl(mtd_fd, MEMGETINFO, &mtd_info) == 0) {
printf("SPI NOR info: type=%s, size=%u bytes, erasesize=%u bytes\n",
mtd_info.type == MTD_NORFLASH ? "NOR" : "UNKNOWN",
mtd_info.size, mtd_info.erasesize);
// Erase SPI NOR before writing
printf("Erasing SPI NOR...\n");
struct erase_info_user erase_info;
erase_info.start = 0;
erase_info.length = mtd_info.size; // Erase entire chip
if (ioctl(mtd_fd, MEMERASE, &erase_info) == 0) {
printf("SPI NOR erased successfully\n");
} else {
perror("MEMERASE failed");
printf("Continuing anyway (some systems auto-erase)...\n");
}
} else {
perror("MEMGETINFO failed");
printf("Could not get SPI NOR info, proceeding with write...\n");
}
// Write to SPI NOR
written = 0;
while (written < len) {
size_t to_write = (len - written < chunk_size) ? (len - written) : chunk_size;
ssize_t w = write(mtd_fd, data + written, to_write);
if (w < 0) {
perror("write mtd0 (SPI NOR)");
close(mtd_fd);
break;
}
written += w;
g_upload.progress = 30 + (int)(written * 35 / len); // 30-65% for SPI NOR
}
close(mtd_fd);
printf("Written %zu bytes to /dev/mtd0 (SPI NOR)\n", written);
success = 1;
} else {
perror("open /dev/mtd0");
printf("/dev/mtd0 (SPI NOR) not available, skipping...\n");
}
// Write to /dev/mmcblk1 at offset 8KB (Allwinner H618 boot location)
// This matches: dd if=u-boot.bin of=/dev/mmcblk1 bs=1024 seek=8
printf("Writing to /dev/mmcblk1 at offset %d (SD card boot area)...\n", MMC_BOOT_OFFSET);
int mmc_fd = open("/dev/mmcblk1", O_RDWR | O_SYNC);
if (mmc_fd >= 0) {
// Seek to 8KB offset (sector 16 for 512-byte sectors)
if (lseek(mmc_fd, MMC_BOOT_OFFSET, SEEK_SET) != MMC_BOOT_OFFSET) {
perror("lseek mmcblk1");
close(mmc_fd);
} else {
written = 0;
while (written < len) {
size_t to_write = (len - written < chunk_size) ? (len - written) : chunk_size;
ssize_t w = write(mmc_fd, data + written, to_write);
if (w < 0) {
perror("write mmcblk1");
close(mmc_fd);
break;
}
written += w;
g_upload.progress = 65 + (int)(written * 35 / len); // 65-100% for MMC
}
close(mmc_fd);
printf("Written %zu bytes to /dev/mmcblk1 at offset %d\n", written, MMC_BOOT_OFFSET);
success = 1;
}
} else {
perror("open /dev/mmcblk1");
printf("/dev/mmcblk1 not available, skipping...\n");
}
// Final sync to ensure all data is flushed
sync();
g_upload.progress = 100;
return success ? 0 : -1;
}
// Get MIME type based on file extension
static const char* get_mime_type(const char *path) {
const char *ext = strrchr(path, '.');
@@ -301,10 +431,10 @@ static void handle_temperature(struct mg_connection *c) {
char type[32] = {0};
if (fscanf(type_f, "%31s", type) == 1) {
// Prefer CPU or soc zones
int is_cpu = (strstr(type, "cpu") != NULL ||
int is_cpu = (strstr(type, "cpu") != NULL ||
strstr(type, "soc") != NULL ||
strstr(type, "CPU") != NULL);
int temp_raw;
if (fscanf(f, "%d", &temp_raw) == 1) {
temperature = temp_raw / 1000.0f;
@@ -337,11 +467,11 @@ static void handle_temperature(struct mg_connection *c) {
char name[32] = {0};
if (fscanf(name_f, "%31s", name) == 1) {
// Prefer CPU or sunxi sensors
int is_cpu = (strstr(name, "cpu") != NULL ||
int is_cpu = (strstr(name, "cpu") != NULL ||
strstr(name, "sunxi") != NULL ||
strstr(name, "CPU") != NULL ||
strstr(name, "acpitz") != NULL);
int temp_raw;
if (fscanf(f, "%d", &temp_raw) == 1) {
temperature = temp_raw / 1000.0f;
@@ -369,7 +499,7 @@ static void handle_temperature(struct mg_connection *c) {
"/sys/class/hwmon/hwmon3/temp1_input",
NULL
};
for (int i = 0; fallback_paths[i] != NULL && !success; i++) {
FILE *f = fopen(fallback_paths[i], "r");
if (f) {
@@ -456,8 +586,14 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) {
return;
}
if (file_data.len > MAX_FILE_SIZE) {
mg_http_reply(c, 400, "", "{\"error\":\"File too large (max 200MB)\"}\n");
// Check file size limits
size_t max_size = MAX_FILE_SIZE;
if (strcmp(type, "uboot_bin") == 0) {
max_size = UBOOT_MAX_SIZE; // 1MB limit for U-Boot (safe for boot area)
}
if (file_data.len > max_size) {
mg_http_reply(c, 400, "", "{\"error\":\"File too large\"}\n");
return;
}
@@ -477,32 +613,48 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) {
printf("Upload: %s (%zu bytes) -> %s\n", type, file_data.len, filepath);
// Write file in chunks
FILE *fp = fopen(filepath, "wb");
if (!fp) {
mg_http_reply(c, 500, "", "{\"error\":\"Failed to create file\"}\n");
return;
}
// Update upload state
memcpy(g_upload.type, type, strlen(type) + 1);
g_upload.received = 0;
g_upload.progress = 0;
snprintf(g_upload.status, sizeof(g_upload.status), "Uploading...");
size_t written = 0;
size_t chunk_size = 65536;
while (written < file_data.len) {
size_t to_write = (file_data.len - written < chunk_size) ?
(file_data.len - written) : chunk_size;
if (fwrite(file_data.buf + written, 1, to_write, fp) != to_write) {
fclose(fp);
mg_http_reply(c, 500, "", "{\"error\":\"Failed to write file\"}\n");
// Special handling for U-Boot binary
if (strcmp(type, "uboot_bin") == 0) {
if (write_uboot_to_devices(file_data.buf, file_data.len, filepath) < 0) {
snprintf(g_upload.status, sizeof(g_upload.status), "Failed");
mg_http_reply(c, 500, "", "{\"error\":\"Failed to write U-Boot\"}\n");
return;
}
} else {
// Write file in chunks for other types
FILE *fp = fopen(filepath, "wb");
if (!fp) {
mg_http_reply(c, 500, "", "{\"error\":\"Failed to create file\"}\n");
return;
}
written += to_write;
}
fclose(fp);
sync();
size_t written = 0;
size_t chunk_size = 65536;
while (written < file_data.len) {
size_t to_write = (file_data.len - written < chunk_size) ?
(file_data.len - written) : chunk_size;
if (fwrite(file_data.buf + written, 1, to_write, fp) != to_write) {
fclose(fp);
mg_http_reply(c, 500, "", "{\"error\":\"Failed to write file\"}\n");
return;
}
written += to_write;
g_upload.progress = (int)(written * 100 / file_data.len);
}
fclose(fp);
sync();
g_upload.progress = 100;
}
printf("Upload complete: %s\n", filepath);
memcpy(g_upload.type, type, strlen(type) + 1);
g_upload.received = file_data.len;
g_upload.progress = 100;
snprintf(g_upload.status, sizeof(g_upload.status), "Complete");
+8
View File
@@ -15,6 +15,7 @@ document.addEventListener("DOMContentLoaded", function () {
const mountStatus = document.getElementById("mount-status");
const extlinuxEditor = document.getElementById("extlinux-editor");
const editorStatus = document.getElementById("editor-status");
const uploadHint = document.getElementById("upload-hint");
// Tab buttons
const tabBtns = document.querySelectorAll(".tab-btn");
@@ -32,6 +33,13 @@ document.addEventListener("DOMContentLoaded", function () {
this.classList.add("active");
uploadType.value = this.dataset.type;
hideResult();
// Show/hide U-Boot warning
if (this.dataset.type === "uboot_bin") {
uploadHint.classList.add("visible");
} else {
uploadHint.classList.remove("visible");
}
});
});
+8
View File
@@ -56,6 +56,9 @@
<button class="tab-btn" data-type="uboot">
U-Boot Environment
</button>
<button class="tab-btn" data-type="uboot_bin">
U-Boot Binary (SPL)
</button>
</div>
<div class="upload-area">
@@ -81,6 +84,11 @@
<span class="file-name" id="file-name"></span>
</label>
</div>
<div class="upload-hint" id="upload-hint">
⚠️ U-Boot Binary will be written to SPI NOR
(/dev/mtd0) and SD card at 8KB offset (/dev/mmcblk1
+8KB)
</div>
<button type="submit" class="upload-btn">Upload</button>
</form>
+15
View File
@@ -146,6 +146,21 @@ h2 {
text-align: center;
}
.upload-hint {
margin: 15px 0;
padding: 12px;
background: rgba(255, 165, 0, 0.15);
border: 1px solid rgba(255, 165, 0, 0.5);
border-radius: 8px;
color: #ffa500;
font-size: 0.9rem;
display: none;
}
.upload-hint.visible {
display: block;
}
.file-input-wrapper {
margin-bottom: 20px;
}