github.com/google/trillian-examples@v0.0.0-20240520080811-0d40d35cef0e/binary_transparency/firmware/devices/dummy/rom/wasm_bootloader.go (about) 1 // Copyright 2020 Google LLC. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package rom 16 17 import ( 18 "fmt" 19 "time" 20 21 "github.com/perlin-network/life/exec" 22 wasm_validation "github.com/perlin-network/life/wasm-validation" 23 ) 24 25 // Most of the code below was copied from https://github.com/perlin-network/life/blob/master/main.go 26 27 // Resolver defines imports for WebAssembly modules ran in Life. 28 type Resolver struct{} 29 30 // ResolveFunc defines a set of import functions that may be called within a WebAssembly module. 31 func (r *Resolver) ResolveFunc(module, field string) exec.FunctionImport { 32 switch module { 33 case "env": 34 switch field { 35 case "__life_ping": 36 return func(vm *exec.VirtualMachine) int64 { 37 return vm.GetCurrentFrame().Locals[0] + 1 38 } 39 case "__life_log": 40 return func(vm *exec.VirtualMachine) int64 { 41 ptr := int(uint32(vm.GetCurrentFrame().Locals[0])) 42 msgLen := int(uint32(vm.GetCurrentFrame().Locals[1])) 43 msg := vm.Memory[ptr : ptr+msgLen] 44 fmt.Printf("[app] %s\n", string(msg)) 45 return 0 46 } 47 case "print_i64": 48 return func(vm *exec.VirtualMachine) int64 { 49 fmt.Printf("[app] print_i64: %d\n", vm.GetCurrentFrame().Locals[0]) 50 return 0 51 } 52 case "print": 53 return func(vm *exec.VirtualMachine) int64 { 54 ptr := int(uint32(vm.GetCurrentFrame().Locals[0])) 55 len := 0 56 for vm.Memory[ptr+len] != 0 { 57 len++ 58 } 59 msg := vm.Memory[ptr : ptr+len] 60 fmt.Printf("[app] print: %s\n", string(msg)) 61 return 0 62 } 63 64 default: 65 panic(fmt.Errorf("unknown field: %s", field)) 66 } 67 default: 68 panic(fmt.Errorf("unknown module: %s", module)) 69 } 70 } 71 72 // ResolveGlobal defines a set of global variables for use within a WebAssembly module. 73 func (r *Resolver) ResolveGlobal(module, field string) int64 { 74 switch module { 75 case "env": 76 switch field { 77 case "__life_magic": 78 return 424 79 default: 80 panic(fmt.Errorf("unknown field: %s", field)) 81 } 82 default: 83 panic(fmt.Errorf("unknown module: %s", module)) 84 } 85 } 86 87 // bootWasm prepares the VM with the provided wasm binary by calling the function 88 // named by entryPoint. 89 // 90 // Note that if the VM is unable to find the specified entrypoint (or none is 91 // specified), the the VM will fall back to attempting to execute the first 92 // function it finds in the input binary. 93 // 94 // Visit the [Life](https://github.com/perlin-network/life) repo for more info. 95 func bootWasm(entryPoint string, input []byte) error { 96 97 if err := wasm_validation.ValidateWasm(input); err != nil { 98 return err 99 } 100 101 // Instantiate a new WebAssembly VM with a few resolved imports. 102 vm, err := exec.NewVirtualMachine(input, exec.VMConfig{ 103 DefaultMemoryPages: 128, 104 DefaultTableSize: 65536, 105 DisableFloatingPoint: false, 106 }, new(Resolver), nil) 107 if err != nil { 108 return err 109 } 110 111 // Get the function ID of the entry point function to be executed. 112 entryID, ok := vm.GetFunctionExport(entryPoint) 113 if !ok { 114 fmt.Printf("Entry function %s not found; starting from 0.\n", entryPoint) 115 entryID = 0 116 } 117 118 start := time.Now() 119 120 // If any function prior to the entry function was declared to be 121 // called by the module, run it first. 122 if vm.Module.Base.Start != nil { 123 startID := int(vm.Module.Base.Start.Index) 124 _, err := vm.Run(startID) 125 if err != nil { 126 vm.PrintStackTrace() 127 return err 128 } 129 } 130 // Run the WebAssembly module's entry function. 131 ret, err := vm.Run(entryID) 132 if err != nil { 133 vm.PrintStackTrace() 134 return err 135 } 136 end := time.Now() 137 138 fmt.Printf("return value = %d, duration = %v\n", ret, end.Sub(start)) 139 return nil 140 }