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/devices/platform/gpio-fsi/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/devices/platform/gpio-fsi/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 control_complete_init(control,invocation); 57 return TRUE; 58 } 59 60 static gint 61 fsi_putcfam(int fd, uint64_t addr64, uint32_t val_host) 62 { 63 int rc; 64 uint32_t val = htobe32(val_host); 65 /* Map FSI to FSI_BYTE, as the 'raw' kernel interface expects this */ 66 uint32_t addr = (addr64 & 0x7ffc00) | ((addr64 & 0x3ff) << 2); 67 68 rc = lseek(fd, addr, SEEK_SET); 69 if (rc < 0) { 70 g_print("ERROR HostControl: cfam seek failed (0x%08x): %s\n", addr, 71 strerror(errno)); 72 return errno; 73 }; 74 75 rc = write(fd, &val, sizeof(val)); 76 if (rc < 0) { 77 g_print("ERROR HostControl: cfam write failed: %s\n", 78 strerror(errno)); 79 return errno; 80 } 81 82 return 0; 83 } 84 85 static int fsi_rescan(void) 86 { 87 char *one = "1"; 88 int fd, rc; 89 90 fd = open(FSI_SCAN_PATH, O_WRONLY); 91 if (fd < 0) { 92 g_print("ERROR HostControl: Failed to open path '%s': %s\n", 93 FSI_SCAN_PATH, strerror(errno)); 94 return errno; 95 } 96 rc = write(fd, one, sizeof(one)); 97 close(fd); 98 if (rc < 0) { 99 g_print("ERROR HostControl: Failed to perform FSI scan: %s\n", 100 strerror(errno)); 101 return errno; 102 } 103 g_print("HostControl: Performing FSI scan (delay %d us)\n", 104 FSI_SCAN_DELAY_US); 105 usleep(FSI_SCAN_DELAY_US); 106 107 return 0; 108 } 109 110 static gboolean 111 on_boot(ControlHost *host, 112 GDBusMethodInvocation *invocation, 113 gpointer user_data) 114 { 115 int rc, cfam_fd; 116 GDBusProxy *proxy; 117 GError *error = NULL; 118 GDBusConnection *connection = 119 g_dbus_object_manager_server_get_connection(manager); 120 121 if(control_host_get_debug_mode(host)==1) { 122 int fd; 123 char *one = "1"; 124 g_print("Enabling debug mode; not booting host\n"); 125 fd = open(FSI_EXTERNAL_MODE_PATH, O_RDWR); 126 if (fd < 0) { 127 g_print("ERROR HostControl: Failed to open path '%s'\n", 128 FSI_EXTERNAL_MODE_PATH); 129 return TRUE; 130 } 131 rc = write(fd, one, sizeof(one)); 132 if (rc < 0) { 133 g_print("ERROR HostControl: Failed to enable debug mode '%s'\n", 134 FSI_EXTERNAL_MODE_PATH); 135 } 136 close(fd); 137 return TRUE; 138 } 139 g_print("Booting host\n"); 140 141 rc = fsi_rescan(); 142 if (rc < 0) 143 return FALSE; 144 145 cfam_fd = open(FSI_RAW_PATH, O_RDWR); 146 if (cfam_fd < 0) { 147 g_print("ERROR HostControl: Failed to open '%s'\n", FSI_RAW_PATH); 148 return FALSE; 149 } 150 151 Control* control = object_get_control((Object*)user_data); 152 control_host_complete_boot(host,invocation); 153 do { 154 rc = fsi_putcfam(cfam_fd, FSI_A_SI1S, 0x20000000); 155 rc |= fsi_putcfam(cfam_fd, TRUE_MASK, 0x40000000); 156 rc |= fsi_putcfam(cfam_fd, INTERRUPT_STATUS_REG, 0xFFFFFFFF); 157 if(rc) { break; } 158 159 const gchar* flash_side = control_host_get_flash_side(host); 160 g_print("Using %s side of the bios flash\n",flash_side); 161 if(strcmp(flash_side,"primary")==0) { 162 rc |= fsi_putcfam(cfam_fd, SBE_VITAL, PRIMARY_SIDE); 163 } else if(strcmp(flash_side,"golden") == 0) { 164 rc |= fsi_putcfam(cfam_fd, SBE_VITAL, GOLDEN_SIDE); 165 } else { 166 g_print("ERROR: Invalid flash side: %s\n",flash_side); 167 rc = 0xff; 168 169 } 170 if(rc) { break; } 171 172 rc = fsi_putcfam(cfam_fd, SBE_VITAL, START_SBE); 173 } while(0); 174 if(rc) 175 { 176 g_print("ERROR HostControl: SBE sequence failed (rc=%d)\n",rc); 177 } 178 /* Close file descriptor */ 179 close(cfam_fd); 180 181 control_host_emit_booted(host); 182 183 return TRUE; 184 } 185 186 static void 187 on_bus_acquired(GDBusConnection *connection, 188 const gchar *name, 189 gpointer 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 // g_print ("Acquired the name %s\n", name); 233 } 234 235 static void 236 on_name_lost(GDBusConnection *connection, 237 const gchar *name, 238 gpointer user_data) 239 { 240 // g_print ("Lost the name %s\n", name); 241 } 242 243 gint 244 main(gint argc, gchar *argv[]) 245 { 246 GMainLoop *loop; 247 cmdline cmd; 248 cmd.argc = argc; 249 cmd.argv = argv; 250 251 guint id; 252 loop = g_main_loop_new(NULL, FALSE); 253 254 id = g_bus_own_name(DBUS_TYPE, 255 dbus_name, 256 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | 257 G_BUS_NAME_OWNER_FLAGS_REPLACE, 258 on_bus_acquired, 259 on_name_acquired, 260 on_name_lost, 261 &cmd, 262 NULL); 263 264 g_main_loop_run(loop); 265 266 g_bus_unown_name(id); 267 g_main_loop_unref(loop); 268 return 0; 269 } 270