| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <assert.h> |
| #include "os/mynewt.h" |
| #include "bootutil/bootutil.h" |
| #include "bootutil/image.h" |
| #include "config/config.h" |
| #include "split/split.h" |
| #include "split_priv.h" |
| |
| #define LOADER_IMAGE_SLOT 0 |
| #define SPLIT_IMAGE_SLOT 1 |
| #define SPLIT_TOTAL_IMAGES 2 |
| |
| static int8_t split_mode_cur; |
| static int8_t split_app_active; |
| |
| void |
| split_app_init(void) |
| { |
| int rc; |
| |
| /* Ensure this function only gets called by sysinit. */ |
| SYSINIT_ASSERT_ACTIVE(); |
| |
| rc = split_conf_init(); |
| assert(rc == 0); |
| } |
| |
| split_status_t |
| split_check_status(void) |
| { |
| void *entry; |
| int rc; |
| |
| rc = split_go(LOADER_IMAGE_SLOT, SPLIT_IMAGE_SLOT, &entry); |
| switch (rc) { |
| case SPLIT_GO_ERR: |
| return SPLIT_STATUS_INVALID; |
| |
| case SPLIT_GO_NON_MATCHING: |
| return SPLIT_STATUS_NOT_MATCHING; |
| |
| case SPLIT_GO_OK: |
| return SPLIT_STATUS_MATCHING; |
| |
| default: |
| assert(0); |
| return SPLIT_STATUS_INVALID; |
| } |
| } |
| |
| split_mode_t |
| split_mode_get(void) |
| { |
| return split_mode_cur; |
| } |
| |
| int |
| split_app_active_get(void) |
| { |
| return split_app_active; |
| } |
| |
| void |
| split_app_active_set(int active) |
| { |
| split_app_active = !!active; |
| } |
| |
| int |
| split_mode_set(split_mode_t split_mode) |
| { |
| /* XXX: For now, cast this as an integer. This value should either be |
| * treated as an enumeration generally (i.e. not read directly and assigned |
| * from values in flash), or switched to a native type of integer. However, |
| * this is not a high priority change, so just cast it for now. |
| */ |
| if ((int) split_mode < 0 || (int) split_mode >= SPLIT_MODE_CNT) { |
| return SYS_EINVAL; |
| } |
| |
| split_mode_cur = split_mode; |
| return 0; |
| } |
| |
| /** |
| * This validates and provides the loader image data |
| * |
| * @return 0 on success; nonzero on failure. |
| */ |
| int |
| split_app_go(void **entry, int toboot) |
| { |
| split_mode_t split_mode; |
| int run_app; |
| int rc; |
| |
| /* Make sure the configuration has been loaded. We need the persisted |
| * `split/status` value to proceed. |
| */ |
| conf_ensure_loaded(); |
| |
| if (toboot) { |
| split_mode = split_mode_get(); |
| |
| /* if we are told not to, then we don't boot an app */ |
| if (split_mode == SPLIT_MODE_LOADER) { |
| return -1; |
| } |
| |
| /* if this is a one-time test, reset the split mode */ |
| switch (split_mode) { |
| case SPLIT_MODE_LOADER: |
| run_app = 0; |
| break; |
| |
| case SPLIT_MODE_TEST_APP: |
| split_write_split(SPLIT_MODE_LOADER); |
| run_app = 1; |
| break; |
| |
| case SPLIT_MODE_TEST_LOADER: |
| split_write_split(SPLIT_MODE_APP); |
| run_app = 0; |
| break; |
| |
| case SPLIT_MODE_APP: |
| run_app = 1; |
| break; |
| |
| default: |
| run_app = 0; |
| break; |
| } |
| |
| if (!run_app) { |
| return -1; |
| } |
| } |
| |
| rc = split_go(LOADER_IMAGE_SLOT, SPLIT_IMAGE_SLOT, entry); |
| if (rc != 0) { |
| /* Images don't match; clear split status. */ |
| split_write_split(SPLIT_MODE_LOADER); |
| } |
| |
| return rc; |
| } |