1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <fcntl.h> 5 #include <unistd.h> 6 #include <sys/stat.h> 7 #include <sys/mman.h> 8 #include <errno.h> 9 10 #include <openbmc_intf.h> 11 #include <openbmc.h> 12 13 /* ------------------------------------------------------------------------- */ 14 static const gchar* dbus_object_path = "/org/openbmc/control"; 15 static const gchar* instance_name = "host0"; 16 static const gchar* dbus_name = "org.openbmc.control.Host"; 17 18 static GDBusObjectManagerServer *manager = NULL; 19 20 #define PPC_BIT32(bit) (0x80000000UL >> (bit)) 21 22 #define FSI_EXTERNAL_MODE_PATH "/sys/devices/platform/gpio-fsi/external_mode" 23 #define FSI_SCAN_PATH "/sys/class/fsi-master/fsi0/rescan" 24 25 /* TODO: Change this over to the cfam path once the cfam chardev patches have landed */ 26 #define FSI_RAW_PATH "/sys/class/fsi-master/fsi0/slave@00:00/raw" 27 28 #define FSI_SCAN_DELAY_US 10000 29 30 /* Attention registers */ 31 #define FSI_A_SI1S 0x081c 32 #define TRUE_MASK 0x100d 33 #define INTERRUPT_STATUS_REG 0x100b 34 35 /* SBE boot register and values */ 36 #define SBE_VITAL 0x281c 37 #define SBE_WARMSTART PPC_BIT32(0) 38 #define SBE_HW_TRIGGER PPC_BIT32(2) 39 #define SBE_UPDATE_1ST_NIBBLE PPC_BIT32(3) 40 #define SBE_IMAGE_SELECT PPC_BIT32(8) 41 #define SBE_UPDATE_3RD_NIBBLE PPC_BIT32(11) 42 43 /* Once the side is selected and attention bits are set, this starts the SBE */ 44 #define START_SBE (SBE_WARMSTART | SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE) 45 46 /* Primary is first side. Golden is second side */ 47 #define PRIMARY_SIDE (SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE) 48 #define GOLDEN_SIDE (SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE | \ 49 SBE_IMAGE_SELECT | SBE_UPDATE_3RD_NIBBLE) 50 51 static gboolean 52 on_init(Control *control, 53 GDBusMethodInvocation *invocation, 54 gpointer user_data) 55 { 56 (void) user_data; 57 control_complete_init(control,invocation); 58 return TRUE; 59 } 60 61 static gint 62 fsi_putcfam(int fd, uint64_t addr64, uint32_t val_host) 63 { 64 int rc; 65 uint32_t val = htobe32(val_host); 66 /* Map FSI to FSI_BYTE, as the 'raw' kernel interface expects this */ 67 uint32_t addr = (addr64 & 0x7ffc00) | ((addr64 & 0x3ff) << 2); 68 69 rc = lseek(fd, addr, SEEK_SET); 70 if (rc < 0) { 71 g_print("ERROR HostControl: cfam seek failed (0x%08x): %s\n", addr, 72 strerror(errno)); 73 return errno; 74 }; 75 76 rc = write(fd, &val, sizeof(val)); 77 if (rc < 0) { 78 g_print("ERROR HostControl: cfam write failed: %s\n", 79 strerror(errno)); 80 return errno; 81 } 82 83 return 0; 84 } 85 86 static int fsi_rescan(void) 87 { 88 char *one = "1"; 89 int fd, rc; 90 91 fd = open(FSI_SCAN_PATH, O_WRONLY); 92 if (fd < 0) { 93 g_print("ERROR HostControl: Failed to open path '%s': %s\n", 94 FSI_SCAN_PATH, strerror(errno)); 95 return errno; 96 } 97 rc = write(fd, one, sizeof(*one)); 98 close(fd); 99 if (rc < 0) { 100 g_print("ERROR HostControl: Failed to perform FSI scan: %s\n", 101 strerror(errno)); 102 return errno; 103 } 104 g_print("HostControl: Performing FSI scan (delay %d us)\n", 105 FSI_SCAN_DELAY_US); 106 usleep(FSI_SCAN_DELAY_US); 107 108 return 0; 109 } 110 111 static gboolean 112 on_boot(ControlHost *host, 113 GDBusMethodInvocation *invocation, 114 gpointer user_data) 115 { 116 (void) user_data; 117 int rc, cfam_fd; 118 119 if(control_host_get_debug_mode(host)==1) { 120 int fd; 121 char *one = "1"; 122 g_print("Enabling debug mode; not booting host\n"); 123 fd = open(FSI_EXTERNAL_MODE_PATH, O_RDWR); 124 if (fd < 0) { 125 g_print("ERROR HostControl: Failed to open path '%s'\n", 126 FSI_EXTERNAL_MODE_PATH); 127 return TRUE; 128 } 129 rc = write(fd, one, sizeof(*one)); 130 if (rc < 0) { 131 g_print("ERROR HostControl: Failed to enable debug mode '%s'\n", 132 FSI_EXTERNAL_MODE_PATH); 133 } 134 close(fd); 135 return TRUE; 136 } 137 g_print("Booting host\n"); 138 139 rc = fsi_rescan(); 140 if (rc < 0) 141 return FALSE; 142 143 cfam_fd = open(FSI_RAW_PATH, O_RDWR); 144 if (cfam_fd < 0) { 145 g_print("ERROR HostControl: Failed to open '%s'\n", FSI_RAW_PATH); 146 return FALSE; 147 } 148 149 control_host_complete_boot(host,invocation); 150 do { 151 rc = fsi_putcfam(cfam_fd, FSI_A_SI1S, 0x20000000); 152 rc |= fsi_putcfam(cfam_fd, TRUE_MASK, 0x40000000); 153 rc |= fsi_putcfam(cfam_fd, INTERRUPT_STATUS_REG, 0xFFFFFFFF); 154 if(rc) { break; } 155 156 const gchar* flash_side = control_host_get_flash_side(host); 157 g_print("Using %s side of the bios flash\n",flash_side); 158 if(strcmp(flash_side,"primary")==0) { 159 rc |= fsi_putcfam(cfam_fd, SBE_VITAL, PRIMARY_SIDE); 160 } else if(strcmp(flash_side,"golden") == 0) { 161 rc |= fsi_putcfam(cfam_fd, SBE_VITAL, GOLDEN_SIDE); 162 } else { 163 g_print("ERROR: Invalid flash side: %s\n",flash_side); 164 rc = 0xff; 165 166 } 167 if(rc) { break; } 168 169 rc = fsi_putcfam(cfam_fd, SBE_VITAL, START_SBE); 170 } while(0); 171 if(rc) 172 { 173 g_print("ERROR HostControl: SBE sequence failed (rc=%d)\n",rc); 174 } 175 /* Close file descriptor */ 176 close(cfam_fd); 177 178 control_host_emit_booted(host); 179 180 return TRUE; 181 } 182 183 static void 184 on_bus_acquired(GDBusConnection *connection, 185 const gchar *name, 186 gpointer user_data) 187 { 188 (void) name; 189 (void) user_data; 190 191 ObjectSkeleton *object; 192 //g_print ("Acquired a message bus connection: %s\n",name); 193 manager = g_dbus_object_manager_server_new(dbus_object_path); 194 195 gchar *s; 196 s = g_strdup_printf("%s/%s",dbus_object_path,instance_name); 197 object = object_skeleton_new(s); 198 g_free(s); 199 200 ControlHost* control_host = control_host_skeleton_new(); 201 object_skeleton_set_control_host(object, control_host); 202 g_object_unref(control_host); 203 204 Control* control = control_skeleton_new(); 205 object_skeleton_set_control(object, control); 206 g_object_unref(control); 207 208 //define method callbacks here 209 g_signal_connect(control_host, 210 "handle-boot", 211 G_CALLBACK(on_boot), 212 object); /* user_data */ 213 g_signal_connect(control, 214 "handle-init", 215 G_CALLBACK(on_init), 216 NULL); /* user_data */ 217 218 control_host_set_debug_mode(control_host,0); 219 control_host_set_flash_side(control_host,"primary"); 220 221 /* Export the object (@manager takes its own reference to @object) */ 222 g_dbus_object_manager_server_set_connection(manager, connection); 223 g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object)); 224 g_object_unref(object); 225 } 226 227 static void 228 on_name_acquired(GDBusConnection *connection, 229 const gchar *name, 230 gpointer user_data) 231 { 232 (void) connection; 233 (void) name; 234 (void) user_data; 235 // g_print ("Acquired the name %s\n", name); 236 } 237 238 static void 239 on_name_lost(GDBusConnection *connection, 240 const gchar *name, 241 gpointer user_data) 242 { 243 (void) connection; 244 (void) name; 245 (void) user_data; 246 // g_print ("Lost the name %s\n", name); 247 } 248 249 gint 250 main(gint argc, gchar *argv[]) 251 { 252 GMainLoop *loop; 253 cmdline cmd; 254 cmd.argc = argc; 255 cmd.argv = argv; 256 257 guint id; 258 loop = g_main_loop_new(NULL, FALSE); 259 260 id = g_bus_own_name(DBUS_TYPE, 261 dbus_name, 262 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | 263 G_BUS_NAME_OWNER_FLAGS_REPLACE, 264 on_bus_acquired, 265 on_name_acquired, 266 on_name_lost, 267 &cmd, 268 NULL); 269 270 g_main_loop_run(loop); 271 272 g_bus_unown_name(id); 273 g_main_loop_unref(loop); 274 return 0; 275 } 276