154 lines
4.5 KiB
Go
154 lines
4.5 KiB
Go
package utils
|
||
|
||
import (
|
||
"fmt"
|
||
"io"
|
||
"os"
|
||
"strconv"
|
||
"sync"
|
||
"syscall"
|
||
"up/utils/mtd"
|
||
)
|
||
|
||
// Глобальное состояние загрузки (используется для обновления прогресса)
|
||
var uploadState struct {
|
||
sync.RWMutex
|
||
Progress int
|
||
// другие поля могут быть здесь
|
||
}
|
||
|
||
// writeUbootToDevices записывает U-Boot в файл, SPI NOR и SD-карту.
|
||
// Принимает данные, их длину и путь для сохранения копии в файловой системе.
|
||
func WriteUbootToDevices(data []byte, filepath string) error {
|
||
UBOOT_MAX_SIZE, err := strconv.Atoi(os.Getenv("UBOOT_MAX_SIZE"))
|
||
if err != nil {
|
||
fmt.Println("error: ", err)
|
||
return err
|
||
}
|
||
MMC_BOOT_OFFSET, err := strconv.Atoi(os.Getenv("MMC_BOOT_OFFSET"))
|
||
if err != nil {
|
||
fmt.Println("error: ", err)
|
||
return err
|
||
}
|
||
const chunkSize = 4096
|
||
dataLen := int64(len(data))
|
||
|
||
fmt.Printf("Writing U-Boot to devices (%d bytes)...\n", dataLen)
|
||
|
||
// Проверка лимита размера
|
||
if dataLen > int64(UBOOT_MAX_SIZE*1024*1024) {
|
||
return fmt.Errorf("U-Boot image too large for SPI NOR (%d > %d bytes)", dataLen, UBOOT_MAX_SIZE)
|
||
}
|
||
|
||
// --- 1. Сохраняем в файл (копия) ---
|
||
f, err := os.Create(filepath)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to create file %s: %w", filepath, err)
|
||
}
|
||
|
||
var written int64
|
||
for written < dataLen {
|
||
toWrite := dataLen - written
|
||
if toWrite > chunkSize {
|
||
toWrite = chunkSize
|
||
}
|
||
n, err := f.Write(data[written : written+toWrite])
|
||
if err != nil {
|
||
f.Close()
|
||
return fmt.Errorf("failed to write to file: %w", err)
|
||
}
|
||
written += int64(n)
|
||
// Прогресс: 30% за запись в файл
|
||
uploadState.Lock()
|
||
uploadState.Progress = int(written * 30 / dataLen)
|
||
uploadState.Unlock()
|
||
}
|
||
f.Close()
|
||
syscall.Sync() // синхронизация после записи файла
|
||
|
||
// --- 2. Запись в SPI NOR (/dev/mtd0) ---
|
||
fmt.Println("Writing to /dev/mtd0 (SPI NOR)...")
|
||
mtdFd, err := os.OpenFile("/dev/mtd0", os.O_RDWR|os.O_SYNC, 0660)
|
||
if err == nil {
|
||
defer mtdFd.Close()
|
||
|
||
// Получаем размер MTD-устройства из sysfs
|
||
mtdSize, err := mtd.ReadMTDSize(0)
|
||
if err != nil {
|
||
fmt.Printf("Cannot get MTD size from sysfs, proceeding without erase: %v\n", err)
|
||
} else {
|
||
// Стираем весь чип
|
||
fmt.Printf("Erasing SPI NOR (size %d bytes)...\n", mtdSize)
|
||
if err := mtd.EraseMTD(mtdFd, 0, mtdSize); err != nil {
|
||
fmt.Printf("Warning: erase failed (continuing anyway): %v\n", err)
|
||
} else {
|
||
fmt.Println("SPI NOR erased successfully")
|
||
}
|
||
}
|
||
|
||
// Запись в MTD
|
||
written = 0
|
||
for written < dataLen {
|
||
toWrite := dataLen - written
|
||
if toWrite > chunkSize {
|
||
toWrite = chunkSize
|
||
}
|
||
n, err := mtdFd.Write(data[written : written+toWrite])
|
||
if err != nil {
|
||
fmt.Printf("Error writing to /dev/mtd0: %v\n", err)
|
||
break
|
||
}
|
||
written += int64(n)
|
||
// Прогресс: 30–65% за SPI NOR
|
||
uploadState.Lock()
|
||
uploadState.Progress = 30 + int(written*35/dataLen)
|
||
uploadState.Unlock()
|
||
}
|
||
fmt.Printf("Written %d bytes to /dev/mtd0\n", written)
|
||
} else {
|
||
fmt.Printf("/dev/mtd0 not available: %v (skipping SPI NOR)\n", err)
|
||
}
|
||
|
||
// --- 3. Запись в SD-карту (/dev/mmcblk1) со смещением 8 КБ ---
|
||
fmt.Printf("Writing to /dev/mmcblk1 at offset %d (SD card boot area)...\n", MMC_BOOT_OFFSET)
|
||
mmcFd, err := os.OpenFile("/dev/mmcblk1", os.O_RDWR|os.O_SYNC, 0660)
|
||
if err == nil {
|
||
defer mmcFd.Close()
|
||
|
||
// Устанавливаем смещение
|
||
if _, err := mmcFd.Seek(int64(MMC_BOOT_OFFSET), io.SeekStart); err != nil {
|
||
fmt.Printf("Failed to seek on /dev/mmcblk1: %v\n", err)
|
||
} else {
|
||
written = 0
|
||
for written < dataLen {
|
||
toWrite := dataLen - written
|
||
if toWrite > chunkSize {
|
||
toWrite = chunkSize
|
||
}
|
||
n, err := mmcFd.Write(data[written : written+toWrite])
|
||
if err != nil {
|
||
fmt.Printf("Error writing to /dev/mmcblk1: %v\n", err)
|
||
break
|
||
}
|
||
written += int64(n)
|
||
// Прогресс: 65–100% за MMC
|
||
uploadState.Lock()
|
||
uploadState.Progress = 65 + int(written*35/dataLen)
|
||
uploadState.Unlock()
|
||
}
|
||
fmt.Printf("Written %d bytes to /dev/mmcblk1 at offset %d\n", written, MMC_BOOT_OFFSET)
|
||
}
|
||
} else {
|
||
fmt.Printf("/dev/mmcblk1 not available: %v (skipping SD card)\n", err)
|
||
}
|
||
|
||
// Финальная синхронизация
|
||
syscall.Sync()
|
||
|
||
uploadState.Lock()
|
||
uploadState.Progress = 100
|
||
uploadState.Unlock()
|
||
|
||
return nil
|
||
}
|