Skip to content

Commit 21e05b7

Browse files
authored
feat: Support remoteproc-like path lookup (custom path, then /lib/firmware) (#3)
1 parent 408c74e commit 21e05b7

6 files changed

Lines changed: 127 additions & 64 deletions

File tree

README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ Control the simulated remote processor via sysfs:
2626

2727
```bash
2828
# Prepare firmware file
29-
touch /tmp/fake-root/lib/firmware/hello_world.elf
29+
touch /tmp/fake-root/lib/firmware/hello-world.elf
3030

3131
# Set firmware
32-
echo hello_world.elf > /tmp/fake-root/sys/class/remoteproc/remoteproc0/firmware
32+
echo hello-world.elf > /tmp/fake-root/sys/class/remoteproc/remoteproc0/firmware
3333

3434
# Start the remote processor
3535
echo start > /tmp/fake-root/sys/class/remoteproc/remoteproc0/state
@@ -47,6 +47,22 @@ Inspect remote processor name:
4747
cat /tmp/fake-root/sys/class/remoteproc/remoteproc0/name
4848
```
4949

50+
Specify custom firmware load path:
51+
52+
```bash
53+
# Set custom load path
54+
echo /tmp > /tmp/fake-root/sys/module/firmware_class/parameters/path
55+
56+
# Prepare firmware file in custom path
57+
touch /tmp/hi-universe.elf
58+
59+
# Set firmware
60+
echo hi-universe.elf > /tmp/fake-root/sys/class/remoteproc/remoteproc0/firmware
61+
62+
# Start the remote processor
63+
echo start > /tmp/fake-root/sys/class/remoteproc/remoteproc0/state
64+
```
65+
5066
## Installation from Releases
5167

5268
The release binaries are unsigned. On macOS, you'll need to remove the quarantine attribute before running:

cmd/remoteproc-simulator/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Example usage:
7676

7777
rootCmd.Flags().UintVar(&index, "index", 0, "is the N in /sys/class/remoteproc/remoteprocN/.../ (default 0)")
7878
rootCmd.Flags().StringVar(&name, "name", "dsp0", "remote processor name written to /sys/class/remoteproc/.../name")
79-
rootCmd.Flags().StringVar(&rootDir, "root-dir", "", "location where /sys will be created")
79+
rootCmd.Flags().StringVar(&rootDir, "root-dir", "", "location where /sys and /lib will be created")
8080
rootCmd.Flags().BoolVar(&showVersion, "version", false, "show version information")
8181

8282
if err := rootCmd.Execute(); err != nil {

e2e/boostrapping_test.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package e2e
22

33
import (
4-
"os"
54
"path/filepath"
6-
"strings"
75
"testing"
86

97
"github.com/stretchr/testify/assert"
@@ -47,13 +45,21 @@ func TestBootstrapping(t *testing.T) {
4745
assert.DirExists(t, instanceDir)
4846
})
4947

50-
t.Run("firmware directory is created", func(t *testing.T) {
48+
t.Run("default firmware directory is created", func(t *testing.T) {
5149
root := t.TempDir()
5250

5351
runSimulator(t, "--root-dir", root, "--index", "99")
5452

55-
firmwareDir, err := os.ReadFile(filepath.Join(root, "sys", "module", "firmware_class", "parameters", "path"))
56-
assert.NoError(t, err)
57-
assert.DirExists(t, strings.TrimSpace(string(firmwareDir)))
53+
pathFile := filepath.Join(root, "lib", "firmware")
54+
assert.DirExists(t, pathFile)
55+
})
56+
57+
t.Run("file used to customize firmware search path is created", func(t *testing.T) {
58+
root := t.TempDir()
59+
60+
runSimulator(t, "--root-dir", root, "--index", "99")
61+
62+
pathFile := filepath.Join(root, "sys", "module", "firmware_class", "parameters", "path")
63+
assert.FileExists(t, pathFile)
5864
})
5965
}

e2e/running_firmware_test.go

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package e2e
33
import (
44
"os"
55
"path/filepath"
6-
"strings"
76
"testing"
87

98
"github.com/stretchr/testify/require"
@@ -15,7 +14,7 @@ func TestRunningFirmware(t *testing.T) {
1514
runSimulator(t, "--root-dir", root, "--index", "3")
1615
instanceDir := filepath.Join(root, "sys", "class", "remoteproc", "remoteproc3")
1716

18-
createFirmwareFile(t, root, "some-firmware.elf")
17+
createFirmwareFile(t, filepath.Join(root, "lib", "firmware", "some-firmware.elf"))
1918
loadFirmware(t, instanceDir, "some-firmware.elf")
2019
setRemoteprocState(t, instanceDir, "start")
2120

@@ -26,6 +25,46 @@ func TestRunningFirmware(t *testing.T) {
2625
requireState(t, instanceDir, "offline")
2726
})
2827

28+
t.Run("firmware file must exist in order to start remoteproc successfully", func(t *testing.T) {
29+
t.Run("in default firmware directory - /lib/firmware", func(t *testing.T) {
30+
root := t.TempDir()
31+
runSimulator(t, "--root-dir", root, "--index", "0")
32+
instanceDir := filepath.Join(root, "sys", "class", "remoteproc", "remoteproc0")
33+
34+
createFirmwareFile(t, filepath.Join(root, "lib", "firmware", "some-firmware.elf"))
35+
loadFirmware(t, instanceDir, "some-firmware.elf")
36+
setRemoteprocState(t, instanceDir, "start")
37+
38+
requireState(t, instanceDir, "running")
39+
})
40+
41+
t.Run("in custom firmware directory, specified in /sys/module/firmware_class/parameters/path", func(t *testing.T) {
42+
root := t.TempDir()
43+
runSimulator(t, "--root-dir", root, "--index", "0")
44+
instanceDir := filepath.Join(root, "sys", "class", "remoteproc", "remoteproc0")
45+
customFirmwarePath := t.TempDir()
46+
firmwareSearchPathFile := filepath.Join(root, "sys", "module", "firmware_class", "parameters", "path")
47+
48+
require.NoError(t, writeFile(firmwareSearchPathFile, customFirmwarePath))
49+
createFirmwareFile(t, filepath.Join(customFirmwarePath, "some-firmware.elf"))
50+
loadFirmware(t, instanceDir, "some-firmware.elf")
51+
setRemoteprocState(t, instanceDir, "start")
52+
53+
requireState(t, instanceDir, "running")
54+
})
55+
56+
t.Run("when firmware file doesn't exist, remoteproc fails to start", func(t *testing.T) {
57+
root := t.TempDir()
58+
runSimulator(t, "--root-dir", root, "--index", "0")
59+
instanceDir := filepath.Join(root, "sys", "class", "remoteproc", "remoteproc0")
60+
61+
loadFirmware(t, instanceDir, "some-firmware.elf")
62+
setRemoteprocState(t, instanceDir, "start")
63+
64+
requireState(t, instanceDir, "offline")
65+
})
66+
})
67+
2968
t.Run("firmware file must exist in folder indicated inside <fake-root>/sys/module/firmware_class/parameters/path", func(t *testing.T) {
3069
root := t.TempDir()
3170
runSimulator(t, "--root-dir", root, "--index", "0")
@@ -38,13 +77,8 @@ func TestRunningFirmware(t *testing.T) {
3877
})
3978
}
4079

41-
func createFirmwareFile(t *testing.T, root, firmwareName string) {
42-
firmwareDirPath, err := os.ReadFile(filepath.Join(root, "sys", "module", "firmware_class", "parameters", "path"))
43-
require.NoError(t, err)
44-
firmwareDirPathStr := strings.TrimSpace(string(firmwareDirPath))
45-
err = os.MkdirAll(firmwareDirPathStr, 0755)
46-
require.NoError(t, err)
47-
firmwarePath := filepath.Join(firmwareDirPathStr, firmwareName)
80+
func createFirmwareFile(t *testing.T, pathToFirmwareFile string) {
81+
firmwarePath := filepath.Join(pathToFirmwareFile)
4882
require.NoError(t, writeFile(firmwarePath, ""))
4983
}
5084

pkg/simulator/filesystem.go

Lines changed: 51 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,23 @@ import (
44
"fmt"
55
"os"
66
"path/filepath"
7+
"strings"
78
)
89

910
type FileSystemManager struct {
10-
instanceDir string
11-
firmwareDirPathFile string
12-
firmwareDir string
13-
createdDirs []string
11+
instanceDir string
12+
customFirmwareLoadPathFile string
13+
defaultFirmwareDir string
14+
createdDirs []string
1415
}
1516

1617
func NewFileSystemManager(rootDir string, index uint) *FileSystemManager {
1718
instanceName := fmt.Sprintf("remoteproc%d", index)
1819
return &FileSystemManager{
19-
instanceDir: filepath.Join(rootDir, "sys", "class", "remoteproc", instanceName),
20-
firmwareDirPathFile: filepath.Join(rootDir, "sys", "module", "firmware_class", "parameters", "path"),
21-
firmwareDir: filepath.Join(rootDir, "firmware"),
22-
createdDirs: []string{},
20+
instanceDir: filepath.Join(rootDir, "sys", "class", "remoteproc", instanceName),
21+
customFirmwareLoadPathFile: filepath.Join(rootDir, "sys", "module", "firmware_class", "parameters", "path"),
22+
defaultFirmwareDir: filepath.Join(rootDir, "lib", "firmware"),
23+
createdDirs: []string{},
2324
}
2425
}
2526

@@ -32,27 +33,26 @@ func (fs *FileSystemManager) BootstrapDirectories() error {
3233
fs.createdDirs = append(fs.createdDirs, createdInstancePath)
3334
}
3435

35-
createdFirmwareDirSpecPath, err := mkfile(fs.firmwareDirPathFile, 0755)
36+
createdParametersDir, err := mkdirAll(filepath.Dir(fs.customFirmwareLoadPathFile), 0755)
3637
if err != nil {
3738
fs.Cleanup()
38-
return fmt.Errorf("failed to create firmware path directory: %w", err)
39+
return fmt.Errorf("failed to create parameters directory: %w", err)
3940
}
40-
if createdFirmwareDirSpecPath != "" {
41-
fs.createdDirs = append(fs.createdDirs, createdFirmwareDirSpecPath)
41+
if createdParametersDir != "" {
42+
fs.createdDirs = append(fs.createdDirs, createdParametersDir)
4243
}
43-
44-
if err := os.WriteFile(fs.firmwareDirPathFile, []byte(fs.firmwareDir), 0644); err != nil {
44+
if err := os.WriteFile(fs.customFirmwareLoadPathFile, []byte(""), 0644); err != nil {
4545
fs.Cleanup()
46-
return fmt.Errorf("failed to write firmware path file: %w", err)
46+
return fmt.Errorf("failed to create empty fimware search path file; %w", err)
4747
}
4848

49-
createdFirmwareDir, err := mkdirAll(fs.firmwareDir, 0755)
49+
createdDefaultFirmwareDir, err := mkdirAll(fs.defaultFirmwareDir, 0755)
5050
if err != nil {
5151
fs.Cleanup()
5252
return fmt.Errorf("failed to create firmware directory: %w", err)
5353
}
54-
if createdFirmwareDir != "" {
55-
fs.createdDirs = append(fs.createdDirs, createdFirmwareDir)
54+
if createdDefaultFirmwareDir != "" {
55+
fs.createdDirs = append(fs.createdDirs, createdDefaultFirmwareDir)
5656
}
5757

5858
return nil
@@ -67,18 +67,38 @@ func (fs *FileSystemManager) WriteInstanceFile(filename, content string) error {
6767
return nil
6868
}
6969

70-
func (fs *FileSystemManager) FirmwareExists(firmwareName string) bool {
71-
path := filepath.Join(fs.firmwareDir, firmwareName)
72-
_, err := os.Stat(path)
73-
return !os.IsNotExist(err)
70+
func (fs *FileSystemManager) CheckFirmwareExists(firmwareName string) error {
71+
lookupPaths := []string{}
72+
73+
customFirmwareDir := fs.customFirmwareDir()
74+
if customFirmwareDir != "" {
75+
firmwareExistsInCustomPath := fileExists(filepath.Join(customFirmwareDir, firmwareName))
76+
if firmwareExistsInCustomPath {
77+
return nil
78+
}
79+
lookupPaths = append(lookupPaths, customFirmwareDir)
80+
}
81+
82+
defaultFirmwareDir := fs.defaultFirmwareDir
83+
firmwareExistsInDefaultDir := fileExists(filepath.Join(defaultFirmwareDir, firmwareName))
84+
if firmwareExistsInDefaultDir {
85+
return nil
86+
}
87+
lookupPaths = append(lookupPaths, defaultFirmwareDir)
88+
89+
return fmt.Errorf("firmware file %s not found, checked in %s", firmwareName, strings.Join(lookupPaths, " and "))
7490
}
7591

76-
func (fs *FileSystemManager) InstanceDir() string {
77-
return fs.instanceDir
92+
func (fs *FileSystemManager) customFirmwareDir() string {
93+
customFirmwareLoadPath, err := os.ReadFile(fs.customFirmwareLoadPathFile)
94+
if err != nil {
95+
return ""
96+
}
97+
return strings.TrimSpace(string(customFirmwareLoadPath))
7898
}
7999

80-
func (fs *FileSystemManager) FirmwareDir() string {
81-
return fs.firmwareDir
100+
func (fs *FileSystemManager) InstanceDir() string {
101+
return fs.instanceDir
82102
}
83103

84104
func (fs *FileSystemManager) Cleanup() error {
@@ -91,24 +111,6 @@ func (fs *FileSystemManager) Cleanup() error {
91111
return nil
92112
}
93113

94-
func mkfile(path string, perm os.FileMode) (string, error) {
95-
dir, err := mkdirAll(filepath.Dir(path), perm)
96-
if err != nil {
97-
return "", err
98-
}
99-
file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, perm)
100-
if err != nil {
101-
return "", err
102-
}
103-
defer file.Close()
104-
if dir == "" {
105-
return path, nil
106-
} else {
107-
return dir, nil
108-
}
109-
110-
}
111-
112114
func mkdirAll(path string, perm os.FileMode) (string, error) {
113115
current := path
114116
var topmostMissing string
@@ -136,3 +138,8 @@ func mkdirAll(path string, perm os.FileMode) (string, error) {
136138

137139
return topmostMissing, nil
138140
}
141+
142+
func fileExists(path string) bool {
143+
_, err := os.Stat(path)
144+
return !os.IsNotExist(err)
145+
}

pkg/simulator/remoteproc.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ func (r *Remoteproc) handleStateChange(value string) {
163163
return
164164
}
165165

166-
if !r.fs.FirmwareExists(r.firmware) {
167-
log.Printf("Cannot start: firmware file not found in %s directory", r.fs.FirmwareDir())
166+
if err := r.fs.CheckFirmwareExists(r.firmware); err != nil {
167+
log.Printf("Cannot start: %s", err)
168168
r.setState(r.state)
169169
return
170170
}

0 commit comments

Comments
 (0)